From a3ef1ac2d0a7ee28404573a5fc256dda9f562f60 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 13:19:56 +0200 Subject: [PATCH 001/185] [build] - initial commit --- .editorconfig | 4 + .gitignore | 35 + .gitmodules | 12 + CHANGELOG.md | 1767 + DISTRIBUTE.md | 57 + LICENSE.md | 227 + MapboxGLAndroidSDK/.gitignore | 2 + MapboxGLAndroidSDK/build.gradle | 105 + MapboxGLAndroidSDK/lint.xml | 7 + MapboxGLAndroidSDK/proguard-rules.pro | 41 + .../src/main/AndroidManifest.xml | 15 + .../com/mapbox/mapboxsdk/AccountsManager.java | 170 + .../com/mapbox/mapboxsdk/LibraryLoader.java | 55 + .../mapboxsdk/LibraryLoaderProvider.java | 15 + .../com/mapbox/mapboxsdk/MapStrictMode.java | 46 + .../mapboxsdk/MapStrictModeException.java | 7 + .../java/com/mapbox/mapboxsdk/Mapbox.java | 225 + .../com/mapbox/mapboxsdk/ModuleProvider.java | 38 + .../mapbox/mapboxsdk/ModuleProviderImpl.java | 30 + .../mapboxsdk/annotations/Annotation.java | 153 + .../mapboxsdk/annotations/ArrowDirection.java | 31 + .../annotations/BaseMarkerOptions.java | 124 + .../annotations/BasePointCollection.java | 82 + .../mapbox/mapboxsdk/annotations/Bubble.java | 315 + .../mapboxsdk/annotations/BubbleLayout.java | 350 + .../annotations/BubblePopupHelper.java | 35 + .../mapbox/mapboxsdk/annotations/Icon.java | 124 + .../mapboxsdk/annotations/IconFactory.java | 188 + .../mapboxsdk/annotations/InfoWindow.java | 351 + .../mapbox/mapboxsdk/annotations/Marker.java | 278 + .../mapboxsdk/annotations/MarkerOptions.java | 195 + .../mapbox/mapboxsdk/annotations/Polygon.java | 109 + .../mapboxsdk/annotations/PolygonOptions.java | 308 + .../mapboxsdk/annotations/Polyline.java | 71 + .../annotations/PolylineOptions.java | 250 + .../mapboxsdk/annotations/package-info.java | 4 + .../mapboxsdk/attribution/Attribution.java | 70 + .../attribution/AttributionLayout.java | 68 + .../attribution/AttributionMeasure.java | 249 + .../attribution/AttributionParser.java | 314 + .../mapboxsdk/attribution/package-info.java | 4 + .../mapboxsdk/camera/CameraPosition.java | 397 + .../mapbox/mapboxsdk/camera/CameraUpdate.java | 23 + .../mapboxsdk/camera/CameraUpdateFactory.java | 637 + .../mapbox/mapboxsdk/camera/package-info.java | 4 + .../constants/GeometryConstants.java | 67 + .../mapboxsdk/constants/MapboxConstants.java | 232 + .../constants/TelemetryConstants.java | 14 + .../mapboxsdk/constants/package-info.java | 4 + .../CalledFromWorkerThreadException.java | 8 + .../exceptions/ConversionException.java | 11 + .../IconBitmapChangedException.java | 25 + .../InvalidLatLngBoundsException.java | 12 + .../InvalidMarkerPositionException.java | 16 + .../MapboxConfigurationException.java | 33 + .../exceptions/TooManyIconsException.java | 20 + .../mapboxsdk/exceptions/package-info.java | 4 + .../com/mapbox/mapboxsdk/geometry/LatLng.java | 334 + .../mapboxsdk/geometry/LatLngBounds.java | 608 + .../mapbox/mapboxsdk/geometry/LatLngQuad.java | 94 + .../mapbox/mapboxsdk/geometry/LatLngSpan.java | 139 + .../mapboxsdk/geometry/ProjectedMeters.java | 155 + .../mapboxsdk/geometry/VisibleRegion.java | 161 + .../mapboxsdk/geometry/package-info.java | 4 + .../mapbox/mapboxsdk/http/HttpIdentifier.java | 39 + .../com/mapbox/mapboxsdk/http/HttpLogger.java | 35 + .../mapbox/mapboxsdk/http/HttpRequest.java | 32 + .../mapbox/mapboxsdk/http/HttpRequestUrl.java | 53 + .../mapbox/mapboxsdk/http/HttpResponder.java | 32 + .../mapboxsdk/http/LocalRequestTask.java | 75 + .../mapboxsdk/http/NativeHttpRequest.java | 90 + .../mapbox/mapboxsdk/http/package-info.java | 4 + .../location/AnimatorListenerHolder.java | 45 + .../mapboxsdk/location/CompassEngine.java | 55 + .../mapboxsdk/location/CompassListener.java | 33 + .../mapboxsdk/location/LatLngEvaluator.java | 21 + .../location/LayerBitmapProvider.java | 32 + .../location/LayerFeatureProvider.java | 26 + .../location/LayerSourceProvider.java | 111 + .../location/LocationAnimatorCoordinator.java | 422 + .../location/LocationCameraController.java | 437 + .../mapboxsdk/location/LocationComponent.java | 1586 + .../LocationComponentActivationOptions.java | 244 + .../LocationComponentCompassEngine.java | 268 + .../location/LocationComponentConstants.java | 94 + ...ationComponentNotInitializedException.java | 8 + .../location/LocationComponentOptions.java | 1778 + .../LocationComponentPositionManager.java | 48 + .../location/LocationLayerController.java | 464 + .../mapboxsdk/location/MapboxAnimator.java | 95 + .../location/MapboxAnimatorProvider.java | 40 + .../location/MapboxAnimatorSetProvider.java | 32 + .../location/MapboxCameraAnimatorAdapter.java | 36 + .../location/MapboxFloatAnimator.java | 17 + .../location/MapboxLatLngAnimator.java | 20 + .../OnCameraMoveInvalidateListener.java | 7 + .../OnCameraTrackingChangedListener.java | 21 + .../OnLocationCameraTransitionListener.java | 24 + .../location/OnLocationClickListener.java | 14 + .../location/OnLocationLongClickListener.java | 14 + .../location/OnLocationStaleListener.java | 17 + .../location/OnRenderModeChangedListener.java | 16 + .../mapboxsdk/location/StaleStateManager.java | 99 + .../com/mapbox/mapboxsdk/location/Utils.java | 121 + .../mapboxsdk/location/modes/CameraMode.java | 66 + .../mapboxsdk/location/modes/RenderMode.java | 45 + .../location/modes/package-info.java | 4 + .../mapboxsdk/location/package-info.java | 4 + .../java/com/mapbox/mapboxsdk/log/Logger.java | 321 + .../mapboxsdk/log/LoggerDefinition.java | 102 + .../mapbox/mapboxsdk/log/package-info.java | 4 + .../mapboxsdk/maps/AnnotationContainer.java | 87 + .../mapboxsdk/maps/AnnotationManager.java | 519 + .../mapbox/mapboxsdk/maps/Annotations.java | 25 + .../maps/AttributionDialogManager.java | 208 + .../maps/CameraChangeDispatcher.java | 204 + .../maps/FocalPointChangeListener.java | 11 + .../mapbox/mapboxsdk/maps/IconManager.java | 155 + .../java/com/mapbox/mapboxsdk/maps/Image.java | 22 + .../mapboxsdk/maps/InfoWindowManager.java | 96 + .../mapboxsdk/maps/MapChangeReceiver.java | 395 + .../mapbox/mapboxsdk/maps/MapFragment.java | 241 + .../mapboxsdk/maps/MapGestureDetector.java | 1140 + .../mapbox/mapboxsdk/maps/MapKeyListener.java | 271 + .../com/mapbox/mapboxsdk/maps/MapView.java | 1350 + .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 2391 + .../mapboxsdk/maps/MapboxMapOptions.java | 1242 + .../mapboxsdk/maps/MarkerContainer.java | 146 + .../com/mapbox/mapboxsdk/maps/Markers.java | 27 + .../com/mapbox/mapboxsdk/maps/NativeMap.java | 268 + .../mapbox/mapboxsdk/maps/NativeMapView.java | 1489 + .../mapboxsdk/maps/OnMapReadyCallback.java | 22 + .../mapboxsdk/maps/PolygonContainer.java | 84 + .../com/mapbox/mapboxsdk/maps/Polygons.java | 22 + .../mapboxsdk/maps/PolylineContainer.java | 83 + .../com/mapbox/mapboxsdk/maps/Polylines.java | 22 + .../com/mapbox/mapboxsdk/maps/Projection.java | 283 + .../maps/ShapeAnnotationContainer.java | 41 + .../mapboxsdk/maps/ShapeAnnotations.java | 13 + .../java/com/mapbox/mapboxsdk/maps/Style.java | 1150 + .../mapboxsdk/maps/SupportMapFragment.java | 219 + .../mapboxsdk/maps/TelemetryDefinition.java | 66 + .../com/mapbox/mapboxsdk/maps/Transform.java | 341 + .../com/mapbox/mapboxsdk/maps/UiSettings.java | 1106 + .../mapbox/mapboxsdk/maps/package-info.java | 4 + .../mapboxsdk/maps/renderer/MapRenderer.java | 158 + .../maps/renderer/MapRendererRunnable.java | 32 + .../maps/renderer/MapRendererScheduler.java | 17 + .../maps/renderer/egl/EGLConfigChooser.java | 328 + .../maps/renderer/egl/EGLConfigException.java | 21 + .../maps/renderer/egl/package-info.java | 4 + .../GLSurfaceViewMapRenderer.java | 115 + .../glsurfaceview/MapboxGLSurfaceView.java | 54 + .../renderer/glsurfaceview/package-info.java | 4 + .../mapboxsdk/maps/renderer/package-info.java | 4 + .../textureview/TextureViewMapRenderer.java | 115 + .../textureview/TextureViewRenderThread.java | 470 + .../renderer/textureview/package-info.java | 4 + .../mapboxsdk/maps/widgets/CompassView.java | 178 + .../mapboxsdk/maps/widgets/package-info.java | 4 + .../module/http/HttpRequestImpl.java | 196 + .../module/http/HttpRequestUtil.java | 71 + .../mapboxsdk/module/http/package-info.java | 4 + .../loader/LibraryLoaderProviderImpl.java | 49 + .../mapboxsdk/module/loader/package-info.java | 4 + .../module/telemetry/MapBaseEvent.java | 39 + .../module/telemetry/MapEventFactory.java | 57 + .../module/telemetry/MapLoadEvent.java | 179 + .../telemetry/OfflineDownloadEndEvent.java | 140 + .../telemetry/OfflineDownloadStartEvent.java | 98 + .../module/telemetry/PerformanceEvent.java | 179 + .../module/telemetry/PhoneState.java | 171 + .../module/telemetry/TelemetryImpl.java | 136 + .../module/telemetry/package-info.java | 4 + .../mapboxsdk/net/ConnectivityListener.java | 10 + .../mapboxsdk/net/ConnectivityReceiver.java | 160 + .../net/NativeConnectivityListener.java | 44 + .../mapbox/mapboxsdk/net/package-info.java | 4 + .../OfflineGeometryRegionDefinition.java | 175 + .../mapboxsdk/offline/OfflineManager.java | 682 + .../mapboxsdk/offline/OfflineRegion.java | 532 + .../offline/OfflineRegionDefinition.java | 72 + .../mapboxsdk/offline/OfflineRegionError.java | 92 + .../offline/OfflineRegionStatus.java | 172 + .../OfflineTilePyramidRegionDefinition.java | 162 + .../mapboxsdk/offline/package-info.java | 4 + .../com/mapbox/mapboxsdk/package-info.java | 4 + .../mapboxsdk/snapshotter/MapSnaphotUtil.java | 29 + .../mapboxsdk/snapshotter/MapSnapshot.java | 81 + .../mapboxsdk/snapshotter/MapSnapshotter.java | 661 + .../mapboxsdk/snapshotter/package-info.java | 4 + .../mapbox/mapboxsdk/storage/FileSource.java | 413 + .../mapbox/mapboxsdk/storage/Resource.java | 60 + .../mapboxsdk/storage/package-info.java | 4 + .../style/expressions/Expression.java | 4891 + .../style/expressions/package-info.java | 4 + .../style/layers/BackgroundLayer.java | 216 + .../style/layers/CannotAddLayerException.java | 15 + .../mapboxsdk/style/layers/CircleLayer.java | 584 + .../mapboxsdk/style/layers/CustomLayer.java | 37 + .../style/layers/FillExtrusionLayer.java | 463 + .../mapboxsdk/style/layers/FillLayer.java | 436 + .../mapboxsdk/style/layers/HeatmapLayer.java | 331 + .../style/layers/HillshadeLayer.java | 360 + .../mapbox/mapboxsdk/style/layers/Layer.java | 168 + .../style/layers/LayoutPropertyValue.java | 11 + .../mapboxsdk/style/layers/LineLayer.java | 676 + .../style/layers/PaintPropertyValue.java | 11 + .../mapboxsdk/style/layers/Property.java | 696 + .../style/layers/PropertyFactory.java | 2558 + .../mapboxsdk/style/layers/PropertyValue.java | 127 + .../mapboxsdk/style/layers/RasterLayer.java | 397 + .../mapboxsdk/style/layers/SymbolLayer.java | 1436 + .../style/layers/TransitionOptions.java | 136 + .../mapboxsdk/style/layers/layer.java.ejs | 250 + .../mapboxsdk/style/layers/package-info.java | 4 + .../mapboxsdk/style/layers/property.java.ejs | 61 + .../style/layers/property_factory.java.ejs | 100 + .../mapbox/mapboxsdk/style/light/Light.java | 242 + .../mapboxsdk/style/light/Position.java | 90 + .../mapboxsdk/style/light/light.java.ejs | 154 + .../mapboxsdk/style/light/package-info.java | 4 + .../sources/CannotAddSourceException.java | 15 + .../style/sources/CustomGeometrySource.java | 379 + .../sources/CustomGeometrySourceOptions.java | 85 + .../style/sources/GeoJsonOptions.java | 139 + .../style/sources/GeoJsonSource.java | 518 + .../style/sources/GeometryTileProvider.java | 22 + .../mapboxsdk/style/sources/ImageSource.java | 271 + .../style/sources/RasterDemSource.java | 185 + .../mapboxsdk/style/sources/RasterSource.java | 182 + .../mapboxsdk/style/sources/Source.java | 91 + .../mapboxsdk/style/sources/TileSet.java | 341 + .../style/sources/UnknownSource.java | 27 + .../mapboxsdk/style/sources/VectorSource.java | 171 + .../mapboxsdk/style/sources/package-info.java | 4 + .../mapboxsdk/style/types/Formatted.java | 69 + .../style/types/FormattedSection.java | 240 + .../mapboxsdk/style/types/package-info.java | 4 + .../mapboxsdk/text/LocalGlyphRasterizer.java | 59 + .../mapbox/mapboxsdk/text/package-info.java | 4 + .../mapbox/mapboxsdk/utils/AnimatorUtils.java | 168 + .../mapbox/mapboxsdk/utils/BitmapUtils.java | 189 + .../mapbox/mapboxsdk/utils/ColorUtils.java | 204 + .../com/mapbox/mapboxsdk/utils/Compare.java | 27 + .../com/mapbox/mapboxsdk/utils/FileUtils.java | 147 + .../com/mapbox/mapboxsdk/utils/FontUtils.java | 81 + .../mapboxsdk/utils/MapFragmentUtils.java | 51 + .../com/mapbox/mapboxsdk/utils/MathUtils.java | 64 + .../mapbox/mapboxsdk/utils/StringUtils.java | 27 + .../mapbox/mapboxsdk/utils/ThreadUtils.java | 48 + .../mapbox/mapboxsdk/utils/package-info.java | 4 + .../src/main/java/overview.html | 19 + .../src/main/res-public/values/public.xml | 162 + .../res/drawable-hdpi/mapbox_compass_icon.png | Bin 0 -> 3787 bytes .../res/drawable-hdpi/mapbox_logo_helmet.png | Bin 0 -> 1650 bytes .../res/drawable-hdpi/mapbox_logo_icon.png | Bin 0 -> 4778 bytes .../mapbox_marker_icon_default.png | Bin 0 -> 1520 bytes .../mapbox_markerview_icon_default.png | Bin 0 -> 1669 bytes .../mapbox_mylocation_icon_bearing.png | Bin 0 -> 1046 bytes .../mapbox_mylocation_icon_default.png | Bin 0 -> 885 bytes .../res/drawable-mdpi/mapbox_compass_icon.png | Bin 0 -> 2488 bytes .../res/drawable-mdpi/mapbox_logo_helmet.png | Bin 0 -> 950 bytes .../res/drawable-mdpi/mapbox_logo_icon.png | Bin 0 -> 2622 bytes .../mapbox_marker_icon_default.png | Bin 0 -> 1010 bytes .../mapbox_markerview_icon_default.png | Bin 0 -> 1115 bytes .../mapbox_mylocation_icon_bearing.png | Bin 0 -> 649 bytes .../mapbox_mylocation_icon_default.png | Bin 0 -> 555 bytes .../drawable-xhdpi/mapbox_compass_icon.png | Bin 0 -> 4775 bytes .../res/drawable-xhdpi/mapbox_logo_helmet.png | Bin 0 -> 2184 bytes .../res/drawable-xhdpi/mapbox_logo_icon.png | Bin 0 -> 6579 bytes .../mapbox_marker_icon_default.png | Bin 0 -> 1995 bytes .../mapbox_markerview_icon_default.png | Bin 0 -> 2163 bytes .../mapbox_mylocation_icon_bearing.png | Bin 0 -> 1345 bytes .../mapbox_mylocation_icon_default.png | Bin 0 -> 1096 bytes .../drawable-xxhdpi/mapbox_compass_icon.png | Bin 0 -> 7527 bytes .../drawable-xxhdpi/mapbox_logo_helmet.png | Bin 0 -> 3389 bytes .../res/drawable-xxhdpi/mapbox_logo_icon.png | Bin 0 -> 10802 bytes .../mapbox_marker_icon_default.png | Bin 0 -> 2998 bytes .../mapbox_markerview_icon_default.png | Bin 0 -> 3163 bytes .../mapbox_mylocation_icon_bearing.png | Bin 0 -> 1902 bytes .../mapbox_mylocation_icon_default.png | Bin 0 -> 1586 bytes .../drawable-xxxhdpi/mapbox_compass_icon.png | Bin 0 -> 18537 bytes .../drawable-xxxhdpi/mapbox_logo_helmet.png | Bin 0 -> 4468 bytes .../res/drawable-xxxhdpi/mapbox_logo_icon.png | Bin 0 -> 14441 bytes .../mapbox_marker_icon_default.png | Bin 0 -> 4006 bytes .../mapbox_markerview_icon_default.png | Bin 0 -> 4071 bytes .../mapbox_mylocation_icon_bearing.png | Bin 0 -> 3022 bytes .../mapbox_mylocation_icon_default.png | Bin 0 -> 2456 bytes .../res/drawable/mapbox_info_bg_selector.xml | 5 + .../res/drawable/mapbox_info_icon_default.xml | 9 + .../drawable/mapbox_info_icon_selected.xml | 9 + .../drawable/mapbox_mylocation_bg_shape.xml | 10 + .../mapbox_popup_window_transparent.xml | 12 + .../res/drawable/mapbox_rounded_corner.xml | 10 + .../res/drawable/mapbox_user_bearing_icon.xml | 10 + .../main/res/drawable/mapbox_user_icon.xml | 10 + .../res/drawable/mapbox_user_icon_shadow.xml | 19 + .../res/drawable/mapbox_user_icon_stale.xml | 10 + .../res/drawable/mapbox_user_puck_icon.xml | 17 + .../res/drawable/mapbox_user_stroke_icon.xml | 10 + .../layout/mapbox_attribution_list_item.xml | 14 + .../res/layout/mapbox_infowindow_content.xml | 53 + .../res/layout/mapbox_mapview_internal.xml | 27 + .../res/layout/mapbox_view_image_marker.xml | 6 + .../src/main/res/values-bg/strings.xml | 15 + .../src/main/res/values-ca/strings.xml | 15 + .../src/main/res/values-cs/strings.xml | 17 + .../src/main/res/values-es/strings.xml | 17 + .../src/main/res/values-fr/strings.xml | 17 + .../src/main/res/values-gl/strings.xml | 17 + .../src/main/res/values-he/strings.xml | 16 + .../src/main/res/values-hu/strings.xml | 15 + .../src/main/res/values-iw/strings.xml | 16 + .../src/main/res/values-ko/strings.xml | 16 + .../src/main/res/values-lt/strings.xml | 15 + .../src/main/res/values-nl/strings.xml | 15 + .../src/main/res/values-pl/strings.xml | 17 + .../src/main/res/values-pt-rPT/strings.xml | 16 + .../src/main/res/values-ru/strings.xml | 16 + .../src/main/res/values-sv/strings.xml | 16 + .../src/main/res/values-uk/strings.xml | 16 + .../src/main/res/values-vi/strings.xml | 17 + .../src/main/res/values-zh-rCN/strings.xml | 17 + .../src/main/res/values-zh-rHK/strings.xml | 17 + .../src/main/res/values-zh-rTW/strings.xml | 17 + .../src/main/res/values/attrs.xml | 186 + .../src/main/res/values/colors.xml | 9 + .../src/main/res/values/dimens.xml | 29 + .../src/main/res/values/strings.xml | 30 + .../src/main/res/values/styles.xml | 37 + .../mapbox/mapboxsdk/AccountsManagerTest.java | 59 + .../com/mapbox/mapboxsdk/MapboxInjector.java | 48 + .../java/com/mapbox/mapboxsdk/MapboxTest.java | 109 + .../mapboxsdk/annotations/AnnotationTest.java | 93 + .../mapboxsdk/annotations/IconTest.java | 56 + .../mapboxsdk/annotations/InfoWindowTest.java | 86 + .../mapboxsdk/annotations/MarkerTest.java | 160 + .../mapboxsdk/annotations/PolygonTest.java | 75 + .../mapboxsdk/annotations/PolylineTest.java | 75 + .../attribution/AttributionParseTest.java | 322 + .../mapboxsdk/camera/CameraPositionTest.java | 120 + .../mapboxsdk/constants/AppConstant.java | 6 + .../mapboxsdk/geometry/LatLngBoundsTest.java | 813 + .../mapboxsdk/geometry/LatLngSpanTest.java | 65 + .../mapbox/mapboxsdk/geometry/LatLngTest.java | 286 + .../geometry/ProjectedMetersTest.java | 66 + .../mapboxsdk/geometry/VisibleRegionTest.java | 95 + .../mapboxsdk/location/CompassEngineTest.java | 89 + .../LocationAnimatorCoordinatorTest.kt | 532 + .../LocationCameraControllerTest.java | 1001 + ...ocationComponentActivationOptionsTest.java | 119 + .../LocationComponentOptionsTest.java | 81 + .../LocationComponentPositionManagerTest.kt | 130 + .../location/LocationComponentTest.kt | 453 + .../location/LocationLayerControllerTest.java | 718 + .../mapboxsdk/location/MapboxAnimatorTest.kt | 43 + .../mapbox/mapboxsdk/location/UtilsTest.java | 28 + .../com/mapbox/mapboxsdk/log/LoggerTest.kt | 93 + .../mapboxsdk/maps/AnnotationManagerTest.java | 86 + .../mapboxsdk/maps/MapChangeReceiverTest.java | 586 + .../mapboxsdk/maps/MapTouchListenersTest.java | 157 + .../maps/MapboxMapOptionsAttrsTest.kt | 101 + .../mapboxsdk/maps/MapboxMapOptionsTest.java | 186 + .../mapbox/mapboxsdk/maps/MapboxMapTest.kt | 202 + .../mapbox/mapboxsdk/maps/StyleBuilderTest.kt | 237 + .../com/mapbox/mapboxsdk/maps/StyleTest.kt | 408 + .../mapbox/mapboxsdk/maps/TransformTest.kt | 183 + .../mapbox/mapboxsdk/maps/UiSettingsTest.java | 415 + .../module/http/HttpRequestUrlTest.kt | 67 + .../module/http/HttpRequestUtilTest.kt | 35 + .../module/telemetry/MapEventFactoryTest.java | 149 + .../module/telemetry/SchemaTest.java | 270 + .../style/expressions/ExpressionTest.java | 1537 + .../telemetry/HttpTransportTest.java | 20 + .../mapbox/mapboxsdk/utils/ColorUtilsTest.kt | 22 + .../mapbox/mapboxsdk/utils/MockParcel.java | 267 + .../org.mockito.plugins.MockMaker | 1 + MapboxGLAndroidSDKLint/.gitignore | 1 + MapboxGLAndroidSDKLint/build.gradle | 37 + .../com/mapbox/mapboxsdk/lint/KeepDetector.kt | 75 + .../mapboxsdk/lint/MapboxIssueRegistry.kt | 13 + .../mapbox/mapboxsdk/lint/KeepDetectorTest.kt | 28 + MapboxGLAndroidSDKTestApp/.gitignore | 2 + MapboxGLAndroidSDKTestApp/README.md | 11 + MapboxGLAndroidSDKTestApp/build.gradle | 93 + .../lint-baseline-local.xml | 166 + .../lint/lint-baseline-ci.xml | 177 + MapboxGLAndroidSDKTestApp/proguard-rules.pro | 14 + .../src/androidTest/AndroidManifest.xml | 4 + .../src/androidTest/assets/streets.json | 5331 + .../java/com/mapbox/mapboxsdk/AppCenter.kt | 15 + .../mapboxsdk/InstrumentationApplication.kt | 10 + .../mapbox/mapboxsdk/InstrumentationRunner.kt | 11 + .../camera/CameraUpdateFactoryTest.kt | 186 + .../integration/BaseIntegrationTest.kt | 40 + .../integration/FragmentBackStackTest.kt | 45 + .../integration/GLSurfaceViewReopenTest.kt | 29 + .../integration/GLSurfaceViewReuseTest.kt | 29 + .../integration/OrientationChangeTest.kt | 32 + .../QueryRenderedFeaturesBoxCountTest.kt | 30 + .../integration/TextureViewReopenTest.kt | 29 + .../integration/TextureViewReuseTest.kt | 29 + .../integration/ViewPagerScrollTest.kt | 36 + .../location/LocationComponentTest.kt | 1603 + .../location/LocationLayerControllerTest.kt | 609 + .../location/utils/LocationComponentAction.kt | 38 + .../utils/MapboxLocationTestingUtils.kt | 79 + .../utils/StyleChangeIdlingResource.kt | 40 + .../mapbox/mapboxsdk/maps/BaseLayerTest.kt | 27 + .../mapboxsdk/maps/GesturesUiTestUtils.kt | 516 + .../mapboxsdk/maps/IconManagerResolver.java | 42 + .../mapboxsdk/maps/MapGestureDetectorTest.kt | 193 + .../mapbox/mapboxsdk/maps/MapboxMapTest.java | 477 + .../com/mapbox/mapboxsdk/maps/MapboxTest.java | 111 + .../mapboxsdk/maps/NativeMapViewTest.kt | 404 + .../mapbox/mapboxsdk/maps/TransformTest.kt | 33 + .../mapboxsdk/maps/VisibleRegionTest.kt | 400 + .../mapboxsdk/offline/OfflineDownloadTest.kt | 85 + .../snapshotter/MapSnapshotterTest.kt | 57 + .../testapp/action/MapboxMapAction.java | 50 + .../testapp/action/OrientationAction.java | 78 + .../mapboxsdk/testapp/action/WaitAction.java | 39 + .../mapboxsdk/testapp/activity/BaseTest.java | 103 + .../testapp/activity/EspressoTest.java | 28 + .../testapp/activity/activity.junit.ejs | 32 + .../testapp/annotations/IconTest.java | 138 + .../testapp/annotations/MarkerTest.java | 63 + .../testapp/annotations/PolygonTest.java | 46 + .../testapp/annotations/PolylineTest.java | 42 + .../testapp/camera/CameraAnimateTest.java | 11 + .../testapp/camera/CameraEaseTest.java | 12 + .../testapp/camera/CameraForTest.java | 260 + .../testapp/camera/CameraMoveTest.java | 12 + .../mapboxsdk/testapp/camera/CameraTest.java | 307 + .../testapp/fragment/MapDialogFragmentTest.kt | 35 + .../geometry/GeoJsonConversionTest.java | 148 + .../testapp/geometry/LatLngBoundsTest.java | 65 + .../testapp/maps/ImageMissingTest.kt | 155 + .../testapp/maps/RemoveUnusedImagesTest.kt | 163 + .../mapboxsdk/testapp/maps/StyleLoadTest.kt | 31 + .../testapp/maps/widgets/AttributionTest.java | 217 + .../testapp/maps/widgets/CompassViewTest.java | 67 + .../testapp/maps/widgets/LogoTest.java | 60 + .../mapboxsdk/testapp/offline/CacheTest.kt | 88 + .../testapp/offline/OfflineManagerTest.kt | 124 + .../testapp/offline/OfflineUtilsTest.java | 41 + .../mapboxsdk/testapp/render/RenderTest.java | 74 + .../testapp/storage/FileSourceMapTest.kt | 59 + .../storage/FileSourceStandaloneTest.kt | 116 + .../testapp/storage/FileSourceTestUtils.kt | 59 + .../testapp/string/UppperLowerCaseTest.java | 47 + .../testapp/style/BackgroundLayerTest.java | 141 + .../testapp/style/CircleLayerTest.java | 453 + .../testapp/style/CustomGeometrySourceTest.kt | 69 + .../testapp/style/ExpressionTest.java | 786 + .../testapp/style/FillExtrusionLayerTest.java | 340 + .../testapp/style/FillLayerTest.java | 326 + .../testapp/style/GeoJsonSourceTests.java | 189 + .../testapp/style/HeatmapLayerTest.java | 215 + .../testapp/style/HillshadeLayerTest.java | 223 + .../mapboxsdk/testapp/style/ImageTest.kt | 75 + .../mapboxsdk/testapp/style/LightTest.java | 172 + .../testapp/style/LineLayerTest.java | 493 + .../testapp/style/RasterLayerTest.java | 240 + .../testapp/style/RuntimeStyleTests.java | 370 + .../style/RuntimeStyleTimingTests.java | 27 + .../testapp/style/StyleLoaderTest.java | 59 + .../testapp/style/SymbolLayerTest.java | 1313 + .../mapboxsdk/testapp/style/layer.junit.ejs | 195 + .../mapboxsdk/testapp/style/light.junit.ejs | 132 + .../utils/SnapshotterIdlingResource.java | 38 + .../testapp/utils/TestConstants.java | 12 + .../testapp/utils/TestingAsyncUtils.kt | 18 + .../mapbox/mapboxsdk/utils/FontUtilsTest.java | 41 + .../src/main/AndroidManifest.xml | 1029 + .../src/main/assets/Roboto-Medium.ttf | Bin 0 -> 127488 bytes .../src/main/assets/Roboto-Regular.ttf | Bin 0 -> 126072 bytes .../src/main/assets/commercial-24.png | Bin 0 -> 308 bytes .../src/main/assets/dog-park-24.png | Bin 0 -> 831 bytes .../src/main/assets/earthquakes.geojson | 6113 + .../src/main/assets/fill_filter_style.json | 10976 ++ .../0-255.pbf | Bin 0 -> 75287 bytes .../0-255.pbf | Bin 0 -> 73518 bytes .../0-255.pbf | Bin 0 -> 72149 bytes .../0-255.pbf | Bin 0 -> 75290 bytes .../8192-8447.pbf | Bin 0 -> 30553 bytes .../src/main/assets/heavy_style.json | 81857 +++++++++ .../src/main/assets/line_filter_style.json | 8746 + .../src/main/assets/london-underground-24.png | Bin 0 -> 729 bytes .../src/main/assets/numeric_filter_style.json | 8734 + .../src/main/assets/offline_test.db | Bin 0 -> 73728 bytes .../src/main/assets/points-sf.geojson | 115 + .../src/main/assets/points.geojson | 136346 +++++++++++++++ .../src/main/assets/small_line.geojson | 1 + .../src/main/assets/small_poly.geojson | 1 + .../src/main/assets/streets.json | 10398 ++ .../src/main/assets/town-hall-24.png | Bin 0 -> 552 bytes .../mapboxsdk/testapp/MapboxApplication.java | 95 + .../activity/FeatureOverviewActivity.java | 168 + .../AnimatedSymbolLayerActivity.java | 443 + .../annotation/BulkMarkerActivity.java | 200 + .../DynamicMarkerChangeActivity.java | 120 + .../activity/annotation/PolygonActivity.java | 219 + .../activity/annotation/PolylineActivity.java | 224 + .../annotation/PressForMarkerActivity.java | 152 + .../camera/CameraAnimationTypeActivity.java | 173 + .../camera/CameraAnimatorActivity.java | 281 + .../camera/CameraPositionActivity.java | 279 + .../camera/GestureDetectorActivity.java | 456 + .../activity/camera/LatLngBoundsActivity.kt | 165 + .../activity/camera/ManualZoomActivity.java | 120 + .../activity/camera/MaxMinZoomActivity.java | 99 + .../activity/camera/ScrollByActivity.java | 158 + .../customlayer/CustomLayerActivity.java | 143 + .../DeviceIndependentTestActivity.java | 79 + .../espresso/EspressoTestActivity.java | 66 + .../activity/espresso/PixelTestActivity.kt | 66 + ...QueryRenderedFeaturesBoxCountActivity.java | 154 + ...yRenderedFeaturesBoxHighlightActivity.java | 130 + ...enderedFeaturesBoxSymbolCountActivity.java | 145 + ...eryRenderedFeaturesPropertiesActivity.java | 244 + .../feature/QuerySourceFeaturesActivity.java | 134 + .../fragment/FragmentBackStackActivity.kt | 67 + .../fragment/MapFragmentActivity.java | 95 + .../activity/fragment/MultiMapActivity.java | 31 + .../fragment/NestedViewPagerActivity.kt | 166 + .../fragment/SupportMapFragmentActivity.java | 96 + .../activity/fragment/ViewPagerActivity.kt | 102 + .../imagegenerator/PrintActivity.java | 93 + .../imagegenerator/SnapshotActivity.kt | 89 + .../DynamicInfoWindowAdapterActivity.java | 158 + .../infowindow/InfoWindowActivity.java | 199 + .../infowindow/InfoWindowAdapterActivity.java | 128 + .../LocationComponentActivationActivity.java | 140 + .../location/LocationFragmentActivity.kt | 176 + .../location/LocationMapChangeActivity.java | 142 + .../location/LocationModesActivity.java | 432 + .../ManualLocationUpdatesActivity.java | 170 + .../testapp/activity/location/Utils.java | 59 + .../maplayout/BottomSheetActivity.java | 282 + .../activity/maplayout/DebugModeActivity.java | 306 + .../activity/maplayout/DoubleMapActivity.java | 160 + .../GLSurfaceRecyclerViewActivity.kt | 154 + .../LatLngBoundsForCameraActivity.java | 154 + .../maplayout/LocalGlyphActivity.java | 80 + .../activity/maplayout/MapChangeActivity.java | 89 + .../maplayout/MapInDialogActivity.java | 110 + .../maplayout/MapPaddingActivity.java | 131 + .../activity/maplayout/OverlayMapActivity.kt | 86 + .../activity/maplayout/SimpleMapActivity.java | 89 + .../maplayout/TextureRecyclerViewActivity.kt | 15 + .../maplayout/VisibilityChangeActivity.java | 144 + .../ChangeResourcesCachePathActivity.kt | 180 + .../offline/DeleteRegionActivity.java | 175 + .../offline/DownloadRegionActivity.kt | 319 + .../offline/MergeOfflineRegionsActivity.kt | 147 + .../activity/offline/OfflineActivity.java | 320 + .../offline/UpdateMetadataActivity.java | 187 + .../activity/render/RenderTestActivity.java | 366 + .../activity/render/RenderTestDefinition.java | 91 + .../render/RenderTestSnapshotter.java | 18 + .../render/RenderTestStyleDefinition.java | 131 + .../snapshot/MapSnapshotterActivity.java | 127 + .../MapSnapshotterLocalStyleActivity.java | 71 + .../MapSnapshotterMarkerActivity.java | 105 + .../snapshot/MapSnapshotterReuseActivity.java | 103 + .../storage/CacheManagementActivity.kt | 77 + .../storage/UrlTransformActivity.java | 99 + .../style/AnimatedImageSourceActivity.java | 143 + .../style/BuildingFillExtrusionActivity.java | 151 + .../activity/style/CircleLayerActivity.java | 284 + .../activity/style/CustomSpriteActivity.java | 144 + .../style/DataDrivenStyleActivity.java | 472 + .../activity/style/DraggableMarkerActivity.kt | 331 + .../activity/style/FillExtrusionActivity.java | 122 + .../style/FillExtrusionStyleTestActivity.java | 78 + .../style/GeoJsonClusteringActivity.java | 281 + .../activity/style/GradientLineActivity.java | 117 + .../activity/style/GridSourceActivity.java | 154 + .../activity/style/HeatmapLayerActivity.java | 228 + .../style/HillshadeLayerActivity.java | 87 + .../testapp/activity/style/NoStyleActivity.kt | 84 + .../style/RealTimeGeoJsonActivity.java | 129 + .../activity/style/RuntimeStyleActivity.java | 607 + .../style/RuntimeStyleTimingTestActivity.java | 99 + .../activity/style/StyleFileActivity.java | 177 + .../style/SymbolGeneratorActivity.java | 368 + .../activity/style/SymbolLayerActivity.java | 375 + .../ZoomFunctionSymbolLayerActivity.java | 199 + .../PerformanceMeasurementActivity.java | 189 + .../TextureViewAnimationActivity.java | 148 + .../TextureViewDebugModeActivity.java | 26 + .../TextureViewResizeActivity.java | 103 + ...tureViewTransparentBackgroundActivity.java | 108 + .../turf/PhysicalUnitCircleActivity.kt | 125 + .../testapp/adapter/FeatureAdapter.java | 61 + .../adapter/FeatureSectionAdapter.java | 174 + .../testapp/model/activity/Feature.java | 69 + .../model/annotations/CityStateMarker.java | 18 + .../annotations/CityStateMarkerOptions.java | 68 + .../model/annotations/CountryMarker.java | 24 + .../annotations/CountryMarkerOptions.java | 75 + .../model/customlayer/ExampleCustomLayer.java | 19 + .../other/OfflineDownloadRegionDialog.java | 47 + .../model/other/OfflineListRegionsDialog.java | 36 + .../mapboxsdk/testapp/utils/FileUtils.kt | 64 + .../mapboxsdk/testapp/utils/FontCache.java | 26 + .../mapboxsdk/testapp/utils/GeoParseUtil.java | 51 + .../mapboxsdk/testapp/utils/IconUtils.java | 31 + .../testapp/utils/IdleZoomListener.java | 25 + .../testapp/utils/ItemClickSupport.java | 95 + .../mapboxsdk/testapp/utils/NavUtils.java | 14 + .../mapboxsdk/testapp/utils/OfflineUtils.java | 37 + .../testapp/utils/ResourceUtils.java | 39 + .../utils/TileLoadingMeasurementUtils.java | 217 + .../mapboxsdk/testapp/utils/TimberLogger.java | 57 + .../mapboxsdk/testapp/utils/TimingLogger.java | 160 + .../mapboxsdk/testapp/utils/TokenUtils.java | 37 + .../testapp/utils/ViewToBitmapUtil.java | 22 + .../view/LockableBottomSheetBehavior.java | 74 + .../mapboxsdk/testapp/view/MapViewPager.java | 20 + .../src/main/res/animator/scale_down.xml | 11 + .../src/main/res/animator/scale_up.xml | 11 + .../src/main/res/drawable-hdpi/ic_android.png | Bin 0 -> 1711 bytes .../main/res/drawable-hdpi/ic_android_2.png | Bin 0 -> 1562 bytes .../res/drawable-hdpi/ic_launcher_round.png | Bin 0 -> 24697 bytes .../src/main/res/drawable-hdpi/icon.png | Bin 0 -> 19772 bytes .../main/res/drawable-hdpi/icon_burned.png | Bin 0 -> 1587 bytes .../src/main/res/drawable-mdpi/ic_android.png | Bin 0 -> 1217 bytes .../main/res/drawable-mdpi/ic_android_2.png | Bin 0 -> 1117 bytes .../res/drawable-mdpi/ic_launcher_round.png | Bin 0 -> 14115 bytes .../src/main/res/drawable-mdpi/icon.png | Bin 0 -> 11003 bytes .../main/res/drawable-mdpi/icon_burned.png | Bin 0 -> 913 bytes .../res/drawable-mdpi/southeast_radar_0.png | Bin 0 -> 172489 bytes .../res/drawable-mdpi/southeast_radar_1.png | Bin 0 -> 177163 bytes .../res/drawable-mdpi/southeast_radar_2.png | Bin 0 -> 179236 bytes .../res/drawable-mdpi/southeast_radar_3.png | Bin 0 -> 177074 bytes .../main/res/drawable-xhdpi/ic_android.png | Bin 0 -> 2202 bytes .../main/res/drawable-xhdpi/ic_android_2.png | Bin 0 -> 2142 bytes .../res/drawable-xhdpi/ic_launcher_round.png | Bin 0 -> 37126 bytes .../src/main/res/drawable-xhdpi/icon.png | Bin 0 -> 30669 bytes .../main/res/drawable-xhdpi/icon_burned.png | Bin 0 -> 1587 bytes .../main/res/drawable-xxhdpi/ic_android.png | Bin 0 -> 3639 bytes .../main/res/drawable-xxhdpi/ic_android_2.png | Bin 0 -> 3495 bytes .../res/drawable-xxhdpi/ic_launcher_round.png | Bin 0 -> 66853 bytes .../src/main/res/drawable-xxhdpi/ic_us.png | Bin 0 -> 418 bytes .../src/main/res/drawable-xxhdpi/icon.png | Bin 0 -> 58564 bytes .../main/res/drawable-xxhdpi/icon_burned.png | Bin 0 -> 2382 bytes .../main/res/drawable-xxxhdpi/ic_android.png | Bin 0 -> 4936 bytes .../res/drawable-xxxhdpi/ic_android_2.png | Bin 0 -> 4883 bytes .../main/res/drawable-xxxhdpi/ic_car_top.png | Bin 0 -> 19879 bytes .../drawable-xxxhdpi/ic_launcher_round.png | Bin 0 -> 103015 bytes .../main/res/drawable-xxxhdpi/ic_taxi_top.png | Bin 0 -> 11275 bytes .../src/main/res/drawable-xxxhdpi/icon.png | Bin 0 -> 93272 bytes .../main/res/drawable-xxxhdpi/icon_burned.png | Bin 0 -> 3018 bytes .../src/main/res/drawable-xxxhdpi/water.jpg | Bin 0 -> 165806 bytes .../main/res/drawable/custom_user_arrow.xml | 11 + .../main/res/drawable/custom_user_icon.xml | 10 + .../res/drawable/custom_user_puck_icon.xml | 23 + .../src/main/res/drawable/ic_ab_back.xml | 12 + .../src/main/res/drawable/ic_add.xml | 9 + .../res/drawable/ic_add_a_photo_black.xml | 9 + .../src/main/res/drawable/ic_add_white.xml | 9 + .../drawable/ic_airplanemode_active_black.xml | 12 + .../res/drawable/ic_animate_coordinates.xml | 9 + .../main/res/drawable/ic_arrow_downward.xml | 9 + .../src/main/res/drawable/ic_arrow_upward.xml | 9 + .../src/main/res/drawable/ic_check_box.xml | 9 + .../src/main/res/drawable/ic_delete.xml | 9 + .../res/drawable/ic_directions_bus_black.xml | 9 + .../res/drawable/ic_directions_car_black.xml | 9 + .../res/drawable/ic_directions_run_black.xml | 9 + .../src/main/res/drawable/ic_droppin.xml | 4 + .../res/drawable/ic_hearing_black_24dp.xml | 9 + .../src/main/res/drawable/ic_input.xml | 9 + .../src/main/res/drawable/ic_layers.xml | 9 + .../src/main/res/drawable/ic_layers_clear.xml | 9 + .../main/res/drawable/ic_location_city.xml | 9 + .../res/drawable/ic_location_disabled.xml | 9 + .../src/main/res/drawable/ic_my_location.xml | 9 + .../src/main/res/drawable/ic_paint.xml | 9 + .../main/res/drawable/ic_pause_black_24dp.xml | 9 + .../res/drawable/ic_play_arrow_black_24dp.xml | 9 + .../src/main/res/drawable/ic_print.xml | 9 + .../src/main/res/drawable/ic_refresh.xml | 9 + .../src/main/res/drawable/ic_stars.xml | 9 + .../src/main/res/drawable/line_divider.xml | 12 + .../mapbox_user_icon_shadow_0px_test.xml | 19 + .../main/res/layout/activity_add_sprite.xml | 28 + .../layout/activity_animated_image_source.xml | 16 + .../res/layout/activity_animated_marker.xml | 17 + .../layout/activity_backstack_fragment.xml | 17 + .../main/res/layout/activity_bottom_sheet.xml | 76 + .../res/layout/activity_building_layer.xml | 35 + .../res/layout/activity_cache_management.xml | 32 + .../activity_camera_animation_types.xml | 51 + .../res/layout/activity_camera_animator.xml | 26 + .../res/layout/activity_camera_position.xml | 33 + .../main/res/layout/activity_camera_test.xml | 16 + .../activity_change_resources_cache_path.xml | 21 + .../main/res/layout/activity_circle_layer.xml | 42 + .../main/res/layout/activity_custom_layer.xml | 25 + .../res/layout/activity_data_driven_style.xml | 24 + .../main/res/layout/activity_debug_mode.xml | 90 + .../src/main/res/layout/activity_default.xml | 12 + .../res/layout/activity_draggable_marker.xml | 19 + .../res/layout/activity_dynamic_marker.xml | 29 + .../res/layout/activity_espresso_test.xml | 15 + .../res/layout/activity_extrusion_test.xml | 17 + .../res/layout/activity_feature_overview.xml | 14 + .../layout/activity_fill_extrusion_layer.xml | 18 + .../layout/activity_geojson_clustering.xml | 23 + .../res/layout/activity_gesture_detector.xml | 27 + .../res/layout/activity_gradient_line.xml | 10 + .../main/res/layout/activity_grid_source.xml | 16 + .../main/res/layout/activity_heatmaplayer.xml | 13 + .../res/layout/activity_hillshade_layer.xml | 16 + .../main/res/layout/activity_infowindow.xml | 17 + .../layout/activity_infowindow_adapter.xml | 17 + .../main/res/layout/activity_latlngbounds.xml | 47 + .../main/res/layout/activity_local_glyph.xml | 17 + ...vity_location_layer_activation_builder.xml | 17 + .../activity_location_layer_fragment.xml | 24 + .../activity_location_layer_map_change.xml | 30 + .../layout/activity_location_layer_mode.xml | 78 + .../activity_location_manual_update.xml | 43 + .../main/res/layout/activity_manual_zoom.xml | 18 + .../main/res/layout/activity_map_fragment.xml | 8 + .../res/layout/activity_map_in_dialog.xml | 11 + .../main/res/layout/activity_map_padding.xml | 33 + .../main/res/layout/activity_map_simple.xml | 14 + .../res/layout/activity_map_snapshotter.xml | 14 + .../activity_map_snapshotter_marker.xml | 14 + .../layout/activity_map_snapshotter_reuse.xml | 24 + .../res/layout/activity_map_visibility.xml | 17 + .../main/res/layout/activity_marker_bulk.xml | 17 + .../main/res/layout/activity_maxmin_zoom.xml | 16 + .../layout/activity_merge_offline_regions.xml | 20 + .../res/layout/activity_metadata_update.xml | 22 + .../main/res/layout/activity_multi_map.xml | 69 + .../src/main/res/layout/activity_offline.xml | 47 + .../layout/activity_offline_region_delete.xml | 21 + .../src/main/res/layout/activity_overlay.xml | 13 + .../res/layout/activity_physical_circle.xml | 32 + .../main/res/layout/activity_pixel_test.xml | 16 + .../src/main/res/layout/activity_polyline.xml | 29 + .../res/layout/activity_press_for_marker.xml | 20 + .../src/main/res/layout/activity_print.xml | 23 + .../layout/activity_query_features_box.xml | 25 + .../layout/activity_query_features_point.xml | 16 + .../layout/activity_query_source_features.xml | 26 + .../main/res/layout/activity_recyclerview.xml | 12 + .../res/layout/activity_region_download.xml | 216 + .../res/layout/activity_restricted_bounds.xml | 17 + .../res/layout/activity_runtime_style.xml | 12 + .../main/res/layout/activity_scroll_by.xml | 106 + .../src/main/res/layout/activity_snapshot.xml | 29 + .../main/res/layout/activity_style_file.xml | 38 + .../res/layout/activity_symbol_generator.xml | 13 + .../main/res/layout/activity_symbollayer.xml | 8 + .../layout/activity_textureview_animate.xml | 29 + .../activity_textureview_debug_mode.xml | 98 + .../layout/activity_textureview_resize.xml | 29 + .../activity_textureview_transparent.xml | 16 + .../main/res/layout/activity_viewpager.xml | 21 + .../res/layout/activity_zoom_symbol_layer.xml | 16 + .../res/layout/dialog_camera_position.xml | 212 + .../res/layout/drawer_navigation_drawer.xml | 7 + .../main/res/layout/fragment_dialog_map.xml | 16 + .../main/res/layout/fragment_double_map.xml | 22 + .../main/res/layout/item_gesture_alert.xml | 14 + .../src/main/res/layout/item_main_feature.xml | 38 + .../src/main/res/layout/item_map_gl.xml | 10 + .../src/main/res/layout/item_map_texture.xml | 11 + .../src/main/res/layout/item_viewpager.xml | 17 + .../main/res/layout/section_main_layout.xml | 29 + .../main/res/layout/view_custom_marker.xml | 22 + .../src/main/res/layout/view_text_marker.xml | 17 + .../src/main/res/menu/menu_animator.xml | 20 + .../src/main/res/menu/menu_bounds.xml | 16 + .../src/main/res/menu/menu_building.xml | 12 + .../src/main/res/menu/menu_bulk_marker.xml | 9 + .../src/main/res/menu/menu_custom_layer.xml | 15 + .../main/res/menu/menu_data_driven_style.xml | 50 + .../src/main/res/menu/menu_debug.xml | 17 + .../main/res/menu/menu_generator_symbol.xml | 12 + .../src/main/res/menu/menu_gestures.xml | 27 + .../src/main/res/menu/menu_infowindow.xml | 19 + .../src/main/res/menu/menu_location_mode.xml | 39 + .../src/main/res/menu/menu_padding.xml | 8 + .../src/main/res/menu/menu_polygon.xml | 24 + .../src/main/res/menu/menu_polyline.xml | 25 + .../main/res/menu/menu_press_for_marker.xml | 8 + .../src/main/res/menu/menu_runtime_style.xml | 73 + .../src/main/res/menu/menu_symbol_layer.xml | 16 + .../src/main/res/menu/menu_symbols.xml | 12 + .../src/main/res/menu/menu_zoom.xml | 25 + .../src/main/res/raw/amsterdam.geojson | 2283 + .../src/main/res/raw/local_style.json | 7660 + .../src/main/res/raw/no_bg_style.json | 43 + .../src/main/res/raw/sat_style.json | 38 + .../res/raw/test_feature_collection.geojson | 26 + .../res/raw/test_feature_properties.geojson | 21 + .../raw/test_line_gradient_feature.geojson | 38 + .../res/raw/test_line_string_feature.geojson | 17 + .../test_multi_line_string_feature.geojson | 29 + .../res/raw/test_multi_point_feature.geojson | 17 + .../raw/test_multi_polygon_feature.geojson | 49 + .../main/res/raw/test_point_feature.geojson | 11 + .../main/res/raw/test_points_utrecht.geojson | 49 + .../main/res/raw/test_polygon_feature.geojson | 27 + .../test_polygon_with_hole_feature.geojson | 45 + .../src/main/res/raw/tiny_countries.geojson | 2741 + .../src/main/res/values-v21/attrs.xml | 6 + .../src/main/res/values-v21/styles.xml | 19 + .../src/main/res/values/actions.xml | 94 + .../src/main/res/values/arrays.xml | 15 + .../src/main/res/values/categories.xml | 21 + .../src/main/res/values/colors.xml | 13 + .../src/main/res/values/descriptions.xml | 89 + .../src/main/res/values/dimens.xml | 10 + .../src/main/res/values/ids.xml | 11 + .../src/main/res/values/strings.xml | 6 + .../src/main/res/values/styles.xml | 57 + .../src/main/res/values/titles.xml | 89 + README.md | 118 + TESTS.md | 117 + build.gradle | 34 + checkstyle.xml | 226 + gradle/android-nitpick.gradle | 66 + gradle/artifact-settings.gradle | 21 + gradle/dependencies.gradle | 90 + gradle/gradle-bintray.gradle | 117 + gradle/gradle-checkstyle.gradle | 26 + gradle/gradle-config.gradle | 23 + gradle/gradle-dependencies-graph.gradle | 29 + gradle/gradle-javadoc.gradle | 18 + gradle/gradle-lint.gradle | 30 + gradle/gradle-make.gradle | 18 + gradle/gradle-update-vendor-modules.gradle | 8 + gradle/jacoco-report.gradle | 33 + gradle/ktlint.gradle | 27 + gradle/native-build.gradle | 63 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54227 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 + gradlew.bat | 84 + resources/compass.svg | 34 + resources/direction-dot.svg | 28 + resources/dot-arrow.svg | 11 + resources/location-dot.svg | 15 + resources/location-static-dot.svg | 15 + scripts/exclude-activity-gen.json | 56 + scripts/generate-license.py | 39 + scripts/generate-style-code.js | 394 + scripts/generate-test-code.js | 73 + scripts/metrics.sh | 19 + scripts/parse-jacoco-report.py | 31 + scripts/release.py | 236 + scripts/run-render-test.py | 43 + scripts/validate-license.py | 17 + settings.gradle | 1 + src/android_renderer_backend.cpp | 67 + src/android_renderer_backend.hpp | 43 + src/android_renderer_frontend.cpp | 143 + src/android_renderer_frontend.hpp | 68 + src/annotation/marker.cpp | 23 + src/annotation/marker.hpp | 28 + src/annotation/multi_point.hpp | 34 + src/annotation/polygon.cpp | 40 + src/annotation/polygon.hpp | 21 + src/annotation/polyline.cpp | 31 + src/annotation/polyline.hpp | 21 + src/asset_manager.hpp | 14 + src/asset_manager_file_source.cpp | 57 + src/asset_manager_file_source.hpp | 29 + src/async_task.cpp | 62 + src/attach_env.cpp | 22 + src/attach_env.hpp | 31 + src/bitmap.cpp | 124 + src/bitmap.hpp | 43 + src/bitmap_factory.cpp | 25 + src/bitmap_factory.hpp | 20 + src/connectivity_listener.cpp | 41 + src/connectivity_listener.hpp | 29 + src/conversion/collection.cpp | 32 + src/conversion/collection.hpp | 18 + src/conversion/color.cpp | 17 + src/conversion/color.hpp | 18 + src/conversion/constant.cpp | 57 + src/conversion/constant.hpp | 104 + src/conversion/conversion.hpp | 50 + src/example_custom_layer.cpp | 238 + src/file_source.cpp | 202 + src/file_source.hpp | 81 + src/geojson/feature.cpp | 79 + src/geojson/feature.hpp | 23 + src/geojson/feature_collection.cpp | 37 + src/geojson/feature_collection.hpp | 26 + src/geojson/geometry.cpp | 97 + src/geojson/geometry.hpp | 28 + src/geojson/geometry_collection.cpp | 47 + src/geojson/geometry_collection.hpp | 26 + src/geojson/line_string.cpp | 55 + src/geojson/line_string.hpp | 36 + src/geojson/multi_line_string.cpp | 56 + src/geojson/multi_line_string.hpp | 34 + src/geojson/multi_point.cpp | 41 + src/geojson/multi_point.hpp | 33 + src/geojson/multi_polygon.cpp | 53 + src/geojson/multi_polygon.hpp | 32 + src/geojson/point.cpp | 34 + src/geojson/point.hpp | 27 + src/geojson/polygon.cpp | 55 + src/geojson/polygon.hpp | 35 + src/geojson/util.hpp | 52 + src/geometry/lat_lng.cpp | 29 + src/geometry/lat_lng.hpp | 29 + src/geometry/lat_lng_bounds.cpp | 30 + src/geometry/lat_lng_bounds.hpp | 26 + src/geometry/lat_lng_quad.cpp | 37 + src/geometry/lat_lng_quad.hpp | 27 + src/geometry/projected_meters.cpp | 17 + src/geometry/projected_meters.hpp | 21 + src/gl_functions.cpp | 156 + src/graphics/pointf.cpp | 25 + src/graphics/pointf.hpp | 24 + src/graphics/rectf.cpp | 35 + src/graphics/rectf.hpp | 28 + src/gson/json_array.cpp | 50 + src/gson/json_array.hpp | 24 + src/gson/json_element.cpp | 88 + src/gson/json_element.hpp | 24 + src/gson/json_object.cpp | 65 + src/gson/json_object.hpp | 24 + src/gson/json_primitive.cpp | 13 + src/gson/json_primitive.hpp | 21 + src/http_file_source.cpp | 194 + src/image.cpp | 21 + src/java/util.cpp | 19 + src/java/util.hpp | 81 + src/java_types.cpp | 49 + src/java_types.hpp | 43 + src/jni.cpp | 54 + src/jni.hpp | 24 + src/jni_native.cpp | 164 + src/jni_native.hpp | 13 + src/logger.cpp | 34 + src/logger.hpp | 21 + src/logging_android.cpp | 13 + src/main.cpp | 9 + src/map/camera_position.cpp | 68 + src/map/camera_position.hpp | 23 + src/map/image.cpp | 41 + src/map/image.hpp | 21 + src/map_renderer.cpp | 236 + src/map_renderer.hpp | 128 + src/map_renderer_runnable.cpp | 50 + src/map_renderer_runnable.hpp | 47 + src/native_map_view.cpp | 1153 + src/native_map_view.hpp | 261 + src/offline/offline_manager.cpp | 330 + src/offline/offline_manager.hpp | 109 + src/offline/offline_region.cpp | 300 + src/offline/offline_region.hpp | 92 + src/offline/offline_region_definition.cpp | 107 + src/offline/offline_region_definition.hpp | 43 + src/offline/offline_region_error.cpp | 44 + src/offline/offline_region_error.hpp | 19 + src/offline/offline_region_status.cpp | 38 + src/offline/offline_region_status.hpp | 19 + src/run_loop.cpp | 256 + src/run_loop_impl.hpp | 58 + src/snapshotter/map_snapshot.cpp | 65 + src/snapshotter/map_snapshot.hpp | 48 + src/snapshotter/map_snapshotter.cpp | 176 + src/snapshotter/map_snapshotter.hpp | 74 + src/string_util.cpp | 25 + src/style/android_conversion.hpp | 128 + src/style/conversion/filter.cpp | 26 + src/style/conversion/filter.hpp | 16 + src/style/conversion/position.cpp | 24 + src/style/conversion/position.hpp | 25 + src/style/conversion/property_expression.hpp | 23 + src/style/conversion/property_value.hpp | 62 + src/style/conversion/transition_options.cpp | 17 + src/style/conversion/transition_options.hpp | 21 + src/style/conversion/url_or_tileset.cpp | 30 + src/style/conversion/url_or_tileset.hpp | 16 + src/style/formatted.cpp | 54 + src/style/formatted.hpp | 23 + src/style/formatted_section.cpp | 11 + src/style/formatted_section.hpp | 18 + src/style/layers/background_layer.cpp | 145 + src/style/layers/background_layer.hpp | 58 + src/style/layers/circle_layer.cpp | 268 + src/style/layers/circle_layer.hpp | 84 + src/style/layers/custom_layer.cpp | 70 + src/style/layers/custom_layer.hpp | 44 + src/style/layers/fill_extrusion_layer.cpp | 220 + src/style/layers/fill_extrusion_layer.hpp | 74 + src/style/layers/fill_layer.cpp | 199 + src/style/layers/fill_layer.hpp | 70 + src/style/layers/heatmap_layer.cpp | 161 + src/style/layers/heatmap_layer.hpp | 62 + src/style/layers/hillshade_layer.cpp | 178 + src/style/layers/hillshade_layer.hpp | 66 + src/style/layers/layer.cpp | 198 + src/style/layers/layer.cpp.ejs | 137 + src/style/layers/layer.hpp | 126 + src/style/layers/layer.hpp.ejs | 62 + src/style/layers/layer_manager.cpp | 172 + src/style/layers/layer_manager.hpp | 57 + src/style/layers/line_layer.cpp | 307 + src/style/layers/line_layer.hpp | 94 + src/style/layers/raster_layer.cpp | 220 + src/style/layers/raster_layer.hpp | 74 + src/style/layers/symbol_layer.cpp | 592 + src/style/layers/symbol_layer.hpp | 180 + src/style/light.cpp | 143 + src/style/light.hpp | 53 + src/style/position.cpp | 35 + src/style/position.hpp | 24 + src/style/sources/custom_geometry_source.cpp | 210 + src/style/sources/custom_geometry_source.hpp | 50 + src/style/sources/geojson_source.cpp | 265 + src/style/sources/geojson_source.hpp | 73 + src/style/sources/image_source.cpp | 79 + src/style/sources/image_source.hpp | 39 + src/style/sources/raster_dem_source.cpp | 62 + src/style/sources/raster_dem_source.hpp | 29 + src/style/sources/raster_source.cpp | 61 + src/style/sources/raster_source.hpp | 29 + src/style/sources/source.cpp | 168 + src/style/sources/source.hpp | 61 + src/style/sources/unknown_source.cpp | 43 + src/style/sources/unknown_source.hpp | 27 + src/style/sources/vector_source.cpp | 84 + src/style/sources/vector_source.hpp | 33 + src/style/transition_options.cpp | 35 + src/style/transition_options.hpp | 26 + src/style/value.cpp | 83 + src/style/value.hpp | 43 + src/test/benchmark_runner.cpp | 10 + src/test/runtime.cpp | 74 + src/test/runtime.hpp | 9 + src/test/test_runner.cpp | 10 + src/text/collator.cpp | 199 + src/text/collator_jni.hpp | 64 + src/text/format_number.cpp | 81 + src/text/format_number_jni.hpp | 29 + src/text/local_glyph_rasterizer.cpp | 130 + src/text/local_glyph_rasterizer_jni.hpp | 33 + src/thread.cpp | 56 + src/timer.cpp | 75 + src/unaccent.cpp | 18 + vendor/mapbox-events-android | 1 + vendor/mapbox-gestures-android | 1 + vendor/mapbox-gl-native | 1 + vendor/mapbox-java | 1 + 1061 files changed, 403354 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CHANGELOG.md create mode 100644 DISTRIBUTE.md create mode 100644 LICENSE.md create mode 100644 MapboxGLAndroidSDK/.gitignore create mode 100644 MapboxGLAndroidSDK/build.gradle create mode 100644 MapboxGLAndroidSDK/lint.xml create mode 100644 MapboxGLAndroidSDK/proguard-rules.pro create mode 100644 MapboxGLAndroidSDK/src/main/AndroidManifest.xml create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoaderProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictMode.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictModeException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/AnimatorListenerHolder.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentNotInitializedException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraMoveInvalidateListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraTrackingChangedListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationClickListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationLongClickListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationStaleListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnRenderModeChangedListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java create mode 100755 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TelemetryDefinition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/MapboxGLSurfaceView.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtil.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/LibraryLoaderProviderImpl.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapBaseEvent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactory.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapLoadEvent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadEndEvent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadStartEvent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PhoneState.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnaphotUtil.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CannotAddLayerException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CannotAddSourceException.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySourceOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/Compare.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FileUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/StringUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/package-info.java create mode 100644 MapboxGLAndroidSDK/src/main/java/overview.html create mode 100644 MapboxGLAndroidSDK/src/main/res-public/values/public.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_compass_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_helmet.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_marker_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_markerview_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_mylocation_icon_bearing.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_mylocation_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_compass_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_helmet.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_marker_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_markerview_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_mylocation_icon_bearing.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_mylocation_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_compass_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_helmet.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_marker_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_markerview_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_mylocation_icon_bearing.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_mylocation_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_compass_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_helmet.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_marker_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_markerview_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mylocation_icon_bearing.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mylocation_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_compass_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_helmet.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_marker_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_markerview_icon_default.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_mylocation_icon_bearing.png create mode 100755 MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_mylocation_icon_default.png create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_popup_window_transparent.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_rounded_corner.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_bearing_icon.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_icon.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_icon_shadow.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_icon_stale.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_puck_icon.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/drawable/mapbox_user_stroke_icon.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-bg/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-cs/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-es/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-fr/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-gl/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-he/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-hu/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-iw/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-ko/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-lt/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-pl/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-pt-rPT/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-sv/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-zh-rCN/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-zh-rHK/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values-zh-rTW/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values/attrs.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values/colors.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values/dimens.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values/strings.xml create mode 100644 MapboxGLAndroidSDK/src/main/res/values/styles.xml create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/UtilsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/log/LoggerTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleBuilderTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtilTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactoryTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/telemetry/SchemaTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/ColorUtilsTest.kt create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java create mode 100644 MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker create mode 100644 MapboxGLAndroidSDKLint/.gitignore create mode 100644 MapboxGLAndroidSDKLint/build.gradle create mode 100644 MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/KeepDetector.kt create mode 100644 MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/MapboxIssueRegistry.kt create mode 100644 MapboxGLAndroidSDKLint/src/test/java/com/mapbox/mapboxsdk/lint/KeepDetectorTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/.gitignore create mode 100644 MapboxGLAndroidSDKTestApp/README.md create mode 100644 MapboxGLAndroidSDKTestApp/build.gradle create mode 100644 MapboxGLAndroidSDKTestApp/lint-baseline-local.xml create mode 100644 MapboxGLAndroidSDKTestApp/lint/lint-baseline-ci.xml create mode 100644 MapboxGLAndroidSDKTestApp/proguard-rules.pro create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/AndroidManifest.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/AppCenter.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/QueryRenderedFeaturesBoxCountTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxLocationTestingUtils.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/BaseLayerTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GesturesUiTestUtils.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/IconManagerResolver.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TransformTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/LatLngBoundsTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ImageMissingTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RemoveUnusedImagesTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineUtilsTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/render/RenderTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceMapTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceStandaloneTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTestUtils.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/StyleLoaderTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/SnapshotterIdlingResource.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestingAsyncUtils.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/Roboto-Medium.ttf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/Roboto-Regular.ttf create mode 100755 MapboxGLAndroidSDKTestApp/src/main/assets/commercial-24.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/dog-park-24.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/earthquakes.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fill_filter_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Bold,Arial Unicode MS Bold/0-255.pbf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Italic,Arial Unicode MS Regular/0-255.pbf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Medium,Arial Unicode MS Regular/0-255.pbf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/0-255.pbf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/8192-8447.pbf create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/heavy_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/line_filter_style.json create mode 100755 MapboxGLAndroidSDKTestApp/src/main/assets/london-underground-24.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/numeric_filter_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/offline_test.db create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/points-sf.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/points.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/small_line.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/small_poly.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/streets.json create mode 100755 MapboxGLAndroidSDKTestApp/src/main/assets/town-hall-24.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/DeviceIndependentTestActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QuerySourceFeaturesActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/FragmentBackStackActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/NestedViewPagerActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationComponentActivationActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/Utils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/OverlayMapActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/VisibilityChangeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DownloadRegionActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MergeOfflineRegionsActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestDefinition.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestSnapshotter.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestStyleDefinition.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/CacheManagementActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GradientLineActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HillshadeLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/NoStyleActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewAnimationActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewDebugModeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewResizeActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/PhysicalUnitCircleActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/activity/Feature.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarkerOptions.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerOptions.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FileUtils.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/NavUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ResourceUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimberLogger.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ViewToBitmapUtil.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/LockableBottomSheetBehavior.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/MapViewPager.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_launcher_round.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon_burned.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_launcher_round.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon_burned.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_0.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_1.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_3.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_launcher_round.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon_burned.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_launcher_round.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_us.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon_burned.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android_2.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_launcher_round.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon_burned.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/water.jpg create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/custom_user_arrow.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/custom_user_icon.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/custom_user_puck_icon.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_ab_back.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_white.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_animate_coordinates.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_arrow_downward.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_arrow_upward.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_check_box.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_hearing_black_24dp.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_pause_black_24dp.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_play_arrow_black_24dp.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_stars.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable/mapbox_user_icon_shadow_0px_test.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_image_source.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_bottom_sheet.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_cache_management.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_change_resources_cache_path.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_data_driven_style.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_draggable_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_espresso_test.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_fill_extrusion_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gradient_line.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_grid_source.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_heatmaplayer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_hillshade_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_latlngbounds.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_local_glyph.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_activation_builder.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_fragment.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_map_change.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_mode.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_manual_update.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_reuse.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_visibility.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_merge_offline_regions.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_overlay.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_physical_circle.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_source_features.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_region_download.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbol_generator.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_animate.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_debug_mode.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_resize.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_zoom_symbol_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/drawer_navigation_drawer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/item_gesture_alert.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/item_viewpager.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bounds.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bulk_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_data_driven_style.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_debug.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_generator_symbol.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_gestures.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_mode.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_press_for_marker.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbols.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/local_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/sat_style.json create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_collection.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_properties.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_gradient_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_string_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_line_string_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_point_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_polygon_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_point_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_points_utrecht.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_with_hole_feature.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/raw/tiny_countries.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml create mode 100644 README.md create mode 100644 TESTS.md create mode 100644 build.gradle create mode 100644 checkstyle.xml create mode 100644 gradle/android-nitpick.gradle create mode 100644 gradle/artifact-settings.gradle create mode 100644 gradle/dependencies.gradle create mode 100644 gradle/gradle-bintray.gradle create mode 100644 gradle/gradle-checkstyle.gradle create mode 100644 gradle/gradle-config.gradle create mode 100644 gradle/gradle-dependencies-graph.gradle create mode 100644 gradle/gradle-javadoc.gradle create mode 100644 gradle/gradle-lint.gradle create mode 100644 gradle/gradle-make.gradle create mode 100644 gradle/gradle-update-vendor-modules.gradle create mode 100644 gradle/jacoco-report.gradle create mode 100644 gradle/ktlint.gradle create mode 100644 gradle/native-build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100755 resources/compass.svg create mode 100755 resources/direction-dot.svg create mode 100644 resources/dot-arrow.svg create mode 100755 resources/location-dot.svg create mode 100755 resources/location-static-dot.svg create mode 100644 scripts/exclude-activity-gen.json create mode 100644 scripts/generate-license.py create mode 100755 scripts/generate-style-code.js create mode 100644 scripts/generate-test-code.js create mode 100755 scripts/metrics.sh create mode 100755 scripts/parse-jacoco-report.py create mode 100644 scripts/release.py create mode 100644 scripts/run-render-test.py create mode 100644 scripts/validate-license.py create mode 100644 settings.gradle create mode 100755 src/android_renderer_backend.cpp create mode 100755 src/android_renderer_backend.hpp create mode 100644 src/android_renderer_frontend.cpp create mode 100644 src/android_renderer_frontend.hpp create mode 100644 src/annotation/marker.cpp create mode 100644 src/annotation/marker.hpp create mode 100644 src/annotation/multi_point.hpp create mode 100644 src/annotation/polygon.cpp create mode 100644 src/annotation/polygon.hpp create mode 100644 src/annotation/polyline.cpp create mode 100644 src/annotation/polyline.hpp create mode 100644 src/asset_manager.hpp create mode 100644 src/asset_manager_file_source.cpp create mode 100644 src/asset_manager_file_source.hpp create mode 100644 src/async_task.cpp create mode 100644 src/attach_env.cpp create mode 100644 src/attach_env.hpp create mode 100644 src/bitmap.cpp create mode 100644 src/bitmap.hpp create mode 100644 src/bitmap_factory.cpp create mode 100644 src/bitmap_factory.hpp create mode 100644 src/connectivity_listener.cpp create mode 100644 src/connectivity_listener.hpp create mode 100644 src/conversion/collection.cpp create mode 100644 src/conversion/collection.hpp create mode 100644 src/conversion/color.cpp create mode 100644 src/conversion/color.hpp create mode 100644 src/conversion/constant.cpp create mode 100644 src/conversion/constant.hpp create mode 100644 src/conversion/conversion.hpp create mode 100644 src/example_custom_layer.cpp create mode 100644 src/file_source.cpp create mode 100644 src/file_source.hpp create mode 100644 src/geojson/feature.cpp create mode 100644 src/geojson/feature.hpp create mode 100644 src/geojson/feature_collection.cpp create mode 100644 src/geojson/feature_collection.hpp create mode 100644 src/geojson/geometry.cpp create mode 100644 src/geojson/geometry.hpp create mode 100644 src/geojson/geometry_collection.cpp create mode 100644 src/geojson/geometry_collection.hpp create mode 100644 src/geojson/line_string.cpp create mode 100644 src/geojson/line_string.hpp create mode 100644 src/geojson/multi_line_string.cpp create mode 100644 src/geojson/multi_line_string.hpp create mode 100644 src/geojson/multi_point.cpp create mode 100644 src/geojson/multi_point.hpp create mode 100644 src/geojson/multi_polygon.cpp create mode 100644 src/geojson/multi_polygon.hpp create mode 100644 src/geojson/point.cpp create mode 100644 src/geojson/point.hpp create mode 100644 src/geojson/polygon.cpp create mode 100644 src/geojson/polygon.hpp create mode 100644 src/geojson/util.hpp create mode 100644 src/geometry/lat_lng.cpp create mode 100644 src/geometry/lat_lng.hpp create mode 100644 src/geometry/lat_lng_bounds.cpp create mode 100644 src/geometry/lat_lng_bounds.hpp create mode 100644 src/geometry/lat_lng_quad.cpp create mode 100644 src/geometry/lat_lng_quad.hpp create mode 100644 src/geometry/projected_meters.cpp create mode 100644 src/geometry/projected_meters.hpp create mode 100644 src/gl_functions.cpp create mode 100644 src/graphics/pointf.cpp create mode 100644 src/graphics/pointf.hpp create mode 100644 src/graphics/rectf.cpp create mode 100644 src/graphics/rectf.hpp create mode 100644 src/gson/json_array.cpp create mode 100644 src/gson/json_array.hpp create mode 100644 src/gson/json_element.cpp create mode 100644 src/gson/json_element.hpp create mode 100644 src/gson/json_object.cpp create mode 100644 src/gson/json_object.hpp create mode 100644 src/gson/json_primitive.cpp create mode 100644 src/gson/json_primitive.hpp create mode 100644 src/http_file_source.cpp create mode 100644 src/image.cpp create mode 100644 src/java/util.cpp create mode 100644 src/java/util.hpp create mode 100644 src/java_types.cpp create mode 100644 src/java_types.hpp create mode 100755 src/jni.cpp create mode 100644 src/jni.hpp create mode 100755 src/jni_native.cpp create mode 100644 src/jni_native.hpp create mode 100644 src/logger.cpp create mode 100644 src/logger.hpp create mode 100644 src/logging_android.cpp create mode 100644 src/main.cpp create mode 100644 src/map/camera_position.cpp create mode 100644 src/map/camera_position.hpp create mode 100644 src/map/image.cpp create mode 100644 src/map/image.hpp create mode 100644 src/map_renderer.cpp create mode 100644 src/map_renderer.hpp create mode 100644 src/map_renderer_runnable.cpp create mode 100644 src/map_renderer_runnable.hpp create mode 100755 src/native_map_view.cpp create mode 100755 src/native_map_view.hpp create mode 100644 src/offline/offline_manager.cpp create mode 100644 src/offline/offline_manager.hpp create mode 100644 src/offline/offline_region.cpp create mode 100644 src/offline/offline_region.hpp create mode 100644 src/offline/offline_region_definition.cpp create mode 100644 src/offline/offline_region_definition.hpp create mode 100644 src/offline/offline_region_error.cpp create mode 100644 src/offline/offline_region_error.hpp create mode 100644 src/offline/offline_region_status.cpp create mode 100644 src/offline/offline_region_status.hpp create mode 100644 src/run_loop.cpp create mode 100644 src/run_loop_impl.hpp create mode 100644 src/snapshotter/map_snapshot.cpp create mode 100644 src/snapshotter/map_snapshot.hpp create mode 100644 src/snapshotter/map_snapshotter.cpp create mode 100644 src/snapshotter/map_snapshotter.hpp create mode 100644 src/string_util.cpp create mode 100644 src/style/android_conversion.hpp create mode 100644 src/style/conversion/filter.cpp create mode 100644 src/style/conversion/filter.hpp create mode 100644 src/style/conversion/position.cpp create mode 100644 src/style/conversion/position.hpp create mode 100644 src/style/conversion/property_expression.hpp create mode 100644 src/style/conversion/property_value.hpp create mode 100644 src/style/conversion/transition_options.cpp create mode 100644 src/style/conversion/transition_options.hpp create mode 100644 src/style/conversion/url_or_tileset.cpp create mode 100644 src/style/conversion/url_or_tileset.hpp create mode 100644 src/style/formatted.cpp create mode 100644 src/style/formatted.hpp create mode 100644 src/style/formatted_section.cpp create mode 100644 src/style/formatted_section.hpp create mode 100644 src/style/layers/background_layer.cpp create mode 100644 src/style/layers/background_layer.hpp create mode 100644 src/style/layers/circle_layer.cpp create mode 100644 src/style/layers/circle_layer.hpp create mode 100644 src/style/layers/custom_layer.cpp create mode 100644 src/style/layers/custom_layer.hpp create mode 100644 src/style/layers/fill_extrusion_layer.cpp create mode 100644 src/style/layers/fill_extrusion_layer.hpp create mode 100644 src/style/layers/fill_layer.cpp create mode 100644 src/style/layers/fill_layer.hpp create mode 100644 src/style/layers/heatmap_layer.cpp create mode 100644 src/style/layers/heatmap_layer.hpp create mode 100644 src/style/layers/hillshade_layer.cpp create mode 100644 src/style/layers/hillshade_layer.hpp create mode 100644 src/style/layers/layer.cpp create mode 100644 src/style/layers/layer.cpp.ejs create mode 100644 src/style/layers/layer.hpp create mode 100644 src/style/layers/layer.hpp.ejs create mode 100644 src/style/layers/layer_manager.cpp create mode 100644 src/style/layers/layer_manager.hpp create mode 100644 src/style/layers/line_layer.cpp create mode 100644 src/style/layers/line_layer.hpp create mode 100644 src/style/layers/raster_layer.cpp create mode 100644 src/style/layers/raster_layer.hpp create mode 100644 src/style/layers/symbol_layer.cpp create mode 100644 src/style/layers/symbol_layer.hpp create mode 100644 src/style/light.cpp create mode 100644 src/style/light.hpp create mode 100644 src/style/position.cpp create mode 100644 src/style/position.hpp create mode 100644 src/style/sources/custom_geometry_source.cpp create mode 100644 src/style/sources/custom_geometry_source.hpp create mode 100644 src/style/sources/geojson_source.cpp create mode 100644 src/style/sources/geojson_source.hpp create mode 100644 src/style/sources/image_source.cpp create mode 100644 src/style/sources/image_source.hpp create mode 100644 src/style/sources/raster_dem_source.cpp create mode 100644 src/style/sources/raster_dem_source.hpp create mode 100644 src/style/sources/raster_source.cpp create mode 100644 src/style/sources/raster_source.hpp create mode 100644 src/style/sources/source.cpp create mode 100644 src/style/sources/source.hpp create mode 100644 src/style/sources/unknown_source.cpp create mode 100644 src/style/sources/unknown_source.hpp create mode 100644 src/style/sources/vector_source.cpp create mode 100644 src/style/sources/vector_source.hpp create mode 100644 src/style/transition_options.cpp create mode 100644 src/style/transition_options.hpp create mode 100644 src/style/value.cpp create mode 100644 src/style/value.hpp create mode 100644 src/test/benchmark_runner.cpp create mode 100644 src/test/runtime.cpp create mode 100644 src/test/runtime.hpp create mode 100644 src/test/test_runner.cpp create mode 100644 src/text/collator.cpp create mode 100644 src/text/collator_jni.hpp create mode 100644 src/text/format_number.cpp create mode 100644 src/text/format_number_jni.hpp create mode 100644 src/text/local_glyph_rasterizer.cpp create mode 100644 src/text/local_glyph_rasterizer_jni.hpp create mode 100644 src/thread.cpp create mode 100644 src/timer.cpp create mode 100644 src/unaccent.cpp create mode 160000 vendor/mapbox-events-android create mode 160000 vendor/mapbox-gestures-android create mode 160000 vendor/mapbox-gl-native create mode 160000 vendor/mapbox-java diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..8a6c90a0d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.{kt,kts}] +indent_size=2 +insert_final_newline=false +disabled_rules=no-wildcard-imports \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ff3db8735 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Gradle files +.gradle/ + +# IntelliJ files +.idea/ +*.iml + +# Build files +build/ +.externalNativeBuild +**/.cxx +*.so +*.apk + +# Local settings +local.properties +gradle/configuration.gradle + +# Token file +MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml + +# Capture files +captures/ + +# Generated test cases +MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen/ + +# Generated list files from code generation +/scripts/generate-style-code.list + +# Input files for running render tests +MapboxGLAndroidSDKTestApp/src/main/assets/integration/ + +# Local AS configuration file +gradle.properties \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..e59e6f17d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "vendor/mapbox-gl-native"] + path = vendor/mapbox-gl-native + url = git@github.com:mapbox/mapbox-gl-native.git +[submodule "vendor/mapbox-events-android"] + path = vendor/mapbox-events-android + url = git@github.com:mapbox/mapbox-events-android.git +[submodule "vendor/mapbox-java"] + path = vendor/mapbox-java + url = git@github.com:mapbox/mapbox-java.git +[submodule "vendor/mapbox-gestures-android"] + path = vendor/mapbox-gestures-android + url = git@github.com:mapbox/mapbox-gestures-android.git diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..5fb33f7ca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1767 @@ +# Changelog for the Mapbox Maps SDK for Android + +Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. + +## master +### Bug fixes + - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560) + +## 8.4.0-alpha.1 - September 4, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.4.0-alpha.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): + +### Features + - Introduce `clusterProperties` option for aggregated cluster properties. [#15425](https://github.com/mapbox/mapbox-gl-native/pull/15425) + - Expose the `CameraPosition#padding` field and associated utility camera position builders. This gives a choice to set a persisting map padding immediately during a transition instead of setting it lazily `MapboxMap#setPadding`, which required scheduling additional transition to be applied. This also deprecates `MapboxMap#setPadding` as there should be no need for a lazy padding setter. [#15444](https://github.com/mapbox/mapbox-gl-native/pull/15444) + - Add number-format expression that allows to format a number to a string, with configurations as minimal/maximal fraction and locale/currency. [#15424](https://github.com/mapbox/mapbox-gl-native/pull/15424) + - Enable using of `text-offset` option together with `text-variable-anchor` (if `text-radial-offset` option is not provided). If used with `text-variable-anchor`, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position. [#15542](https://github.com/mapbox/mapbox-gl-native/pull/15542) + +### Bug fixes +- Fixed a rendering issue of `collisionBox` when `text-translate` or `icon-translate` is enabled. [#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467) +- Fixed unnecessary layers blink when the same components are re-added after the style reload [#15513](https://github.com/mapbox/mapbox-gl-native/pull/15513) +- Fixed an issue in JNI marshaling code that converted a float to long that produced invalid expressions [#15557](https://github.com/mapbox/mapbox-gl-native/pull/15557) +- Call callback onFinish() immediately when trying to move camera to current position [#15558](https://github.com/mapbox/mapbox-gl-native/pull/15558) + +### Performance improvements + - Mark used offline region resources in batches. [#15521](https://github.com/mapbox/mapbox-gl-native/pull/15521) + +### Other Changes +- JNI binding refactor [#15462](https://github.com/mapbox/mapbox-gl-native/pull/15462) +- Javadoc changes to clarify OfflineManager methods [#15519](https://github.com/mapbox/mapbox-gl-native/pull/15519) + +## 8.3.0 - August 28, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-beta.1...android-v8.3.0) since [Mapbox Maps SDK for Android v8.3.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-beta.1): + +This release changes how offline tile requests are billed — they are now billed on a pay-as-you-go basis and all developers are able raise the offline tile limit for their users. Offline requests were previously exempt from monthly active user (MAU) billing and increasing the offline per-user tile limit to more than 6,000 tiles required the purchase of an enterprise license. By upgrading to this release, you are opting into the changes outlined in [this blog post](https://blog.mapbox.com/offline-maps-for-all-bb0fc51827be) and [#15380](https://github.com/mapbox/mapbox-gl-native/pull/15380). + +### Features + - Allow ability to pass a string array resource into `localIdeographFontFamily` for enabling/disabling the feature and specifying fallback fonts. [#15488](https://github.com/mapbox/mapbox-gl-native/pull/15488) + +### Bug fixes + - Fixed a rendering issue caused by all icons being treated as SDFs if an SDF and non-SDF icon were in the same layer. [#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456) + - Fixed an issue where changing location's render mode when the`LocationComponent` is disable wouldn't invalidate the foreground icon when it's back enabled. [#15507](https://github.com/mapbox/mapbox-gl-native/pull/15507) + +## 8.2.2 - August 23, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.1...android-v8.2.2) since [Mapbox Maps SDK for Android v8.2.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.1): + +### Bug fixes + - Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function. [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398) + - Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/1540) + - Fixed a wrong calculation of visibility in high pitch scenarios which might've led to tiles in the viewport not being rendered. [#15461](https://github.com/mapbox/mapbox-gl-native/pull/15461) + +### Other Changes + - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437) + +## 8.3.0-beta.1 - August 22, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.3...android-v8.3.0-beta.1) since [Mapbox Maps SDK for Android v8.3.0-alpha.3](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.3): + +### Bug fixes + - Fixed a bug where glyphs generated through the LocalGlyphRasterizer interface were changing fonts during some zoom changes. [#15407](https://github.com/mapbox/mapbox-gl-native/pull/15407) + - Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/15408) + - Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398). + - Font lookup on pre lollipop devices failed, provide default font list instead [#15410](https://github.com/mapbox/mapbox-gl-native/pull/15410). + - Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer [#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367). + - Fixed a bug where quick-scale was registered during a move gesture that followed a double-tap. Bumped gestures library to `v0.5.1`. [#15427](https://github.com/mapbox/mapbox-gl-native/pull/15427) + - Fixed symbol overlap when zooming out quickly. [#15416](https://github.com/mapbox/mapbox-gl-native/pull/15416) + +### Other Changes + - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437) + +### Docs + - Add javadoc to OnStyleImageMissingListener indicating the required synchronous addition images, document workaround [#15418](https://github.com/mapbox/mapbox-gl-native/pull/15418) + +## 8.3.0-alpha.3 - August 15, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.2...android-v8.3.0-alpha.3) since [Mapbox Maps SDK for Android v8.3.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.2): + +### Gestures handling + - Bumped gestures library version to v0.5.0 which replaces the compat gesture detector with a custom scale gesture detector implementation. This is a softly breaking change because the underlying scale gesture detector reference has been removed. This brings a set of improvements to gestures without removing any functionality from the previous implementation. [#15136](https://github.com/mapbox/mapbox-gl-native/pull/15136) + - Improved scale and rotate gestures by refining sensitivity thresholds and animation velocity. [#15136](https://github.com/mapbox/mapbox-gl-native/pull/15136) + - Improved quick-zoom gestures by making zoom changes linear. Quick-zoom scale changes are now executed based on y-axis delta changes. [#15386](https://github.com/mapbox/mapbox-gl-native/pull/15386) + +### Features + - Introduced the text-writing-mode layout property for symbol layers. This property allows labels to be placed horizontally or vertically. The property accepts an array of enumeration values from a ( horizontal | vertical ) set. [#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932) + - Added support for fallback fonts in `localIdeographFontFamily`. [#15255](https://github.com/mapbox/mapbox-gl-native/pull/15255) + +### Bug fixes + - Fixed an issue where it was possible to set the map’s content insets then tilt the map enough to see the horizon, causing performance issues [#15195](https://github.com/mapbox/mapbox-gl-native/pull/15195) + - Allow loading of a map without a style URI or style JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293) + - Fixed an issue where animated camera transitions zoomed in or out too dramatically [#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281) + - Enable variable label placement when `text-allow-overlap` property is set to true [#15354](https://github.com/mapbox/mapbox-gl-native/pull/15354) + +## 8.3.0-alpha.2 - August 7, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.1...android-v8.3.0-alpha.2) since [Mapbox Maps SDK for Android v8.3.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.1): + +### Bug fixes + - Load a style without an URI or JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293) + - Do not try to wake up the RunLoop if a wake is already pending. Fixes offline downloads that could freeze after resuming. [#15330](https://github.com/mapbox/mapbox-gl-native/pull/15330) + +## 8.0.2 - July 31, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.0.1...android-v8.0.2) since [Mapbox Maps SDK for Android v8.0.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.0.1): + +### Bug fixes + - Fixed rendering layers after fill-extrusion regression caused by optimization of fill-extrusion rendering [#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065) + - Fixed a map update bug caused by the render tiles and the render passes getting unsynchronized [#15092](https://github.com/mapbox/mapbox-gl-native/pull/15092) + - Fixed a custom geometry source bug caused by using the outdated tiles after style update [#15112](https://github.com/mapbox/mapbox-gl-native/pull/15112) + - Ensure location shadow's gradient radius is greater than 0 [#15099](https://github.com/mapbox/mapbox-gl-native/pull/15099) + +## 7.4.1 - July 31, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v7.4.0...android-v7.4.1) since [Mapbox Maps SDK for Android v7.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v7.4.0): + +### Bug fixes + - Fixed a map update bug caused by the render tiles and the render passes getting unsynchronized [#15092](https://github.com/mapbox/mapbox-gl-native/pull/15092) + - Ensure location shadow's gradient radius is greater than 0 [#15099](https://github.com/mapbox/mapbox-gl-native/pull/15099) + - Fixed a custom geometry source bug caused by using the outdated tiles after style update [#15112](https://github.com/mapbox/mapbox-gl-native/pull/15112) + +## 8.3.0-alpha.1 - July 31, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0...android-v8.3.0-alpha.1) since [Mapbox Maps SDK for Android v8.2.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0): + +### Features + - Do not include CJK ideographs in the offline packs by default. This decreases overall offline download size but changes appearance by a default set local glyph generation [#14269](https://github.com/mapbox/mapbox-gl-native/pull/14269) + - Update target SDK to 28, update support library and fix gradle warnings [#15135](https://github.com/mapbox/mapbox-gl-native/pull/15135) + - Introduce VertexVector::extend() and use it in placement code [#15194](https://github.com/mapbox/mapbox-gl-native/pull/15194) + +### Bug fixes + - Save location animation timestamp only when fed. Fixes an issue where external camera updates impacted location animation duration[#15265](https://github.com/mapbox/mapbox-gl-native/pull/15265) + - Fixed flickering on style change for the same tile set [#15127](https://github.com/mapbox/mapbox-gl-native/pull/15127) + - Fix location render/camera modes being reinitialized even when the new mode is the same [#15266](https://github.com/mapbox/mapbox-gl-native/pull/15266) + - Ensure default local ideographs font family is not overwrote. Fix a bug that prevented local CJK glyphs generation. The local generation is now enabled by default and the font family used for generation is set to "sans-serif. [#15253](https://github.com/mapbox/mapbox-gl-native/pull/15253) + - Fix int overflow issue in GridIndex [#15245](https://github.com/mapbox/mapbox-gl-native/pull/15245) + - Align gesture animation reason for onCameraMoveStarted [#15218](https://github.com/mapbox/mapbox-gl-native/pull/15218) + - Remove layers first when clearing the style, fixes unnecessary log dumps [#15191](https://github.com/mapbox/mapbox-gl-native/pull/15191) + - Remove unused field from icon buffer [#15189](https://github.com/mapbox/mapbox-gl-native/pull/15189) + +### Performance improvements + - Release quad data after vertex buffers are created [#15189](https://github.com/mapbox/mapbox-gl-native/pull/15189) + - Decrease size of SymbolBucket [#15178](https://github.com/mapbox/mapbox-gl-native/pull/15178) + - Avoid geometry collections copying [#15201](https://github.com/mapbox/mapbox-gl-native/pull/15201) + +## 8.2.1 - July 31, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0...android-v8.2.1) since [Mapbox Maps SDK for Android v8.2.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0): + +### Bug fixes + - Save location animation timestamp only when fed [#15265](https://github.com/mapbox/mapbox-gl-native/pull/15265) + +## 8.1.1 - July 26, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.1.0...android-v8.1.1) since [Mapbox Maps SDK for Android v8.1.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.1.0): + +### Bug fixes + - Fixed rendering layers after fill-extrusion regression caused by optimization of fill-extrusion rendering [#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065) + - Fixed a map update bug caused by the render tiles and the render passes getting unsynchronized [#15092](https://github.com/mapbox/mapbox-gl-native/pull/15092) + - Fixed collision with content insets [#15130](https://github.com/mapbox/mapbox-gl-native/pull/15130) + - Fixed a custom geometry source bug caused by using the outdated tiles after style update [#15112](https://github.com/mapbox/mapbox-gl-native/pull/15112) + - Allow map panning after quick zoom is disabled but a phantom gesture is executed [#15093](https://github.com/mapbox/mapbox-gl-native/pull/15093) + - Ensure location shadow's gradient radius is greater than 0 [#15099](https://github.com/mapbox/mapbox-gl-native/pull/15099) + - Ensure that move detector is enabled if double-tap is interrupted [#15103](https://github.com/mapbox/mapbox-gl-native/pull/15103) + +## 8.2.0 - July 24, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0-beta.1...android-v8.2.0) since [Mapbox Maps SDK for Android v8.2.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0-beta.1): + +### Bug fixes + - Fix rendering of layers that are on top of fill-extrusion layers [#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065) + +## 8.2.0-beta.1 - July 18, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0-alpha.3...android-v8.2.0-beta.1) since [Mapbox Maps SDK for Android v8.2.0-alpha.3](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0-alpha.3): + +### Bug fixes + - Fix `CustomGeometrySource` bug caused by usage of outdated tiles after a style update [#15112](https://github.com/mapbox/mapbox-gl-native/pull/15112) + - Fix bug where previous anchors set in `text-variable-anchor` were still preferred after anchor options were reset [#15129](https://github.com/mapbox/mapbox-gl-native/pull/15129) + - Fix issue where annotations could not be selected due to a regression in content insets [#15130](https://github.com/mapbox/mapbox-gl-native/pull/15130) + +## 8.2.0-alpha.3 - July 11, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0-alpha.2...android-v8.2.0-alpha.3) since [Mapbox Maps SDK for Android v8.2.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0-alpha.2): + +### Bug fixes + - Fix map update bug caused by render tiles and render passes becoming unsynchronized [#15092](https://github.com/mapbox/mapbox-gl-native/pull/15092) + - Fix fill-extrusion layers always rendered above other layers [#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065) + - Fix a bug where map panning would be blocked after a quick zoom gesture was attempted when quick zoom is set to be ignored by `UiSettings` preferences [#15093](https://github.com/mapbox/mapbox-gl-native/pull/15093) + - Fix a bug where map panning would be blocked if double-tap is interrupted [#15103](https://github.com/mapbox/mapbox-gl-native/pull/15103) + +### Minor features and improvements + - Improve performance of queryRenderedFeatures by removing unnecessary iterations over vectors and unneeded layers [#14930](https://github.com/mapbox/mapbox-gl-native/pull/14930) + - Decrease the minimum pixel distance between the current camera position and the target required to interpolate during camera animation [#15073](https://github.com/mapbox/mapbox-gl-native/pull/15073) + - Introduce `MapboxMapOptions` facility creation method [#15069](https://github.com/mapbox/mapbox-gl-native/pull/15069) + - Throw configuration exception when accessing Mapbox services with an invalid token [#15081](https://github.com/mapbox/mapbox-gl-native/pull/15081) + - Allow setting a null access token in the runtime [#15081](https://github.com/mapbox/mapbox-gl-native/pull/15081) + - Ensure location shadow's gradient radius is greater than 0 [#15099](https://github.com/mapbox/mapbox-gl-native/pull/15099) + +### Other Changes + - Update okhttp to latest stable version that support pre lollipop (`3.12.3`) [#15087](https://github.com/mapbox/mapbox-gl-native/pull/15087) + - Fix up "match" expressions docs with stop arguments [#15102](https://github.com/mapbox/mapbox-gl-native/pull/15102) + +## 8.2.0-alpha.2 - July 3, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0-alpha.1...android-v8.2.0-alpha.2) since [Mapbox Maps SDK for Android v8.2.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0-alpha.1): + +### Major features + - Cache management API [#14962](https://github.com/mapbox/mapbox-gl-native/pull/14962) + +### Bug fixes + - Fix style change transition regression caused by delayed setting of the updated layer properties [#15016](https://github.com/mapbox/mapbox-gl-native/pull/15016) + +### Minor features and improvements + - Include Hiragana and Katakana glyph ranges to LocalGlyphRasterizer [#15009](https://github.com/mapbox/mapbox-gl-native/pull/15009) + +### Other Changes + - Update CI image with NDK r20 [#15005](https://github.com/mapbox/mapbox-gl-native/pull/15005) + +## 8.2.0-alpha.1 - June 26, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.1.0...android-v8.2.0-alpha.1) since [Mapbox Maps SDK for Android v8.1.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.1.0): + +### Bug fixes + - Fix `queryRenderedFeatues` bug caused by incorrect sort feature index calculation [#14884](https://github.com/mapbox/mapbox-gl-native/pull/14884) + - Fix performance regression by switching back to a more compact line attributes layout [#14851](https://github.com/mapbox/mapbox-gl-native/pull/14851) + - Fix a bug that restricted camera viewport after camera bounds were reset [#14882](https://github.com/mapbox/mapbox-gl-native/pull/14882) + - Fix a bug that ignored floating point values during core to platform color conversion [#14954](https://github.com/mapbox/mapbox-gl-native/pull/14954) + - Implemented asymmetric center of perspective: fixed an issue that caused the focal point to be always based on the view's horizontal center when setting [MapboxMap setPadding](https://docs.mapbox.com/android/api/map-sdk/8.0.0/com/mapbox/mapboxsdk/maps/MapboxMap.html#setPadding-int-int-int-int-). [#14664](https://github.com/mapbox/mapbox-gl-native/pull/14664) + +### Minor features and improvements + - Allow null updates to GeoJsonSource [#14898](https://github.com/mapbox/mapbox-gl-native/pull/14898) + +### Other Changes + - Add resource usage to HttpRequest, add offline query flag to HttpRequest [#14837](https://github.com/mapbox/mapbox-gl-native/pull/14837) + +## 8.1.0 - June 20, 2019 + +### Bugs + - Accept floating numbers during core->platform color conversion [#14954](https://github.com/mapbox/mapbox-gl-native/pull/14954) + - Ensure to re-enable move when quickzoom finishes [#14965](https://github.com/mapbox/mapbox-gl-native/pull/14965) + +### Features + - Limit concurrent request for Android 4.4 and below to 10 [#14971](https://github.com/mapbox/mapbox-gl-native/pull/14971) + +_Note about #14971:_ This pr makes an adjustment as a precautionary measure towards a rare bug that was discovered via instrumented unit tests on Android 4.4 (aka KitKat). This bug isn’t tied to a code change in the Mapbox Maps SDK for Android. Rather, the root cause is on the Android OS (and how it interacts with OkHttp). + +The Maps SDK doesn’t directly communicate with this system library that the bug originates from, but goes through an external dependency that handles the http communication for the Maps SDK. Capturing from the upstream repository that the code path to this system library isn’t thread safe in Android 4.4 and can result in the native crash above. The only way to fix this issue is by upgrading the end-user device to Android 5.0 or higher which isn’t possible if the device manufacturer hasn’t released an update for it. + +Please see https://github.com/square/okhttp/issues/2679 for more information. + +## 8.1.0-beta.1 - June 13, 2019 + +### Bugs + - Fix compilation warning with updated clang [#14865](https://github.com/mapbox/mapbox-gl-native/pull/14865) + - Fix reset behavior for setLatLngBoundsForCameraTarget [#14882](https://github.com/mapbox/mapbox-gl-native/pull/14882) + +### Features + - Add resource usage to HttpRequest, add offline query param [#14837](https://github.com/mapbox/mapbox-gl-native/pull/14837) + +## 8.0.1 - June 11, 2019 + +### Bugs + - Reset the native renderer only when the GL thread exits [#14841](https://github.com/mapbox/mapbox-gl-native/pull/14841) + - Change library loader from Relinker to SoLoader [#14890](https://github.com/mapbox/mapbox-gl-native/pull/14890) + +## 8.1.0-alpha.2 - June 6, 2019 + +### Bugs + - Copy features array before passing them to core [#14804](https://github.com/mapbox/mapbox-gl-native/pull/14804) + - Improve test stability [#14853](https://github.com/mapbox/mapbox-gl-native/pull/14853) + +### Features + - Rename URL API to URI [#14836](https://github.com/mapbox/mapbox-gl-native/pull/14836) + +### Build + - Bumping Android telemetry to 4.5.1 [#14874](https://github.com/mapbox/mapbox-gl-native/pull/14874) + +### Docs + - Add external links to javadoc generation, fix warnings [#14792](https://github.com/mapbox/mapbox-gl-native/pull/14792) + +## 8.1.0-alpha.1 - June 3, 2019 + +### Bugs + - Return color string values in the [0-255] range [#14233](https://github.com/mapbox/mapbox-gl-native/pull/14233) + - Resume file source to complete resources cache path change [#14546](https://github.com/mapbox/mapbox-gl-native/pull/14546) + - Remove binary shader support [#14707](https://github.com/mapbox/mapbox-gl-native/pull/14707) + - Deprecate MapboxMapOptions empty constructor [#14748](https://github.com/mapbox/mapbox-gl-native/pull/14748) + + +### Features + - Break location camera tracking when a developer invoked animation starts [#14745](https://github.com/mapbox/mapbox-gl-native/pull/14745) + - Use URI instead of URL to enable asset loading [#14750](https://github.com/mapbox/mapbox-gl-native/pull/14750) + - Option to change the zoom rate. Decrease the default zoom rate by 35% [#14774](https://github.com/mapbox/mapbox-gl-native/pull/14774) + - Provide API to control eviction of cached images [#14610](https://github.com/mapbox/mapbox-gl-native/pull/14610) + - Android specific thread pool that keeps threads attached to JVM [#14450](https://github.com/mapbox/mapbox-gl-native/pull/14450) + - Asymmetric viewport when edge insets are specified [#14664](https://github.com/mapbox/mapbox-gl-native/pull/14664) + +### Build + - Update maven publishing script to enable aar packaging [#14778](https://github.com/mapbox/mapbox-gl-native/pull/14778) + - Do not try to package duplicate files in the publication [#14822](https://github.com/mapbox/mapbox-gl-native/pull/14822) + +### Docs + - Document that elevation(0) turns off the location shadow [#14723](https://github.com/mapbox/mapbox-gl-native/pull/14723) + +## 8.0.0 - May 22, 2019 + - This release improves the method for counting monthly active users. By upgrading to this release, you are opting into the changes outlined [in this blog post](https://www.mapbox.com/52219). [#14404](https://github.com/mapbox/mapbox-gl-native/pull/14404) + +## 6.8.2 - May 17, 2019 + +### Bugs + - Avoid binary shader load race condition with using multiple maps, disable binary shaders [#14298](https://github.com/mapbox/mapbox-gl-native/pull/14298) + +## 7.5.0-beta.1 - May 17, 2019 + +### Features + - Option to provide custom values for location camera transition [#14606](https://github.com/mapbox/mapbox-gl-native/pull/14606) + +### Bugs + - Expose trackingGesturesManagement attribute [#14659](https://github.com/mapbox/mapbox-gl-native/pull/14659) + - Harden onLowMemory call, use atomic boolean for thread safe management of the render surface [#14622](https://github.com/mapbox/mapbox-gl-native/pull/14622) + - Normalize previous rotation values of the location animator [#14626](https://github.com/mapbox/mapbox-gl-native/pull/14626) + +### Performance + - Remove telemetry gesture event handling code [#14627](https://github.com/mapbox/mapbox-gl-native/pull/14627) + +### Localisation + - Pull in Polish translation and updates to Czech and Hungarian [#14679](https://github.com/mapbox/mapbox-gl-native/pull/14679) + +### Docs + - Add javadoc to highlight incompatible onIdle event with snapshot api [#14621](https://github.com/mapbox/mapbox-gl-native/pull/14621) + +## 7.4.0 - May 15, 2019 +### Features + - Revert SKU token logic [#14594](https://github.com/mapbox/mapbox-gl-native/pull/14594) + +### Bugs + - Keep strong references to the FileSource/OfflineManager operations callbacks [#14601](https://github.com/mapbox/mapbox-gl-native/pull/14601) + - Failed sprite requests do not block tiles rendering [#14605](https://github.com/mapbox/mapbox-gl-native/pull/14605) + - Remove missing image log [#14600](https://github.com/mapbox/mapbox-gl-native/pull/14600) + +## 7.5.0-alpha.2 - May 8, 2019 +### Bugs + - Keep shared_ptr to thread pool in CustomGeometrySource [#14562](https://github.com/mapbox/mapbox-gl-native/pull/14562) + - Changed placement order of symbols to match the viewport-y order when the `PropertyValue#symbolZOrder` is set to `SYMBOL_Z_ORDER_VIEWPORT_Y`, improving collision detection and rendering of symbol layers when icons are allowed to overlap but not text. [#14486](https://github.com/mapbox/mapbox-gl-native/pull/14486) + +## 7.5.0-alpha.1 - May 2, 2019 +### Bugs + - Use same OfflineRegion#isComplete logic as core [#14500](https://github.com/mapbox/mapbox-gl-native/pull/14500) + - Add toString, hashcode and equals to OfflineRegionError [#14499](https://github.com/mapbox/mapbox-gl-native/pull/14499) + +### Features + - Add "layer-above" option to the LocationComponent [#14497](https://github.com/mapbox/mapbox-gl-native/pull/14497) + +### Build + - Update mapbox java sdk to v4.7.0 [#14480](https://github.com/mapbox/mapbox-gl-native/pull/14480) + - Update gestures library to v0.4.2 [#14524](https://github.com/mapbox/mapbox-gl-native/pull/14524) + +### Docs + - Clear up LocationComponent's z-index positioning docs [#14497](https://github.com/mapbox/mapbox-gl-native/pull/14497) + +## 7.4.0-beta.3 - May 2, 2019 +### Features +- Less strict rules for adding render layers to sources [#14540](https://github.com/mapbox/mapbox-gl-native/pull/14540) +- Store type of renderable segment when sorting symbols by key [#14517](https://github.com/mapbox/mapbox-gl-native/pull/14517) + +### Build + - Bump gestures library to v0.4.2 [#14524](https://github.com/mapbox/mapbox-gl-native/pull/14524) + +## 7.4.0-beta.2 - April 23, 2019 +### Features + - Enable/Disable SKU token handling [#14476](https://github.com/mapbox/mapbox-gl-native/pull/14476) + +## 7.4.0-beta.1 - April 19, 2019 +### Bugs + - Order render items properly across several sources [#14408](https://github.com/mapbox/mapbox-gl-native/pull/14408) + - Ignore equal offline region's download state updates [#14399](https://github.com/mapbox/mapbox-gl-native/pull/14399) + - Activate the ConnectivityReceiver when starting the download [#14397](https://github.com/mapbox/mapbox-gl-native/pull/14397) + +### Features + - Port symbol-sort-key symbol layout property [#14386](https://github.com/mapbox/mapbox-gl-native/pull/14386) + - Add style image missing binding integration [#14320](https://github.com/mapbox/mapbox-gl-native/pull/14320) + - Allow snapshot generation without overlain view content [#14413](https://github.com/mapbox/mapbox-gl-native/pull/14413) + - Introduce AccountsManager to support SKU tokens in API requests [#14404](https://github.com/mapbox/mapbox-gl-native/pull/14404) + - Add MapEventFactory [#14309](https://github.com/mapbox/mapbox-gl-native/pull/14309) + - Only perform thread checking in debug builds [#14293](https://github.com/mapbox/mapbox-gl-native/pull/14293) + +### Build + - Bump gestures library to v0.4.1 [#14435](https://github.com/mapbox/mapbox-gl-native/pull/14435) + - Update mapbox java sdk to v4.6.0 [#14424](https://github.com/mapbox/mapbox-gl-native/pull/14424) + - Bump telemetry to 4.4.1 [#14309](https://github.com/mapbox/mapbox-gl-native/pull/14309) + - Program against NativeMap [#14412](https://github.com/mapbox/mapbox-gl-native/pull/14412) + +## 7.3.2 - April 17, 2019 +## Bugs + - Unify has surface state handling, allow querying after map resume [#14426](https://github.com/mapbox/mapbox-gl-native/pull/14426) + +## 7.3.1 - April 12, 2019 +## Bugs + - Harden renderer invocation when Activity is resumed [#14395](https://github.com/mapbox/mapbox-gl-native/pull/14395) + - Check for Mapbox#INSTANCE when initializing the MapView [#14366](https://github.com/mapbox/mapbox-gl-native/pull/14366) + - Disable binary programs shaders [#14298](https://github.com/mapbox/mapbox-gl-native/pull/14298) + +## 7.4.0-alpha.2 - April 10, 2019 +### Bugs + - Check for Mapbox#INSTANCE when initializing the MapView [#14366](https://github.com/mapbox/mapbox-gl-native/pull/14366) + - Clear previous style loaded listener when setting a new style[#14338](https://github.com/mapbox/mapbox-gl-native/pull/14338) + +### Features + - Allow resetting a custom OkHttp client to the default impl [#14349](https://github.com/mapbox/mapbox-gl-native/pull/14349) + - Expose LocationComponentConstants class [#14333](https://github.com/mapbox/mapbox-gl-native/pull/14333) + +### Build + - Fix build with mismatching glShaderSource signature[#14339](https://github.com/mapbox/mapbox-gl-native/pull/14339) + +## 7.4.0-alpha.1 - April 3, 2019 + +### Bugs + - Clean up location permissions annotation [#14311](https://github.com/mapbox/mapbox-gl-native/pull/14311) + - Clear camera callbacks' message queue when the map is destroyed [#14292](https://github.com/mapbox/mapbox-gl-native/pull/14292) + - Use a valid gestures focal point when resetting a manager [#14284](https://github.com/mapbox/mapbox-gl-native/pull/14284) + - Disable move gesture detector foreseeing the quickzoom [#14268](https://github.com/mapbox/mapbox-gl-native/pull/14268) + - Remove request render from MapboxMap#onStart [#14245](https://github.com/mapbox/mapbox-gl-native/pull/14245) + - Use TurfMeasurement#distance in LatLng#distanceTo [#14220](https://github.com/mapbox/mapbox-gl-native/pull/14220) + +### Features + - Add pixel dimension annotation to public UiSettings methods [#14281](https://github.com/mapbox/mapbox-gl-native/pull/14281) + - Add #toString override for formatted sections [#14247](https://github.com/mapbox/mapbox-gl-native/pull/14247) + - Harden fetching camera for bounds when padding is excessive [#14221](https://github.com/mapbox/mapbox-gl-native/pull/14221) + - Traverse expression tree when checking for property overrides [#14259](https://github.com/mapbox/mapbox-gl-native/pull/14259) + - Variable label placement [#14184](https://github.com/mapbox/mapbox-gl-native/pull/14184) + +### Build + - Disable binary programs until we fix [#14294]((https://github.com/mapbox/mapbox-gl-native/pull/14298) + - Disable leak canary during instrumentation tests [#14296](https://github.com/mapbox/mapbox-gl-native/pull/14296) + - Remove Android v7 support library [#14265](https://github.com/mapbox/mapbox-gl-native/pull/14265) + +## 7.3.0 - March 28, 2019 + +### Bugs + - Fix MapView reuse issues [#14127](https://github.com/mapbox/mapbox-gl-native/pull/14127) + - Don't call OnSurfaceCreated from the main thread [#14244](https://github.com/mapbox/mapbox-gl-native/pull/14244) + +## 7.3.0-beta.1 - March 20, 2019 + +### Features + - Expose "text-color" option for formatted sections [#14128](https://github.com/mapbox/mapbox-gl-native/pull/14128) + - Expose LocationComponent's layer IDs [#14155](https://github.com/mapbox/mapbox-gl-native/pull/14155) + +### Bugs + - Cache location layer IDs in a set instead of a list [#14141](https://github.com/mapbox/mapbox-gl-native/pull/14141) + - Clear the style object when the map is destroyed [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + - Cache source/layer only when successfully added [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + +### Build + - Bump telemetry version to 4.3.0 [#14140](https://github.com/mapbox/mapbox-gl-native/pull/14140) + +## 7.3.0-alpha.2 - March 13, 2019 + +### Features +- Option to change path of the resources cache db [#13947](https://github.com/mapbox/mapbox-gl-native/pull/13947) +- Throw an exception if the component is accessed before the activation [#14068](https://github.com/mapbox/mapbox-gl-native/pull/14068) +- Add Galician localization [#14095](https://github.com/mapbox/mapbox-gl-native/pull/14095) + +### Bugs +- Set a blank style when an empty builder is provided [#14085](https://github.com/mapbox/mapbox-gl-native/pull/14085) +- Fix quick-zoom + double-tap gestures combo regression [#14084](https://github.com/mapbox/mapbox-gl-native/pull/14084) +- Explicitly declare MapboxIssueRegistry's lint version [#14086](https://github.com/mapbox/mapbox-gl-native/pull/14086) + +### Build +- Publish SNAPSHOTs to oss.jfrog.org [#14067](https://github.com/mapbox/mapbox-gl-native/pull/14067) + +## 7.3.0-alpha.1 - March 7, 2019 + +### Features +- Make ReLinker default library loader [#13974](https://github.com/mapbox/mapbox-gl-native/pull/13974) +- Add plural style builder methods [#14012](https://github.com/mapbox/mapbox-gl-native/pull/14012) +- Adding areAllGesturesEnabled() boolean retreival method to UiSettings class [#14022](https://github.com/mapbox/mapbox-gl-native/pull/14022) +- Adding builder pattern for LocationComponent activation [#13941](https://github.com/mapbox/mapbox-gl-native/pull/13941) +- Get vector drawables using AppCompatResources and set them programmatically [#14058](https://github.com/mapbox/mapbox-gl-native/pull/14058) + +### Bugs +- LatLngBounds: Fix constrain when crossing antimeridian [#13958](https://github.com/mapbox/mapbox-gl-native/pull/13958) +- Verify no native method is called when saving state [#13980](https://github.com/mapbox/mapbox-gl-native/pull/13980) +- Clear fragment's onMapReady callbacks as part of OnDestroy, not OnDestroyView [#14035](https://github.com/mapbox/mapbox-gl-native/pull/14035) +- Fix dialog fragment setup, add regression test [#14036](https://github.com/mapbox/mapbox-gl-native/pull/14036) +- Remove unused dem memory [#13550](https://github.com/mapbox/mapbox-gl-native/pull/13550) + +### Build +- Adding Bintray Gradle plugin for artifact publishing [#13999](https://github.com/mapbox/mapbox-gl-native/pull/13999) + +## 7.2.0 - February 27, 2019 + +### Bugs +- fix surface creation after app backgrounding for surfaceview[#13976](https://github.com/mapbox/mapbox-gl-native/pull/13976) + +## 7.2.0-beta.1 - February 21, 2019 + +### Bugs +- Keep location component's layers hidden when new style with the "layer-below" option is applied[#13936](https://github.com/mapbox/mapbox-gl-native/pull/13936) + +### Features +- Set localIdeographFontFamily default to sans-serif[#13925](https://github.com/mapbox/mapbox-gl-native/pull/13925) + +## 7.2.0-alpha.2 - February 14, 2019 + +### Bugs +- Invalidate the camera position when gesture finishes[#13920](https://github.com/mapbox/mapbox-gl-native/pull/13920) +- Hook into surface holder to cleanup renderer on the right thread before the surface is destroyed [#13926](https://github.com/mapbox/mapbox-gl-native/pull/13926) +- Fix deadlock in http request on hitting tile limit[#13858](https://github.com/mapbox/mapbox-gl-native/pull/13858) + +## 7.2.0-alpha.1 - February 7, 2019 + +### Build +- Update downstream circle-ci job name [#13872](https://github.com/mapbox/mapbox-gl-native/pull/13872) +- Prioritize running benchmarks when building master [#13801](https://github.com/mapbox/mapbox-gl-native/pull/13801) +- Revert modules vendorization and keep submodules only [#13806](https://github.com/mapbox/mapbox-gl-native/pull/13806) +- Run vendor submodule check [#13816](https://github.com/mapbox/mapbox-gl-native/pull/13816) +- Fetch tags during nitpick, bump gestures library to v0.4.0 [#13847](https://github.com/mapbox/mapbox-gl-native/pull/13847) + +### Bugs +- Test app fixes 7.1.0 QA [#13773](https://github.com/mapbox/mapbox-gl-native/pull/13773) +- Remove deprecated javacompile, resolve AS 3.3.0 warning on deprecation [#13777](https://github.com/mapbox/mapbox-gl-native/pull/13777) +- Update project readme with buck source file ignore configuration [#13788](https://github.com/mapbox/mapbox-gl-native/pull/13788) +- Fix LocationEngine's annotation [#13792](https://github.com/mapbox/mapbox-gl-native/pull/13792) +- Fix core-only layer creation [#13798](https://github.com/mapbox/mapbox-gl-native/pull/13798) +- Remove faulty cast to uint64_t, explict casting for cluster API [#13888](https://github.com/mapbox/mapbox-gl-native/pull/13888) + +### Features +- Separate quick zoom gesture option [#13791](https://github.com/mapbox/mapbox-gl-native/pull/13791) +- Location animators memory and CPU optimizations [#13678](https://github.com/mapbox/mapbox-gl-native/pull/13678) +- Added performance event [#13795](https://github.com/mapbox/mapbox-gl-native/pull/13795) +- Adding new variation of LocationComponent#activateLocationComponent [#13829](https://github.com/mapbox/mapbox-gl-native/pull/13829) +- Expose symbol placement transition duration option [#13868](https://github.com/mapbox/mapbox-gl-native/pull/13868) +- Add experimental pointer [#13889](https://github.com/mapbox/mapbox-gl-native/pull/13889) + +## 7.1.2 - February 7, 2019 + +### Bugs + - Fix layer not rendering correctly when property value's negative [#13888](https://github.com/mapbox/mapbox-gl-native/pull/13888) + +## 7.1.1 - February 1, 2019 + +### Bugs + - Fix a crash caused by the missing `Timber` dependency [#13847](https://github.com/mapbox/mapbox-gl-native/pull/13847) + +## 7.1.0 - January 30, 2019 + +### Build + - Revert Android vendorization, add submodule pinning [#13815](https://github.com/mapbox/mapbox-gl-native/pull/13815) + +## 7.1.0-beta.1 - January 23, 2019 + +### Bugs + - Ignore unused C++ arguments for all build environments [#13774](https://github.com/mapbox/mapbox-gl-native/pull/13774) + - Import gesture detector dimens using the correct package structure [#13750](https://github.com/mapbox/mapbox-gl-native/pull/13750) + - Restore location layer visibility with new "layer-below" [#13771](https://github.com/mapbox/mapbox-gl-native/pull/13771) + - Rename required TransitionOptions field [#13769](https://github.com/mapbox/mapbox-gl-native/pull/13769) + +### Build + - Ignore unused C++ arguments for all build environments [#13774](https://github.com/mapbox/mapbox-gl-native/pull/13774) + - Update to NDK 19, migrate STL experimental/optional [#13049](https://github.com/mapbox/mapbox-gl-native/pull/13049) + +## 7.1.0-alpha.3 - January 21, 2019 + +### Features + - Add library loading to peer objects [#13758](https://github.com/mapbox/mapbox-gl-native/pull/13758) + - Remove tile sorting from the clip and mask algorithms [#13756](https://github.com/mapbox/mapbox-gl-native/pull/13756) + - Ability to disable any layer using pre-processing flags [#13717](https://github.com/mapbox/mapbox-gl-native/pull/13717) + - Make library loader load the native library once [#13748](https://github.com/mapbox/mapbox-gl-native/pull/13748) + - Allow offline and snapshotter to be disabled [#13730](https://github.com/mapbox/mapbox-gl-native/pull/13730) + - Sorted render tiles for TilePyramid [#13739](https://github.com/mapbox/mapbox-gl-native/pull/13739) + +### Bugs + - Adjust maven pom file with vendorized libraries versions [#13765](https://github.com/mapbox/mapbox-gl-native/pull/13765) + - Update attribution feedback URL in code and tests [#13710](https://github.com/mapbox/mapbox-gl-native/pull/13710) + - Re-apply location components "layer-below" when changed [#13749](https://github.com/mapbox/mapbox-gl-native/pull/13749) + - Avoid leaking CompassView context through animator [#13743](https://github.com/mapbox/mapbox-gl-native/pull/13743) + - Allow resetting fps listener [#13733](https://github.com/mapbox/mapbox-gl-native/pull/13733) + +## 7.1.0-alpha.2 - January 16, 2019 + - Do not invoke #onCancel when animation is scheduled from #onFinish block [#13737](https://github.com/mapbox/mapbox-gl-native/pull/13737) + - Updated licenses after Android vendorization [#13738](https://github.com/mapbox/mapbox-gl-native/pull/13738) + - Use QueryFeatureExtension to query the map for supercluster v0.3.0 properties, add api for getLeaves, getChildren and getNextExpansionZoom [#13631](https://github.com/mapbox/mapbox-gl-native/pull/13631) + - Restore correct Snapshot attribution, make attribution parser backwards compatible [#13732](https://github.com/mapbox/mapbox-gl-native/pull/13732) + - Vendorize Android Mapbox dependencies [#13712](https://github.com/mapbox/mapbox-gl-native/pull/13712) + - Introduce NativeMap abstraction, remove static code block removal utility [#13681](https://github.com/mapbox/mapbox-gl-native/pull/13681) + - Notify requests about network reachability in priority order [#13721](https://github.com/mapbox/mapbox-gl-native/pull/13721) + - SymbolBucket, use single map for paint properties data [#13724](https://github.com/mapbox/mapbox-gl-native/pull/13724) + - Avoid NullPointerException when quickly closing activity for attribution click handling [#13723](https://github.com/mapbox/mapbox-gl-native/pull/13723) + - Return constexpr strings from functions to avoid ODR compile failures [#13720](https://github.com/mapbox/mapbox-gl-native/pull/13720) + - Split layer type specific code in mbgl::Programs [#13577](https://github.com/mapbox/mapbox-gl-native/pull/13577) + - Shader program must always match bucket in render symbol layer [#13667](https://github.com/mapbox/mapbox-gl-native/pull/13667) + - Implement Google benchmark runner for Android platform [#13628](https://github.com/mapbox/mapbox-gl-native/pull/13628) + - Avoid leaking attribution dialog when hosting context is stopped [#13673](https://github.com/mapbox/mapbox-gl-native/pull/13673) + - Android test runner for core unit tests [#13617](https://github.com/mapbox/mapbox-gl-native/pull/13617) + - Throw IllegalStateException when when setting an maximum fps while the mapRenderer isn't created yet [#13706](https://github.com/mapbox/mapbox-gl-native/pull/13706) + - Lift Parceable interface to OfflineRegionDefinition [#13688](https://github.com/mapbox/mapbox-gl-native/pull/13688) + - Espresso test rework [#13576](https://github.com/mapbox/mapbox-gl-native/pull/13576) + + +## 7.0.1 - January 11, 2019 + - Experimental setMaximumFps configuration on MapView [#13498](https://github.com/mapbox/mapbox-gl-native/pull/13498) + +## 7.1.0-alpha.1 - January 9, 2019 + - Add a Buck build and BUCK file for Android [#13584](https://github.com/mapbox/mapbox-gl-native/pull/13584) + - Instrumented unit tests, add map tests, refactor generated layer tests [#13443](https://github.com/mapbox/mapbox-gl-native/pull/13443) + - Add setMaximumFps configuration on MapView [#13498](https://github.com/mapbox/mapbox-gl-native/pull/13498) + - Fix deduping rings in quering [#11984](https://github.com/mapbox/mapbox-gl-native/pull/11984) + - Updated script detection for Unicode 11 [#13651](https://github.com/mapbox/mapbox-gl-native/pull/13651) + - Drop layer type and remaining usages [#13624](https://github.com/mapbox/mapbox-gl-native/pull/13624) + - Save debug cache state vs map state [#13638](https://github.com/mapbox/mapbox-gl-native/pull/13638) + - Add "localIdeographs" option to OfflineRegionDefinition [#13607](https://github.com/mapbox/mapbox-gl-native/pull/13607) + - Remove timber in favor of logger [#13625](https://github.com/mapbox/mapbox-gl-native/pull/13625) + +## 7.0.0 - January 7, 2019 + - Update core styles based on the streets-v8 source. This results in breaking changes for any code that references internal layers and sources of the style [#13615](https://github.com/mapbox/mapbox-gl-native/pull/13615) + - Cancel camera transitions only when set CameraMode is not None [#13662](https://github.com/mapbox/mapbox-gl-native/pull/13662) + - Fix location interval workaround initialization [#13670](https://github.com/mapbox/mapbox-gl-native/pull/13670) + +## 7.0.0-beta.2 - December 21, 2018 + - Mapbox services sdk version bump to 4.3.0 [#13610](https://github.com/mapbox/mapbox-gl-native/pull/13610) + - Added Style object parameter mention to LocationComponent methods [#13597](https://github.com/mapbox/mapbox-gl-native/pull/13597) + - Clean up remaining deprecated methods for 7.0.0 [#13613](https://github.com/mapbox/mapbox-gl-native/pull/13613) + - Dismiss the foreground color only when the style is loaded [#13582](https://github.com/mapbox/mapbox-gl-native/pull/13582) + - Location update fastest interval workaround[#13592](https://github.com/mapbox/mapbox-gl-native/pull/13592) + - CameraMode transition animation and result listeners[#13523](https://github.com/mapbox/mapbox-gl-native/pull/13523) + - Validate if weakreference is still valid [#13555](https://github.com/mapbox/mapbox-gl-native/pull/13555) + +## 6.8.1 - December 21, 2018 + - Telemetry bump to 3.5.7 [#13645](https://github.com/mapbox/mapbox-gl-native/pull/13645) + - Revert core styles back to streets-v7 source [#13648](https://github.com/mapbox/mapbox-gl-native/pull/13648) + +## 6.8.0 - December 19, 2018 + - Update core styles based on the streets-v8 source. This results in breaking changes for any code that references internal layers and sources of the style [#13615](https://github.com/mapbox/mapbox-gl-native/pull/13615) + - Fixed compass update time not getting updated [#13569](https://github.com/mapbox/mapbox-gl-native/pull/13569) + - Register compass sensor listener only if necessary [#13573](https://github.com/mapbox/mapbox-gl-native/pull/13573) + - Immediate location animation based on map's projection [#13545](https://github.com/mapbox/mapbox-gl-native/pull/13545) + - Option to disable smooth animation of compass and accuracy values [#13574](https://github.com/mapbox/mapbox-gl-native/pull/13574) + - Add onDidBecomeIdle to Map events [#13513](https://github.com/mapbox/mapbox-gl-native/pull/13513) + - Expose setAccessToken on Mapbox.java [#13397](https://github.com/mapbox/mapbox-gl-native/pull/13397) + - Expose endpoint change option for snapshotter [#13508](https://github.com/mapbox/mapbox-gl-native/pull/13508) + - Use locale sensitive DecimalFormat for color alpha conversion [#13393](https://github.com/mapbox/mapbox-gl-native/pull/13393) + - Enabled RecyclerView integration [#13132](https://github.com/mapbox/mapbox-gl-native/pull/13132) + +## 7.0.0-beta.1 - December 12, 2018 + - Style builder and Style.java [#13484](https://github.com/mapbox/mapbox-gl-native/pull/13484) + - LatLng bounds cannot be wrapped [#13419](https://github.com/mapbox/mapbox-gl-native/pull/13419) + - Expose endpoint change option for snapshotter [#13508](https://github.com/mapbox/mapbox-gl-native/pull/13508) + - Formatted "text-field" property setter [#13358](https://github.com/mapbox/mapbox-gl-native/pull/13358) + - Expose setAccesToken on Mapbox.java [#13397](https://github.com/mapbox/mapbox-gl-native/pull/13397) + - Immediately notify core about forced connectivity state [#13485](https://github.com/mapbox/mapbox-gl-native/pull/13485) + - Handle transition duration of 0ms for symbols [#13535](https://github.com/mapbox/mapbox-gl-native/pull/13535) + - Returning boolean when removing sources and layers [#13428](https://github.com/mapbox/mapbox-gl-native/pull/13428) + - Telemetry v4.1.1 bump [#13499](https://github.com/mapbox/mapbox-gl-native/pull/13499) + - mapbox-java 4.2.0 bump [#13507](https://github.com/mapbox/mapbox-gl-native/pull/13507) + +## 7.0.0-alpha.3 - November 30, 2018 + - Add `fill-extrusion-vertical-gradient` fill paint property [#13463](https://github.com/mapbox/mapbox-gl-native/pull/13463) + - Don't cancel core transitions on MotionEvent#ACTION_CANCEL [#13465](https://github.com/mapbox/mapbox-gl-native/pull/13465) + - Require context in AttributionParser.Options [#13444](https://github.com/mapbox/mapbox-gl-native/pull/13444) + - Deprecated annotations package [#13468](https://github.com/mapbox/mapbox-gl-native/pull/13468) + - Send turnstile event while create MapSnapshotter instance [#13475](https://github.com/mapbox/mapbox-gl-native/pull/13475) + - Remove default zoom level restrictions when activating the location component [#13425](https://github.com/mapbox/mapbox-gl-native/pull/13425) + +## 6.7.2 - November 30, 2018 + - Telemetry v3.5.6 [#13486](https://github.com/mapbox/mapbox-gl-native/pull/13486) + - Add "localIdeographFontFamily" setting to MapSnapshotter to reduce font data usage while snapshotting CJK maps [#13427](https://github.com/mapbox/mapbox-gl-native/pull/13427) + - Send turnstile event while creating MapSnapshotter instance [#13475](https://github.com/mapbox/mapbox-gl-native/pull/13475) + +## 7.0.0-alpha.2 - November 21, 2018 + - Add overlay example with custom drawing using paint and canvas [#13431](https://github.com/mapbox/mapbox-gl-native/pull/13431) + - Use --info argument to show details during test run [#13415](https://github.com/mapbox/mapbox-gl-native/pull/13415) + - Add specific name logging in failure scenarios of PropertyValue [#13409](https://github.com/mapbox/mapbox-gl-native/pull/13409) + - Fixed constant layer filter [#13406](https://github.com/mapbox/mapbox-gl-native/pull/13406) + - Update map feedback URL [#13396](https://github.com/mapbox/mapbox-gl-native/pull/13396) + - Use locale sensitive DecimalFormat for color alpha conversion [#13393](https://github.com/mapbox/mapbox-gl-native/pull/13393) + - Fixed `{prefix}` in tile resource URLs [#13429](https://github.com/mapbox/mapbox-gl-native/pull/13429) + +## 6.7.1 - November 16, 2018 + - Telemetry v3.5.4 [#13330](https://github.com/mapbox/mapbox-gl-native/pull/13330) + +## 7.0.0-alpha.1 - November 14, 2018 + - Added Nullable and NonNull annotations [#13274](https://github.com/mapbox/mapbox-gl-native/pull/13274) + - Catch and re-throw throwables thrown inside map state callbacks [#13351](https://github.com/mapbox/mapbox-gl-native/pull/13351) + - Removed deprecated code and notices [#13244](https://github.com/mapbox/mapbox-gl-native/pull/13244) + - Update to mapbox java services 4.1.0 [#13357](https://github.com/mapbox/mapbox-gl-native/pull/13357) + - Removed deprecated color conversion from PropertyFactory [#13337](https://github.com/mapbox/mapbox-gl-native/pull/13337) + - Removed deprecated OnMapChange interface and implementation [#13240](https://github.com/mapbox/mapbox-gl-native/pull/13240) + - Cleanup isDismissible flag [#13197](https://github.com/mapbox/mapbox-gl-native/pull/13179) + - Removed java 8 language features [#13193](https://github.com/mapbox/mapbox-gl-native/pull/13193) + - Removed ZoomButtonsController support [#13198](https://github.com/mapbox/mapbox-gl-native/pull/13198) + - Changed CustomGeometrySource() signature to be Kotlin friendly [#13178](https://github.com/mapbox/mapbox-gl-native/pull/13178) + - Removed ILatLng and IProjectedMeteres [#13176](https://github.com/mapbox/mapbox-gl-native/pull/13176) + - Option to consume map clicks, consuming location clicks [#13205](https://github.com/mapbox/mapbox-gl-native/pull/13205) + - Consolidated OfflineRegionDefinitions [#13180](https://github.com/mapbox/mapbox-gl-native/pull/13180) + - Added scrollBy() to MapboxMap, depricated CameraUpdate.scrollBy() [#13223](https://github.com/mapbox/mapbox-gl-native/pull/13223) + - Improved CustomGeometrySource constructor typing [#13200](https://github.com/mapbox/mapbox-gl-native/pull/13200) + - Removed deprecated MarkerView[#13194](https://github.com/mapbox/mapbox-gl-native/pull/13194) + - Annotate onMapReady with @NonNull [#13307](https://github.com/mapbox/mapbox-gl-native/pull/13307) + +## 6.6.7 - November 8, 2018 + - Telemetry v3.5.4 [#13330](https://github.com/mapbox/mapbox-gl-native/pull/13330) + +## 6.6.6 - November 8, 2018 + - This release should be skipped in favor of the `v6.6.7`. + +## 6.7.0 - November 7, 2018 + - Handle null getMapAsync invocations, deliver onMapReady only once [#13301](https://github.com/mapbox/mapbox-gl-native/pull/13301) + - Verify if `text-field` is not null before performing compatibility operations [#13294](https://github.com/mapbox/mapbox-gl-native/pull/13294) + - Log Java exception and fail silently instead of throwing a native exception in the map state callbacks[#13294](https://github.com/mapbox/mapbox-gl-native/pull/13294) + - Reintroduce OnMapChange invocation [#13289](https://github.com/mapbox/mapbox-gl-native/pull/13289) + - Null-check nativeMapView in case it's destroyed [#13281](https://github.com/mapbox/mapbox-gl-native/pull/13281) + +## 6.6.5 - November 2, 2018 + - Telemetry v3.5.2 [#13258](https://github.com/mapbox/mapbox-gl-native/pull/13258) + +## 6.6.4 - November 1, 2018 + - Fix crash with non AppCompatActivities [#13222](https://github.com/mapbox/mapbox-gl-native/pull/13222) + - Telemetry bump 3.5.1 [#13204](https://github.com/mapbox/mapbox-gl-native/pull/13204) + - Gestures library 0.3.0 [#13234](https://github.com/mapbox/mapbox-gl-native/pull/13234) + +## 6.7.0-beta.1 - October 31, 2018 + - Remove map initialised check [#13224](https://github.com/mapbox/mapbox-gl-native/pull/13224) + - Upgrade GeoJSONVT to v6.6.2 [#13231](https://github.com/mapbox/mapbox-gl-native/pull/13231) + - Deliver OnMapReady at end of initialisation block [#13220](https://github.com/mapbox/mapbox-gl-native/pull/13220) + - Rework MapCallback to execute in correct order [#13203](https://github.com/mapbox/mapbox-gl-native/pull/13203) + - Deprecate map zoom button controller [#13197](https://github.com/mapbox/mapbox-gl-native/pull/13197) + - RenderState API [#13170](https://github.com/mapbox/mapbox-gl-native/pull/13170) + - Avoid wrapping longitude values at dateline [#13006](https://github.com/mapbox/mapbox-gl-native/pull/13006) + +## 6.7.0-alpha.2 - October 24, 2018 + - Format expression support [#12985](https://github.com/mapbox/mapbox-gl-native/pull/12985) + - Remove view tree observer [#13133](https://github.com/mapbox/mapbox-gl-native/pull/13133) + - Revert infer nullity [#13147](https://github.com/mapbox/mapbox-gl-native/pull/13147) + - Add priorities to requests [#13019](https://github.com/mapbox/mapbox-gl-native/pull/13019) + - Avoid using and [#13135](https://github.com/mapbox/mapbox-gl-native/pull/13135) + - Introduce mgbl::RenderState [#13123](https://github.com/mapbox/mapbox-gl-native/pull/13123) + - Ensure queryRenderedFeatures accounts for icon-rotate [#13105](https://github.com/mapbox/mapbox-gl-native/pull/13105) + - Add 'putResourceForURL' for pre-warming ambient cache [#13119](https://github.com/mapbox/mapbox-gl-native/pull/13119) + +## 6.6.2/6.6.3 - October 24, 2018 + - Remove requirement on vectorDrawables.useSupportLibrary [#13168](https://github.com/mapbox/mapbox-gl-native/pull/13168) + - File source deactivate called before callbacks [#13146](https://github.com/mapbox/mapbox-gl-native/pull/13168) + +## 6.7.0-alpha.1 - October 17, 2018 + - Core format expression integration [#12624](https://github.com/mapbox/mapbox-gl-native/pull/12624) + - Remove obsolete catch block in getLayerAs [#13091](https://github.com/mapbox/mapbox-gl-native/pull/13091) + - Include Mapbox SDK Services proguard configuration [#13103](https://github.com/mapbox/mapbox-gl-native/pull/13103) + - Avoid printing exception for valid code path when loading FileSource [#13102](https://github.com/mapbox/mapbox-gl-native/pull/13102) + - Add equals, hashcode and toString to camera update types [#13089](https://github.com/mapbox/mapbox-gl-native/pull/13089) + - Infer nullity, optimise codebase for consumption by kotlin [#13071](https://github.com/mapbox/mapbox-gl-native/pull/13071) + - Replace OnMapchange with specific callbacks [#13050](https://github.com/mapbox/mapbox-gl-native/pull/13050) + - Offline region creation telemetry event [#12544](https://github.com/mapbox/mapbox-gl-native/pull/12544) + +## 6.6.1 - October 17, 2018 + - Use appcompat resource configuration for vector drawables [#13114](https://github.com/mapbox/mapbox-gl-native/pull/13114) + - Reverse order of prioritising shape vs marker click handling [#13059](https://github.com/mapbox/mapbox-gl-native/pull/13059) + +## 6.6.0 - October 11, 2018 + - Fixed an issue where fill and line layers would occasionally flicker on zoom [#12982](https://github.com/mapbox/mapbox-gl-native/pull/12982) + +## 6.6.0-beta.1 - October 3, 2018 + - Add configuration to change the animation duration multiplier when tracking location [#13011](https://github.com/mapbox/mapbox-gl-native/pull/13011) + - Move camera and puck immediately when starting to track and displacement is big [#13013](https://github.com/mapbox/mapbox-gl-native/pull/13013) + +## 6.6.0-alpha.2 - September 26, 2018 + - Expose offline database merge API [#12860](https://github.com/mapbox/mapbox-gl-native/pull/12860) + - Remove unnecessary camera callbacks loops [#12973](https://github.com/mapbox/mapbox-gl-native/pull/12973) + - Fix an issue where `OnCameraMoveListener#onCameraMove` would not get invoked while using `LocationComponent` [#12932](https://github.com/mapbox/mapbox-gl-native/pull/12932) + - Try not to re-draw tiles when coming back from background [#12844](https://github.com/mapbox/mapbox-gl-native/pull/12844) + - Proguard config revision [#12929](https://github.com/mapbox/mapbox-gl-native/pull/12929) + - Improve compatibility of offline packs between devices [#12933](https://github.com/mapbox/mapbox-gl-native/pull/12933) + - Update telemetry dependency to 3.2.1 [#12974](https://github.com/mapbox/mapbox-gl-native/pull/12974) + - Fix an issue where some tiles weren't rendered correctly when no internet connectivity was available [#12931](https://github.com/mapbox/mapbox-gl-native/pull/12931) + +## 6.6.0-alpha.1 - September 19, 2018 + - Merge LocationLayerPlugin to the Maps SDK [#12786](https://github.com/mapbox/mapbox-gl-native/pull/12786) + - Add `symbol-z-order` symbol layout property to style spec [#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783) + - Add "crossSourceCollisions" map option [#12842](https://github.com/mapbox/mapbox-gl-native/pull/12842) + - "is-supported-script" expression support [#12845](https://github.com/mapbox/mapbox-gl-native/pull/12845) + - Update isEmulator check [#12832](https://github.com/mapbox/mapbox-gl-native/pull/12832) + - Prevent crash when expression evaluates to default, no pattern [#12896](https://github.com/mapbox/mapbox-gl-native/pull/12896) + - Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) [#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864) + - Update proguard config to not warn about AutoValue [#12920](https://github.com/mapbox/mapbox-gl-native/pull/12920) + - Remove nunicode from android binding [#12497](https://github.com/mapbox/mapbox-gl-native/pull/12497) + - Correct LatLngBounds exception message [#12816](https://github.com/mapbox/mapbox-gl-native/pull/12816) + +## 6.5.0 - September 11, 2018 + - Fixed a cubic-bezier interpolation bug. [#12812](https://github.com/mapbox/mapbox-gl-native/issues/12812) + - Fixed an issue that could cause "allow-overlap" symbols to fade in during pan operations instead of always showing. [#12683](https://github.com/mapbox/mapbox-gl-native/issues/12683) + +## 6.5.0-beta.1 - September 5, 2018 + - Retain shared thread pool reference [#12811](https://github.com/mapbox/mapbox-gl-native/pull/12811) + - MapStrictMode configuration [#12817](https://github.com/mapbox/mapbox-gl-native/pull/12817) + - Provide correct expression integration for newly created properties [#12809](https://github.com/mapbox/mapbox-gl-native/pull/12809) + - Get source id for supported layer types [#12801](https://github.com/mapbox/mapbox-gl-native/pull/12801) + - Check if map is destroyed before saving state in a fragment [#12804](https://github.com/mapbox/mapbox-gl-native/pull/12804) + - Bump leak canary to 1.6.1 [#12767](https://github.com/mapbox/mapbox-gl-native/pull/12767) + - Add quotes to string representation of string literal [#12768](https://github.com/mapbox/mapbox-gl-native/pull/12768) + - Make improve this map translatable [#12785](https://github.com/mapbox/mapbox-gl-native/pull/12785) + - Add Keep annotation to abstract components [#12796](https://github.com/mapbox/mapbox-gl-native/pull/12796) + - Gradle tools 3.1.4 [#12795](https://github.com/mapbox/mapbox-gl-native/pull/12795) + - Explicitly remove local references [#12774](https://github.com/mapbox/mapbox-gl-native/pull/12774) + - Add more languages to tx config file [#12719](https://github.com/mapbox/mapbox-gl-native/pull/12719) + - Add support for feature expressions in `line-pattern`, `fill-pattern`, and `fill-extrusion-pattern` properties. [#12284](https://github.com/mapbox/mapbox-gl-native/pull/12284) + +## 6.5.0-alpha.2 - August 29, 2018 + - Keep arbitrary region fields and constructor of OfflineGeometryRegionDefinition while obfuscating [#12734](https://github.com/mapbox/mapbox-gl-native/pull/12734) + - Modularise the SDK [#12468](https://github.com/mapbox/mapbox-gl-native/pull/12468) + - Invalidate InfoWindow's y offset when content is set [#12715](https://github.com/mapbox/mapbox-gl-native/pull/12715) + - Synchronize and coalesce requests targeting the same TileID in the CustomGeometrySource [#12509](https://github.com/mapbox/mapbox-gl-native/pull/12509) + - Line gradient support [#12575](https://github.com/mapbox/mapbox-gl-native/pull/12575) + +## 6.5.0-alpha.1 - August 22, 2018 + - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) + - Fix symbol querying for markers near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) + - Hide peer constructors [#12639](https://github.com/mapbox/mapbox-gl-native/pull/12639) + - Shutting down thread pool of the CustomGeometrySource when the source is destroyed [#12517](https://github.com/mapbox/mapbox-gl-native/pull/12517) + - Harden offline database [#12224](https://github.com/mapbox/mapbox-gl-native/pull/12224) + - Obtain paths to file directories on a worker thread [#12657](https://github.com/mapbox/mapbox-gl-native/pull/12657) + - Arbitrary offline region shapes [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) + - Make AndroidRendererFrontend to request render once per event loop [#12586](https://github.com/mapbox/mapbox-gl-native/issues/12586) + - Converting GeoJsonSource features asynchronously [#12580](https://github.com/mapbox/mapbox-gl-native/pull/12580) + - StyleJson configuration on MapboxMapOptions [#12664](https://github.com/mapbox/mapbox-gl-native/pull/12664) + - Update MapInitializer for OfflineRegionDefinition [#12686](https://github.com/mapbox/mapbox-gl-native/pull/12686) + - Offline symbol render example using AssetFileSource [#12676](https://github.com/mapbox/mapbox-gl-native/pull/12676) + - Added Chinese translations [#12696](https://github.com/mapbox/mapbox-gl-native/pull/12696) + - Collator and resolved-locale expressions [#12688](https://github.com/mapbox/mapbox-gl-native/pull/12688) + - Update telemetry user-agent [#12706](https://github.com/mapbox/mapbox-gl-native/pull/12706) + - Replace hardcoded telemetry settings string with resources [#12707](https://github.com/mapbox/mapbox-gl-native/pull/12707) + - Update GeoJsonOptions javadoc [#12709](https://github.com/mapbox/mapbox-gl-native/pull/12709) + +## 6.4.0 - August 15, 2018 + - Use unconverted bearing value for LatLngBounds calculation [#12616](https://github.com/mapbox/mapbox-gl-native/pull/12616) + - Store release so files with debugging information [#12628](https://github.com/mapbox/mapbox-gl-native/pull/12628) + - Close a security vulnerability introduced in v6.2.0 that would potentially allow the owner of a style to compromise apps loading that style. + +## 6.4.0-beta.1 - August 9, 2018 + - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) + - Enable LTO in release builds [#12546](https://github.com/mapbox/mapbox-gl-native/pull/12546) + - Update Java Services to v3.4.0 [#12564](https://github.com/mapbox/mapbox-gl-native/pull/12564) + - Telemetry bump to 3.1.5 [#12589](https://github.com/mapbox/mapbox-gl-native/pull/12589) + +## 6.4.0-alpha.2 - August 1, 2018 + - Compress shader source code [#12477](https://github.com/mapbox/mapbox-gl-native/pull/12477) + - Add minimal touch target to marker click detection [#12482](https://github.com/mapbox/mapbox-gl-native/pull/12482) + - Improve resulting APK size by using @Keep annotation [#12490](https://github.com/mapbox/mapbox-gl-native/pull/12490) + - Reuse Bitmap, Paint & Canvas instances in LocalGlyphRasterizer [#12488](https://github.com/mapbox/mapbox-gl-native/pull/12488) + - Remove black surface during map start up [#12377](https://github.com/mapbox/mapbox-gl-native/pull/12377) + - Corrected VisibleRegion on rotated map [#12255](https://github.com/mapbox/mapbox-gl-native/pull/12255) + - Tweak conversions to reduce binary size [#12511](https://github.com/mapbox/mapbox-gl-native/pull/12511) + +## 6.4.0-alpha.1 - July 25, 2018 + - Validate if gesture detector is able to handle gesture [#12375](https://github.com/mapbox/mapbox-gl-native/pull/12375) + - Add a convenience method to check whether the map is in a destroyed state, MapView#isDestroyed [#12373](https://github.com/mapbox/mapbox-gl-native/pull/12373) + - Add GeoJSON regression tests for java method look up from JNI [#12354](https://github.com/mapbox/mapbox-gl-native/pull/12354) + - Bump kotlin, timber and okhttp dependencies [#12393](https://github.com/mapbox/mapbox-gl-native/pull/12393) + - Harden map events creation [#12405](https://github.com/mapbox/mapbox-gl-native/pull/12405) + - Fix possibly race on undefined behavior [#12408](https://github.com/mapbox/mapbox-gl-native/pull/12408) + - Option to request the visible region restricted by the content padding [#12407](https://github.com/mapbox/mapbox-gl-native/pull/12407) + - Expose getMap [#12444](https://github.com/mapbox/mapbox-gl-native/pull/12444) + - Correct access token validation [#12458](https://github.com/mapbox/mapbox-gl-native/pull/12458) + - Port `symbol-placement: line-center` to native [#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337) + - Token string syntax (`"{token}"`) in `SymbolLayer` `textField` and `iconImage` property values is now correctly converted to the appropriate expression equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) + - Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) + +## 6.3.0 - July 18, 2018 + - Harden map events creation [#12406](https://github.com/mapbox/mapbox-gl-native/pull/12406) + +## 6.3.0-beta.1 - July 11, 2018 + - Fix JNI lookup of FeatureCollection, add regression test [#12344](https://github.com/mapbox/mapbox-gl-native/pull/12344) + - Added draggable marker example activity, add kotlin support to test app [@12326](https://github.com/mapbox/mapbox-gl-native/pull/12326) + - Telemetry bump to v3.1.4 [#12349](https://github.com/mapbox/mapbox-gl-native/pull/12349) + - Remove unnecessary memory use when collision debug mode is not enabled ([#12294](https://github.com/mapbox/mapbox-gl-native/issues/12294)) + +## 6.3.0-alpha.2 - July 5, 2018 + - Add LatLngForScreenCoordinate to MapSnapshotter API, This allows to convert a LatLng value to the x,y position on the MapSnasphot image [#12221](https://github.com/mapbox/mapbox-gl-native/pull/12221) + - Expose multiple getCameraFor equivalent methods to convert a geometry or a bounds to a camera position with taking in account padding, tilt and bearing [#12290](https://github.com/mapbox/mapbox-gl-native/pull/12290) + - Avoid race condition when calling getMapAsync from a non-UI thread when running instrumentation tests [#12308](https://github.com/mapbox/mapbox-gl-native/pull/12308) + +## 6.2.1 - June 27, 2018 + - Backport range alpha values from 0 to 1 with int color conversion [#12235](https://github.com/mapbox/mapbox-gl-native/pull/12235) + +## 6.3.0-alpha.1 - June 27, 2018 + - Range alpha values from 0 to 1 with int color conversion [#12210](https://github.com/mapbox/mapbox-gl-native/pull/12210) + - Remove reflection lookup for MarkerViewAdapter intialisation [#12218](https://github.com/mapbox/mapbox-gl-native/pull/12218) + - GeoJSON clustering expressions logic change [#12211](https://github.com/mapbox/mapbox-gl-native/pull/12211) + - Add SDF support, allow template images to be tinted [#12181](https://github.com/mapbox/mapbox-gl-native/pull/12181) + - Add android licenses tool, update licenses [#12153](https://github.com/mapbox/mapbox-gl-native/pull/12153) + +## 6.2.0 - June 20, 2018 + - Remove support for Fabric [#12126](https://github.com/mapbox/mapbox-gl-native/pull/12126) + - Dispatch camera start callback only when actually moving [#12172](https://github.com/mapbox/mapbox-gl-native/pull/12172) + +## 6.2.0-beta.3 - June 15, 2018 + - Always commit symbol placement [#12076](https://github.com/mapbox/mapbox-gl-native/pull/12076) + - Ceil map dimensions [#12116](https://github.com/mapbox/mapbox-gl-native/pull/12116) + - Fix match stop conversion [#12128](https://github.com/mapbox/mapbox-gl-native/pull/12128) + - Telemetry bump to v3.1.3 [#12156](https://github.com/mapbox/mapbox-gl-native/pull/12156) + +## 6.2.0-beta.2 - June 7, 2018 + - Ensure that camera is invalidated before generating telemetry event [#12042](https://github.com/mapbox/mapbox-gl-native/pull/12042) + - Offline download batches [#11284](https://github.com/mapbox/mapbox-gl-native/pull/11284) + - Parse Fragment's xml attributes [#12078](https://github.com/mapbox/mapbox-gl-native/pull/12078) + +## 6.2.0-beta.1 - May 31, 2018 + - Bump mapbox-java to 3.2.0 [#12036](https://github.com/mapbox/mapbox-gl-native/pull/12036) + - Optional camera position for map snapshotter [#12028](https://github.com/mapbox/mapbox-gl-native/pull/12029) + - Expose enableOnUserRequest and disableOnUserRequest on Telemetry [#12024](https://github.com/mapbox/mapbox-gl-native/pull/12024) + - Add style json setter/getter to map snapshotter [#12031](https://github.com/mapbox/mapbox-gl-native/pull/12031) + - Fix literal wrapping in comparison expressions [#12022](https://github.com/mapbox/mapbox-gl-native/pull/12022) + - Null check access token in filesource initializer [#12023](https://github.com/mapbox/mapbox-gl-native/pull/12023) + - Allow literal expression property arguments [#12018](https://github.com/mapbox/mapbox-gl-native/pull/12018) + - Raw expression support [#12007](https://github.com/mapbox/mapbox-gl-native/pull/12007) + +## 6.2.0-alpha.2 - May 25, 2018 + - UI Thread checking [#12000](https://github.com/mapbox/mapbox-gl-native/pull/12000) + - Don't force having an Mapbox access token [#12001](https://github.com/mapbox/mapbox-gl-native/pull/12001) + - Unknown tokens in URLs are now preserved, rather than replaced with an empty string [#11787](https://github.com/mapbox/mapbox-gl-native/issues/11787) + - Update onMapChange Listener javadoc [#11972](https://github.com/mapbox/mapbox-gl-native/pull/11972) + - Set Tile loaded/rendered instead of marking tile as optional [#11985](https://github.com/mapbox/mapbox-gl-native/pull/11985) + - Wrap glGetString in `MBGL_CHECK_ERROR` too [#11106](https://github.com/mapbox/mapbox-gl-native/pull/11106) + - Accept constant expression in non-dds properties [#11960](https://github.com/mapbox/mapbox-gl-native/pull/11960) + - Style JSON configuration in Snapshotter [#11976](https://github.com/mapbox/mapbox-gl-native/pull/11976) + - Remove mips and armeabi as supported ABI, update to NDK 17 [#11458](https://github.com/mapbox/mapbox-gl-native/pull/11458) + - Re-assign ids when lng jumps to avoid flicker [#11938](https://github.com/mapbox/mapbox-gl-native/pull/11938) + - Change modifier MapView#initialize to allow subclassing [#11969](https://github.com/mapbox/mapbox-gl-native/pull/11969) + - Avoid symbol flickering when longitude is wrapped [#11938](https://github.com/mapbox/mapbox-gl-native/pull/11938) + - Fix hang when parsing very large angles for hue in hsl colors [#11968](https://github.com/mapbox/mapbox-gl-native/pull/11968) + - Clamp TileJSON.bounds latitudes to [-90, 90] [#11964](https://github.com/mapbox/mapbox-gl-native/pull/11964) + - Align URL token replacement with GL-JS [#11953](https://github.com/mapbox/mapbox-gl-native/pull/11953) + - Align match behaviour [#11935](https://github.com/mapbox/mapbox-gl-native/pull/11935) + +## 6.1.3 - May 23, 2018 + - Circle querying fixes [#11571](https://github.com/mapbox/mapbox-gl-native/pull/11571) + - Global symbol query [#11742](https://github.com/mapbox/mapbox-gl-native/pull/11742) + - Change MapView#initialize modifier to allow overriding [#11969](https://github.com/mapbox/mapbox-gl-native/pull/11969) + - Update telemetry to 3.1.2 [#11987](https://github.com/mapbox/mapbox-gl-native/pull/11987) + +## 6.1.2 - May 18, 2018 + - Update telemetry to 3.1.1 [#11942](https://github.com/mapbox/mapbox-gl-native/pull/11942) + +## 6.2.0-alpha.1 - May 17, 2018 + - `"to-string"` expression operator converts `null` to empty string rather than to `"null"` [#11904](https://github.com/mapbox/mapbox-gl-native/pull/11904) + - Expose MapView#setOfflineRegion [#1922](https://github.com/mapbox/mapbox-gl-native/pull/11922) + - Add nullability annotations to public API for kotlin language integration [#11925](https://github.com/mapbox/mapbox-gl-native/pull/11925) + - Expose MapView created callbacks on MapFragment and SupportMapFragment [#11934](https://github.com/mapbox/mapbox-gl-native/pull/11934) + - Update mapbox-java to 3.1.0 [#11916](https://github.com/mapbox/mapbox-gl-native/pull/11916) + +## 6.1.1 - May 7, 2018 + - Update telemetry to 3.1.0 [#11855](https://github.com/mapbox/mapbox-gl-native/pull/11855) + +## 6.1.0 - May 4, 2018 + - Unwrap LatLngBounds during JNI conversion [#11807](https://github.com/mapbox/mapbox-gl-native/pull/11807) + - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) + - Null-check source before removing [#11789](https://github.com/mapbox/mapbox-gl-native/pull/11789) + - Flutter support: promote pixel-ratio to public API NativeMapView [#11772](https://github.com/mapbox/mapbox-gl-native/pull/11772) + - Unwrap LatLngBounds for the shortest path when requesting camera [#11759](https://github.com/mapbox/mapbox-gl-native/pull/11759) + - Flutter support: integrate view callback abstraction [#11706](https://github.com/mapbox/mapbox-gl-native/pull/11706) + - Match expression doc tweaks [#11691](https://github.com/mapbox/mapbox-gl-native/pull/11691) + - Improve stop javadoc to include interpolate [#11677](https://github.com/mapbox/mapbox-gl-native/pull/11677) + - Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811) + - Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792) + - Add Danish localization; update Hungarian, Russian, Swedish translations [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11136) + +## 5.5.3 - May 4, 2018 + - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800) + +## 6.0.1 - April 17, 2018 + - Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710) + +## 6.0.0 - April 17, 2018 + - Bump telemetry version to 3.0.1 [#11700](https://github.com/mapbox/mapbox-gl-native/pull/11700) + - Update layer when changing its min/max zoom [#11687](https://github.com/mapbox/mapbox-gl-native/pull/11687) + +## 6.0.0-beta.7 - April 12, 2018 + - Add abs, round, floor, ceil expression operators [#11653](https://github.com/mapbox/mapbox-gl-native/pull/11653) + - LatLngBounds correct center calculation [#11650](https://github.com/mapbox/mapbox-gl-native/pull/11650) + - Bump telemetry to 3.0.0 final [#11658](https://github.com/mapbox/mapbox-gl-native/pull/11658) + - Correctly calculate LatLngBounds [#11647](https://github.com/mapbox/mapbox-gl-native/pull/11647) + - Add convenience step expression [#11641](https://github.com/mapbox/mapbox-gl-native/pull/11641) + - Add javadoc examples for Android [#11540](https://github.com/mapbox/mapbox-gl-native/pull/11540) + - Add paused state to map renderer, don't render snapshots after onPause [#11358](https://github.com/mapbox/mapbox-gl-native/pull/11358) + - Rework internal expression conversion [#11490](https://github.com/mapbox/mapbox-gl-native/pull/11490) + - Fixed gesture event listeners javadoc [#11630](https://github.com/mapbox/mapbox-gl-native/pull/11630) + - Add delete local reference on jni strings [#11608](https://github.com/mapbox/mapbox-gl-native/pull/11608) + - Release local references early [#11599](https://github.com/mapbox/mapbox-gl-native/pull/11599) + - Re-bind uniform locations after re-linking program [#11618](https://github.com/mapbox/mapbox-gl-native/pull/11618) + - Bump mapbox-sdk-services to 3.0.1 [#11593](https://github.com/mapbox/mapbox-gl-native/pull/11593) + +## 5.5.2 - April 10, 2018 + - Correct animation scale point [#11643](https://github.com/mapbox/mapbox-gl-native/pull/11643) + - Re-bind uniform locations after re-linking program [#11583](https://github.com/mapbox/mapbox-gl-native/pull/11583) + - Invalidate camera position before delivering onMapReady [#11585](https://github.com/mapbox/mapbox-gl-native/pull/11585) + - Null java peer callback [#11358](https://github.com/mapbox/mapbox-gl-native/pull/11358) + - Add missing delete local reference [#11608](https://github.com/mapbox/mapbox-gl-native/pull/11608) + - Release local refs [#11599](https://github.com/mapbox/mapbox-gl-native/pull/11599) + +## 6.0.0-beta.6 - April 4, 2018 + - Fix race condition crash for heavily modified annotations [#11551](https://github.com/mapbox/mapbox-gl-native/pull/11551) + - Throw exception when converting PropertyValue with an expression [#11572](https://github.com/mapbox/mapbox-gl-native/pull/11572) + - Invalidate camera position before delivering onMapReady [#11585](https://github.com/mapbox/mapbox-gl-native/pull/11585) + - Rework logical condition convenience expressions [#11555](https://github.com/mapbox/mapbox-gl-native/pull/11555) + - Telemetry library version update to 3.0.0-beta.4 [#11590](https://github.com/mapbox/mapbox-gl-native/pull/11590) + +## 6.0.0-beta.5 - March 27, 2018 + - Avoid flashing on pitched overzoomed tiles [#11488](https://github.com/mapbox/mapbox-gl-native/pull/11488) + - Literal array conversion of primitive arrays [#11500](https://github.com/mapbox/mapbox-gl-native/pull/11500) + - Make default output from step more descriptive [#11501](https://github.com/mapbox/mapbox-gl-native/pull/11501) + - Expose public Telemetry API [#11503](https://github.com/mapbox/mapbox-gl-native/pull/11503) + - Convert Android int colors with to-color expression [#11506](https://github.com/mapbox/mapbox-gl-native/pull/11506) + - Prevent default style reload when string style json was set [#11520](https://github.com/mapbox/mapbox-gl-native/pull/11520) + - String, number and bool Expressions with multiple values [#11512](https://github.com/mapbox/mapbox-gl-native/pull/11512) + - Telemetry library 3.0.0-beta.3 [#11534](https://github.com/mapbox/mapbox-gl-native/pull/11534) + - Gestures library v0.2.0 [#11535](https://github.com/mapbox/mapbox-gl-native/pull/11535) + +## 5.5.1 - March 26, 2018 + - Verify optional access of FileSource deactivation [#11480](https://github.com/mapbox/mapbox-gl-native/pull/11480) + - Prevent default style loading when style json was set [#11519](https://github.com/mapbox/mapbox-gl-native/pull/11519) + - Delete local reference when convering Image.java [#11350](https://github.com/mapbox/mapbox-gl-native/pull/11350) + - Use float for pixel ratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) + - Validate if width and height aren't 0 when creating a snapshot [#11364](https://github.com/mapbox/mapbox-gl-native/pull/11364) + - Null check body of http request [#11413](https://github.com/mapbox/mapbox-gl-native/pull/11413) + - Clamp TileJSON bounds [#11425](https://github.com/mapbox/mapbox-gl-native/pull/11425) + +## 6.0.0-beta.4 - March 20, 2018 + - Gesture library 0.1.0 stable [#11483](https://github.com/mapbox/mapbox-gl-native/pull/11483) + - Filters with expressions [#11429](https://github.com/mapbox/mapbox-gl-native/pull/11429) + - Telemetry 3.0.0-beta.2 [#11474](https://github.com/mapbox/mapbox-gl-native/pull/11474) + - High level JNI conversion for geojson [#11471](https://github.com/mapbox/mapbox-gl-native/pull/11471) + - Update to MAS 3.0.0-beta.4 [#11468](https://github.com/mapbox/mapbox-gl-native/pull/11468) + - Support for expression literal on arrays [#11457](https://github.com/mapbox/mapbox-gl-native/pull/11457) + - Fix telemetry integration for two finger tap gesture [#11460](https://github.com/mapbox/mapbox-gl-native/pull/11460) + - Revisit proguard configuration [#11434](https://github.com/mapbox/mapbox-gl-native/pull/11434) + - Expressions accessor support [#11352](https://github.com/mapbox/mapbox-gl-native/pull/11352) + - Calculate camera's LatLng for bounds without map padding [#11410](https://github.com/mapbox/mapbox-gl-native/pull/11410) + - Check for null on http body request [#11413](https://github.com/mapbox/mapbox-gl-native/pull/11413) + - Expose more gesture settings [#11407](https://github.com/mapbox/mapbox-gl-native/pull/11407) + - Revert java 8 language support [#11398](https://github.com/mapbox/mapbox-gl-native/pull/11398) + - Update to MAS 3.0.0-beta.3 [#11373](https://github.com/mapbox/mapbox-gl-native/pull/11373) + - Rework match expression to style specification syntax [#11388](https://github.com/mapbox/mapbox-gl-native/pull/11388) + - Update javadoc configuration for Gradle 4.4 [#11384](https://github.com/mapbox/mapbox-gl-native/pull/11384) + - Rework zoomIn and zoomOut to use ValueAnimators [#11382](https://github.com/mapbox/mapbox-gl-native/pull/11382) + - Delete LocalRef when converting Image.java [#11350](https://github.com/mapbox/mapbox-gl-native/pull/11350) + - Use float for pixelratio when creating a snapshotter [#11367](https://github.com/mapbox/mapbox-gl-native/pull/11367) + - Validate width/height when creating a snapshot [#11364](https://github.com/mapbox/mapbox-gl-native/pull/11364) + +## 6.0.0-beta.3 - March 2, 2018 + - Added missing local reference deletes [#11243](https://github.com/mapbox/mapbox-gl-native/pull/11243), [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Remove obsolete camera api [#11201](https://github.com/mapbox/mapbox-gl-native/pull/11201) + - Fix UTF-8 encoding, add missing package-info.java files [#11261](https://github.com/mapbox/mapbox-gl-native/pull/11261) + - Rework expression api [#11210](https://github.com/mapbox/mapbox-gl-native/pull/11210) + - LatLngBounds fixes [#11333](https://github.com/mapbox/mapbox-gl-native/pull/11333), [#11307](https://github.com/mapbox/mapbox-gl-native/pull/11307), [#11308](https://github.com/mapbox/mapbox-gl-native/pull/11308), [#11309](https://github.com/mapbox/mapbox-gl-native/pull/11309), [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - New gestures library [#11221](https://github.com/mapbox/mapbox-gl-native/pull/11221) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add heatmap color property [#11220](https://github.com/mapbox/mapbox-gl-native/pull/11220) + - Add support for mapzen terrarium raster-dem encoding [#11339](https://github.com/mapbox/mapbox-gl-native/pull/11339) + +## 5.5.0 - March 1, 2018 + - TileJSON Bounds allows values inclusive of world extents [#11178](https://github.com/mapbox/mapbox-gl-native/pull/11178) + - LatLngBounds returned by VisibleRegion when map is rotated [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - Custom Layer fixes & black list VAO on mali t720 [#11239](https://github.com/mapbox/mapbox-gl-native/pull/11239) + - Check if Activity isn't finishing before showing dialog [#11244](https://github.com/mapbox/mapbox-gl-native/pull/11244) + - Decouple MapPadding from overlain views [#11258](https://github.com/mapbox/mapbox-gl-native/pull/11258) + - Don't disable zoom button controller zooming with gesture disabled zoom [#11259](https://github.com/mapbox/mapbox-gl-native/pull/11259) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add missing DeleteLocalRefs [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Continue loading style even if we mutate it [#11294](https://github.com/mapbox/mapbox-gl-native/pull/11294) + - Update telemetry version for OkHttp [#11338](https://github.com/mapbox/mapbox-gl-native/pull/11338) + +## 6.0.0-beta.2 - February 13, 2018 + - Deprecate LocationEngine [#11185](https://github.com/mapbox/mapbox-gl-native/pull/11185) + - Remove LOST from SDK [11186](https://github.com/mapbox/mapbox-gl-native/pull/11186) + - Transparent surface configuration on TextureView [#11065](https://github.com/mapbox/mapbox-gl-native/pull/11065) + - Constrained setLatLng documentation, expose setLatLngZoom method [#11184](https://github.com/mapbox/mapbox-gl-native/pull/11184) + - Integration of new events library [#10999](https://github.com/mapbox/mapbox-gl-native/pull/10999) + - AddImage performance improvement [#11111](https://github.com/mapbox/mapbox-gl-native/pull/11111) + - Migrate MAS to 3.0.0, refactor GeoJson integration [#11149](https://github.com/mapbox/mapbox-gl-native/pull/11149) + - Remove @jar and @aar dependency suffixes [#11161](https://github.com/mapbox/mapbox-gl-native/pull/11161) + +## 5.4.1 - February 9, 2018 + - Don't recreate TextureView surface as part of view resizing, solves OOM crashes [#11148](https://github.com/mapbox/mapbox-gl-native/pull/11148) + - Don't invoke OnLowMemory before map is ready, solves startup crash on low memory devices [#11109](https://github.com/mapbox/mapbox-gl-native/pull/11109) + - Programmatically create GLSurfaceView, solves fragment bug [#11124](https://github.com/mapbox/mapbox-gl-native/pull/11124) + - Proguard config for optional location provider, solves obfuscation warnings [#11127](https://github.com/mapbox/mapbox-gl-native/pull/11127) + - MapView weak reference in global layout listener, solves memory leak [#11128](https://github.com/mapbox/mapbox-gl-native/pull/11128) + +## 5.4.0 - January 30, 2018 + - Blacklist Adreno 2xx GPU for VAO support [#11047](https://github.com/mapbox/mapbox-gl-native/pull/11047) + - Bearing tracking mode GPS_NORTH_FACING [#11095](https://github.com/mapbox/mapbox-gl-native/pull/11095) + - Disable logging for missing location permissions when location is disabled [#11084](https://github.com/mapbox/mapbox-gl-native/pull/11084) + - Create offline handler using the main thread looper [#11021](https://github.com/mapbox/mapbox-gl-native/pull/11021) + +## 6.0.0-beta.1 - January 26, 2018 + - Binding integration for expressions [#10654](https://github.com/mapbox/mapbox-gl-native/pull/10654) + - CustomGeometrySource [#9983](https://github.com/mapbox/mapbox-gl-native/pull/9983) + - HillshadeLayer and RasterDemSource [#11031](https://github.com/mapbox/mapbox-gl-native/pull/11031) + - Revisit marker placement for snapshot [#11029](https://github.com/mapbox/mapbox-gl-native/pull/11029) + - SafeVarargs annotation for expressions [#11027](https://github.com/mapbox/mapbox-gl-native/pull/11027) + - Expression#toString [#11024](https://github.com/mapbox/mapbox-gl-native/pull/11024) + - Rename initRenderSurface to onSurfaceCreated [#11023](https://github.com/mapbox/mapbox-gl-native/pull/11023) + - Expose attribution manager as public API [#10942](https://github.com/mapbox/mapbox-gl-native/pull/10942) + - Replace Mapzen vector source example with Mapillary [#10931](https://github.com/mapbox/mapbox-gl-native/pull/10931) + - Add Hebrew localization [#10967](https://github.com/mapbox/mapbox-gl-native/pull/10967) + - Cleanup gradle configuration files [#10903](https://github.com/mapbox/mapbox-gl-native/pull/10903) + - Send double tap event only once [#10855](https://github.com/mapbox/mapbox-gl-native/pull/10855) + - Parameter validation for LatLngBounds#from [#10831](https://github.com/mapbox/mapbox-gl-native/pull/10831) + - Replace JSON parsing [#10815](https://github.com/mapbox/mapbox-gl-native/pull/10815) + - Orientation change regression test [#10814](https://github.com/mapbox/mapbox-gl-native/pull/10814) + - Max & min LatLng constants [#10780](https://github.com/mapbox/mapbox-gl-native/pull/10780) + - LatLng#wrap return new instance of LatLng [#10769](https://github.com/mapbox/mapbox-gl-native/pull/10769) + - Custom library loader [#10733](https://github.com/mapbox/mapbox-gl-native/pull/10733) + - Inconsistent parameters for LatLngBounds.union [#10728](https://github.com/mapbox/mapbox-gl-native/pull/10728) + - Gradle 4.1 / AS 3.0 [#10549](https://github.com/mapbox/mapbox-gl-native/pull/10549) + +## 5.3.2 - January 22, 2018 + - Validate surface creation before destroying [#10890](https://github.com/mapbox/mapbox-gl-native/pull/10890) + - Add filesource activation ot OfflineRegion [#10904](https://github.com/mapbox/mapbox-gl-native/pull/10904) + - Save configuration of UiSettings [#10908](https://github.com/mapbox/mapbox-gl-native/pull/10908) + - Do not overwrite user-set focal point [#10910](https://github.com/mapbox/mapbox-gl-native/pull/10910) + - Camera callbacks for velocity animated movements [#10925](https://github.com/mapbox/mapbox-gl-native/pull/10925) + - Allow changing the used OkHttpClient [#10948](https://github.com/mapbox/mapbox-gl-native/pull/10948) + - Validate zoom level before creating telemetry event [#10959](https://github.com/mapbox/mapbox-gl-native/pull/10959) + - Handle null call instances in HttpRequest [#10987](https://github.com/mapbox/mapbox-gl-native/pull/10987) + +## 5.3.1 - January 10, 2018 + - Blacklist binary program loading for Vivante GC4000 GPUs [#10862](https://github.com/mapbox/mapbox-gl-native/pull/10862) + - Support Genymotion [#10841](https://github.com/mapbox/mapbox-gl-native/pull/10841) + - Getting bitmap from drawable fix [#10763](https://github.com/mapbox/mapbox-gl-native/pull/10763) + - Use US locale when converting between int color and RGBA string [#10810](https://github.com/mapbox/mapbox-gl-native/pull/10810) + - Harden map destruction [#10811](https://github.com/mapbox/mapbox-gl-native/pull/10811) + - RTL support [#10828](https://github.com/mapbox/mapbox-gl-native/pull/10828) + - Allow configuring Http url logging when a request fails [#10830](https://github.com/mapbox/mapbox-gl-native/pull/10830) + - Don't send double tap event multiple times for telemetry [#10854](https://github.com/mapbox/mapbox-gl-native/pull/10854) + - Fix code generation [#10856](https://github.com/mapbox/mapbox-gl-native/pull/10856) + - Use the correct cancelable callback after posting cancel [#10871](https://github.com/mapbox/mapbox-gl-native/pull/10871) + +## 5.3.0 - December 20, 2017 + - Add support for TinySDF [#10706](https://github.com/mapbox/mapbox-gl-native/pull/10706) + - Save restore MyLocationViewSettings [#10746](https://github.com/mapbox/mapbox-gl-native/pull/10746) + - Post animation callback invocation [#10664](https://github.com/mapbox/mapbox-gl-native/pull/10664) + - Allow configuring Http logging [#10681](https://github.com/mapbox/mapbox-gl-native/pull/10681) + - Fix reverse scale gesture [#10688](https://github.com/mapbox/mapbox-gl-native/pull/10688) + - Update offline region metadata documentation [#10693](https://github.com/mapbox/mapbox-gl-native/pull/10693) + - Post camera listener invocation [#10690](https://github.com/mapbox/mapbox-gl-native/pull/10690) + - Activate filesource for offline region creation [#10718](https://github.com/mapbox/mapbox-gl-native/pull/10718) + - Update Spanish/Vietnamese translations [#10740](https://github.com/mapbox/mapbox-gl-native/pull/10740) + - Update instrumented make target [#10724](https://github.com/mapbox/mapbox-gl-native/pull/10724) + - Remove black flash on start for fragments [#10717](https://github.com/mapbox/mapbox-gl-native/pull/10717) + - CompassView decode crash [#10717](https://github.com/mapbox/mapbox-gl-native/pull/10717) + - Android SDK renaming [#10609](https://github.com/mapbox/mapbox-gl-native/pull/10609) + - Map touch listener based lists [#10749](https://github.com/mapbox/mapbox-gl-native/pull/10749) + +## 5.2.1 - December 6, 2017 + - Close race condition in RunLoop [#10537](https://github.com/mapbox/mapbox-gl-native/pull/10537) + - OkHttp 3.9.1 [#10515](https://github.com/mapbox/mapbox-gl-native/pull/10515) + - Attribution anchor point fix [#10558](https://github.com/mapbox/mapbox-gl-native/pull/10558) + - Pre API 19 VerifyError [#10579](https://github.com/mapbox/mapbox-gl-native/pull/10579) + - Set larger Http request limit [#10567](https://github.com/mapbox/mapbox-gl-native/pull/10567) + - Remove jar generation from maven publish [#10625](https://github.com/mapbox/mapbox-gl-native/pull/10625) + - Enable Map Rendering when paused for multiple window support [#10509](https://github.com/mapbox/mapbox-gl-native/pull/10509) + - Activate FileSource when listing offline regions [#10531](https://github.com/mapbox/mapbox-gl-native/pull/10531) + - Harden MarkerView integration by checking for null bitmap [#10532](https://github.com/mapbox/mapbox-gl-native/pull/10532) + - Use concurrent lists for camera change listeners [#10542](https://github.com/mapbox/mapbox-gl-native/pull/10542) + - Handle destroy activity as part of theme switching [#10589](https://github.com/mapbox/mapbox-gl-native/pull/10589) + - add FileSource activation/deactivation to MapSnapshotter [#10556](https://github.com/mapbox/mapbox-gl-native/pull/10556) + +## 5.2.0 - November 17, 2017 + +- Monkey crashes [#10472](https://github.com/mapbox/mapbox-gl-native/pull/10472) + +## 5.2.0-beta.5 - November 14, 2017 + +- MapSnapshot attribution [#10362](https://github.com/mapbox/mapbox-gl-native/pull/10362) +- Downgrade min sdk to 14 [#10355](https://github.com/mapbox/mapbox-gl-native/pull/10355) +- Harden deselection mechanism for markers [#10403](https://github.com/mapbox/mapbox-gl-native/pull/10403) +- Cherry picks to agua [#10442](https://github.com/mapbox/mapbox-gl-native/pull/10442) +- Rework test activity gen script setup [#10365](https://github.com/mapbox/mapbox-gl-native/pull/10365) +- Fix broken android unit tests, update test make target to SDK [#10387](https://github.com/mapbox/mapbox-gl-native/pull/10387) +- Check for null value when calling mapboxMap.clear [#10388](https://github.com/mapbox/mapbox-gl-native/pull/10388) + +## 5.2.0-beta.4 - November 3, 2017 + +- Revert adding mapbox-android-core dependency (#10354) [#10380](https://github.com/mapbox/mapbox-gl-native/pull/10380) +- Asynchronous TextureView [#10370](https://github.com/mapbox/mapbox-gl-native/pull/10370) +- Workaround OkHttp bug on Android O [10366](https://github.com/mapbox/mapbox-gl-native/pull/10366) +- Revisit logo resize [10553](https://github.com/mapbox/mapbox-gl-native/pull/10353) +- Logo resize for MapSnapshotter [#10312](https://github.com/mapbox/mapbox-gl-native/pull/10312) +- Make location provider optional [#10354](https://github.com/mapbox/mapbox-gl-native/pull/10354) +- Check for positive animation value [#10348](https://github.com/mapbox/mapbox-gl-native/pull/10348) +- Fix IAE of ease/animate [#10338](https://github.com/mapbox/mapbox-gl-native/pull/10338) +- Run full test suite on CI [#10333](https://github.com/mapbox/mapbox-gl-native/pull/10333) +- Make sure camera position gets updated in onFinish() callback after camera.move [#10324](https://github.com/mapbox/mapbox-gl-native/pull/10324) +- throw IAE in animate() and easeCamera() when duration <= 0 [#10321](https://github.com/mapbox/mapbox-gl-native/pull/10321) +- Don't save state if map hasn't been initialised [#10320](https://github.com/mapbox/mapbox-gl-native/pull/10320) +- Make map snapshot optional [#10310](https://github.com/mapbox/mapbox-gl-native/pull/10310) +- Synchronise locationlastions with Transifex [#10309](https://github.com/mapbox/mapbox-gl-native/pull/10309) +- MapboxMap#addImages [#10281](https://github.com/mapbox/mapbox-gl-native/pull/10281) +- Move shape annotation click handling to core [#10267](https://github.com/mapbox/mapbox-gl-native/pull/10267) +- Map snapshotter additions [#10163](https://github.com/mapbox/mapbox-gl-native/pull/10163) +- Add velocity to gestures / port animations to SDK animators [#10202](https://github.com/mapbox/mapbox-gl-native/pull/10202) +- Don't save state if map hasn't been initialised [#10320](https://github.com/mapbox/mapbox-gl-native/pull/10320) +- android.hardware.location.gps feature should not be required [#10347](https://github.com/mapbox/mapbox-gl-native/pull/10347) + +## 5.2.0-beta.3 - October 26, 2017 + +- Reorganize dependencies [#10268](https://github.com/mapbox/mapbox-gl-native/pull/10268) +- Blacklist VAO usage on adreno 3xx [#10291](https://github.com/mapbox/mapbox-gl-native/pull/10291) +- On stop null check [#10259](https://github.com/mapbox/mapbox-gl-native/pull/10259) + +## 5.2.0-beta.2 - October 19, 2017 + +- Wire up MapZoomButtonController with camera change events [#10221](https://github.com/mapbox/mapbox-gl-native/pull/10221) +- Execute callbacks only when not idle [#10220](https://github.com/mapbox/mapbox-gl-native/pull/10220) +- Cleanup unused gradle plugins [#10211](https://github.com/mapbox/mapbox-gl-native/pull/10211) +- add FileSource pause/resume [#9977](https://github.com/mapbox/mapbox-gl-native/pull/9977) +- add make target for ndk-stack [#10185](https://github.com/mapbox/mapbox-gl-native/pull/10185) +- Add interpolator examples [#10067](https://github.com/mapbox/mapbox-gl-native/pull/10067) +- Add an UnsatisfiedLinkError safeguard [#10180](https://github.com/mapbox/mapbox-gl-native/pull/10180) +- Hold off handling hover events untill map has been created [#10142](https://github.com/mapbox/mapbox-gl-native/pull/10142) +- Added `MapboxMap.getCameraForGeometry()` to get a camera with zoom level and center coordinate computed to fit a shape [#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107) +- Fine tune gesture zoom & rotation [#10134](https://github.com/mapbox/mapbox-gl-native/pull/10134) + +## 5.2.0-beta.1 - October 6, 2017 + +- Allow multiple listeners for camera events, deprecate old API [#10141](https://github.com/mapbox/mapbox-gl-native/pull/10141) +- Update symbol layer example with location [#10092](https://github.com/mapbox/mapbox-gl-native/pull/10092) +- Make OfflineTilePyramidRegionDefinition parceable [#10080](https://github.com/mapbox/mapbox-gl-native/pull/10080) +- Fix 5.2.0-SNAPSHOT CI build failing [#10079](https://github.com/mapbox/mapbox-gl-native/pull/10079) +- Deprecate MarkerView [#9782](https://github.com/mapbox/mapbox-gl-native/pull/9782) +- Hide overlain views on initalisation [#10068](https://github.com/mapbox/mapbox-gl-native/pull/10068) +- API for platform side animations [#10001](https://github.com/mapbox/mapbox-gl-native/pull/10001) +- Android asynchronous rendering [#9576](https://github.com/mapbox/mapbox-gl-native/pull/9576) +- Set error handler when starting snapshotter [#10035](https://github.com/mapbox/mapbox-gl-native/pull/10035) +- Hook camera events into compass [#10019](https://github.com/mapbox/mapbox-gl-native/pull/10019) +- Testapp cleanup [#10006](https://github.com/mapbox/mapbox-gl-native/pull/10006) +- Update zoom function example with selected state [#9987](https://github.com/mapbox/mapbox-gl-native/pull/9987) +- Add style inspection to debug activity [#9773](https://github.com/mapbox/mapbox-gl-native/pull/9773) +- Bump external dependencies [#9972](https://github.com/mapbox/mapbox-gl-native/pull/9972) +- Don't recycle bitmap for icon reuse. [#9966](https://github.com/mapbox/mapbox-gl-native/pull/9966) +- Android snapshotter [#9748](https://github.com/mapbox/mapbox-gl-native/pull/9748) +- Revert #9764 [#9851](https://github.com/mapbox/mapbox-gl-native/pull/9851) +- Update docs replacing Bitrise mentions with CircleCI [#9515](https://github.com/mapbox/mapbox-gl-native/pull/9515) +- Style image accessor [#9763](https://github.com/mapbox/mapbox-gl-native/pull/9763) +- Update readme with checkstyle and ndk-stack [#9788](https://github.com/mapbox/mapbox-gl-native/pull/9788) +- make android-check [#9787](https://github.com/mapbox/mapbox-gl-native/pull/9787) +- Deprecate MyLocationView in favor of LocationLayer plugin [#9771](https://github.com/mapbox/mapbox-gl-native/pull/9771) +- Increase firebase timeout for CI testing [#9774](https://github.com/mapbox/mapbox-gl-native/pull/9774) +- Restore max zoom to 25.5 [#9765](https://github.com/mapbox/mapbox-gl-native/pull/9765) +- Update example of camera zoom function on a symbol layer. [#9743](https://github.com/mapbox/mapbox-gl-native/pull/9743) +- Optimise icon management [#9643](https://github.com/mapbox/mapbox-gl-native/pull/9643) +- Expose setStyleJson and getStyleJson [#9714](https://github.com/mapbox/mapbox-gl-native/pull/9714) +- update LatLngBounds activity with BottomSheet interaction [#9736](https://github.com/mapbox/mapbox-gl-native/pull/9736) +- post updating InfoWindow update for InfoWindowAdapter [#9716](https://github.com/mapbox/mapbox-gl-native/pull/9716) +- Annotate MapboxMap class with UiThread [#9712](https://github.com/mapbox/mapbox-gl-native/pull/9712) +- Move ZoomButtonController creation to view initalisation [#9587](https://github.com/mapbox/mapbox-gl-native/pull/9587) +- Solve lint issues, reduce baseline [#9627](https://github.com/mapbox/mapbox-gl-native/pull/9627) +- Remove wear module from project [#9618](https://github.com/mapbox/mapbox-gl-native/pull/9618) +- Add zMediaOverlay configuration + bottom sheet integration [#9592](https://github.com/mapbox/mapbox-gl-native/pull/9592) +- Forward getMapAsync to map for fragment [#9621](https://github.com/mapbox/mapbox-gl-native/pull/9621) +- Make target for dumping system gfx information [#9616](https://github.com/mapbox/mapbox-gl-native/pull/9616) +- Make target documentation [#9617](https://github.com/mapbox/mapbox-gl-native/pull/9617) +- onGlobalLayout hook for map creation [#9607](https://github.com/mapbox/mapbox-gl-native/pull/9607) +- Custom viewpager for horizontal swiping [#9601](https://github.com/mapbox/mapbox-gl-native/pull/9601) +- Disable program caching on Adreno 3xx, 4xx, and 5xx GPUs due to known bugs [#9574](https://github.com/mapbox/mapbox-gl-native/pull/9574) +- Avoid creating InfoWindow iterator if no InfoWindows are shown [#9477](https://github.com/mapbox/mapbox-gl-native/pull/9477) +- Rewire map initialisation [#9462](https://github.com/mapbox/mapbox-gl-native/pull/9462) +- Trying to update non-existent polyline fix [#9544](https://github.com/mapbox/mapbox-gl-native/pull/9544) +- Location accuracy threshold [#9472](https://github.com/mapbox/mapbox-gl-native/pull/9472) +- Rewire gesture handling and telemetry event push [#9494](https://github.com/mapbox/mapbox-gl-native/pull/9494) +- run style instrumentation tests on CI [#9353](https://github.com/mapbox/mapbox-gl-native/pull/9353) +- Fix javadoc comment for public setOfflineMapboxTileCountLimit method [#9454](https://github.com/mapbox/mapbox-gl-native/pull/9454) +- add Map change & visibility test activities [#9425](https://github.com/mapbox/mapbox-gl-native/pull/9425) +- build release package once during ci build [#9351](https://github.com/mapbox/mapbox-gl-native/pull/9351) +- Add support for ImageSource [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110) +- Increased the default maximum zoom level from 20 to 22. [#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835) + +## 5.1.5 - October 31, 2017 + +* Remove obsolete terminate context/display calls [#10162](https://github.com/mapbox/mapbox-gl-native/pull/10162) +* Determine need for clip ID based on actual layers/tiles [#10216](https://github.com/mapbox/mapbox-gl-native/pull/10216) +* Correctly alter sprite URLs [#10217](https://github.com/mapbox/mapbox-gl-native/pull/10217) +* Russian and Ukrainian localizations [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945) + +## 5.1.4 - September 25, 2017 + +* Update translations [#10033](https://github.com/mapbox/mapbox-gl-native/pull/10033) & [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945) +* Continue rendering tiles despite erros [#10012](https://github.com/mapbox/mapbox-gl-native/pull/10012) +* Fix layer z-fighting [#9942](https://github.com/mapbox/mapbox-gl-native/pull/9942) +* Align line vertex to 4-byte boundary [#9943](https://github.com/mapbox/mapbox-gl-native/pull/9943) +* Bump proguard config for OkHttp [#9970](https://github.com/mapbox/mapbox-gl-native/pull/9970) +* Remove database on schema downgrade [#9837](https://github.com/mapbox/mapbox-gl-native/pull/9837) +* Disable rotation gesture when pinch zooming [#10026](https://github.com/mapbox/mapbox-gl-native/pull/10026) +* Do not check if connection is local request [#9968](https://github.com/mapbox/mapbox-gl-native/pull/9968) +* Harden offline region deletion [#9967](https://github.com/mapbox/mapbox-gl-native/pull/9967) +* Clear out mapCallback's OnMapReadyListeners on destroy [#9957](https://github.com/mapbox/mapbox-gl-native/pull/9957) +* Avoid adding duplicate points to bounds [#9955](https://github.com/mapbox/mapbox-gl-native/pull/9955) +* Download is complete fix [#9913](https://github.com/mapbox/mapbox-gl-native/pull/9913) +* MAS 2.2.3 [#9901](https://github.com/mapbox/mapbox-gl-native/pull/9901) +* Russian and Ukrainian localizations [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945) + +## 5.1.3 - August 18, 2017 + +* Use separate attribute component for line normals [#9753](https://github.com/mapbox/mapbox-gl-native/pull/9753) +* Track state of initial overlain views margins [#9391](https://github.com/mapbox/mapbox-gl-native/pull/9391) +* Compability for Samsung devices forcing 3-4 array vector length [#9746](https://github.com/mapbox/mapbox-gl-native/pull/9746) +* Smallest LatLngBounds when visible region crosses dateline [#9747](https://github.com/mapbox/mapbox-gl-native/pull/9747) +* Readd ProjectMeters [#9766](https://github.com/mapbox/mapbox-gl-native/pull/9766) +* Enable location change animation of MyLocationView by default [#9779](https://github.com/mapbox/mapbox-gl-native/pull/9779) +* Avoid IndexOutOfBoundsException when destroying map object [#9789](https://github.com/mapbox/mapbox-gl-native/pull/9789) +* MAS 2.2.1 [#9796](https://github.com/mapbox/mapbox-gl-native/pull/9796) + +## 5.1.2 - August 2, 2017 + +* Disable program caching on Ardreno GPU 3xx, 4xx and 5xx [#9625](https://github.com/mapbox/mapbox-gl-native/pull/9625) +* GeoJSON proguard issue [#9577](https://github.com/mapbox/mapbox-gl-native/pull/9577) +* Harden click events of shape annotations [#9585](https://github.com/mapbox/mapbox-gl-native/pull/9585) +* Validate Marker before opening InfoWindow [#9586](https://github.com/mapbox/mapbox-gl-native/pull/9586) +* Fix added to map check [#9602](https://github.com/mapbox/mapbox-gl-native/pull/9602) +* Don't query shape annotations if none were added [#9606](https://github.com/mapbox/mapbox-gl-native/pull/9606) +* Fix compass direction [#9632](https://github.com/mapbox/mapbox-gl-native/pull/9632) +* Remove preview image integration [#9657](https://github.com/mapbox/mapbox-gl-native/pull/9657) +* Try/catch initialization of telemetry [#9658](https://github.com/mapbox/mapbox-gl-native/pull/9658) +* Fix typo OnCameraMoveStartedListener [#9664](https://github.com/mapbox/mapbox-gl-native/pull/9664) +* Bump MAS dependency to 5.2.0 [#9671](https://github.com/mapbox/mapbox-gl-native/pull/9671) + +## 5.1.1 - July 21, 2017 + +* Rework attribution binding [#9433](https://github.com/mapbox/mapbox-gl-native/pull/9433) +* BackendScope changes [#9538](https://github.com/mapbox/mapbox-gl-native/pull/9538) +* Invisible MarkerView performance fix [#9420](https://github.com/mapbox/mapbox-gl-native/pull/9420) +* Polyline/Polygon click listeners [#9443](https://github.com/mapbox/mapbox-gl-native/pull/9443) +* Hit test Marker/MarkerViews [#9424](https://github.com/mapbox/mapbox-gl-native/pull/9424) +* Fine tune fling gesture [#9532](https://github.com/mapbox/mapbox-gl-native/pull/9532) +* Bump OkHttp 3.8.0, Android 7.x crashes [#9522](https://github.com/mapbox/mapbox-gl-native/pull/9522) +* MyLocationView tint fix [#9410](https://github.com/mapbox/mapbox-gl-native/pull/9410) +* VisibleRegion logic [#9428](https://github.com/mapbox/mapbox-gl-native/pull/9428) +* Validate motion event [#9434](https://github.com/mapbox/mapbox-gl-native/pull/9434) +* Add French localization [#9545](https://github.com/mapbox/mapbox-gl-native/pull/9545) +* Fix public.xml [#9525](https://github.com/mapbox/mapbox-gl-native/pull/9525/files) +* Manage InfoWindow selection in AnnotationManager [#9567](https://github.com/mapbox/mapbox-gl-native/pull/9567) +* Increase touch target size [#9565](https://github.com/mapbox/mapbox-gl-native/pull/9565) +* Work around Adreno 2xx GPU bugs [#9573](https://github.com/mapbox/mapbox-gl-native/pull/9573) + +## 5.1.0 - June 30, 2017 + +* Update to MAS 2.1.3 [#9402](https://github.com/mapbox/mapbox-gl-native/pull/9402) +* Downgrade LOST to v1.1.1 [#9394](https://github.com/mapbox/mapbox-gl-native/pull/9394) +* OnCameraIdle hook into quickzoom gesture [#9339](https://github.com/mapbox/mapbox-gl-native/pull/9339) +* LatLngBounds conversion regression, add test [#9324](https://github.com/mapbox/mapbox-gl-native/pull/9324) + +## 5.1.0-beta.5 - June 21, 2017 + +* Update MAS dependency to 2.1.2 [#9311](https://github.com/mapbox/mapbox-gl-native/pull/9311) +* Update LOST dependency to 3.0.1 [#9302](https://github.com/mapbox/mapbox-gl-native/pull/9302) +* Fix Pulse example Parcelable creator [#9283](https://github.com/mapbox/mapbox-gl-native/pull/9283) +* Custom marker view anchoring [#9282](https://github.com/mapbox/mapbox-gl-native/pull/9282) +* Update Activity test generation [#9276](https://github.com/mapbox/mapbox-gl-native/pull/9276) +* Validate camera position before transforming [#9275](https://github.com/mapbox/mapbox-gl-native/pull/9275) +* Revisit javadoc [#9266](https://github.com/mapbox/mapbox-gl-native/pull/9266) +* Build with NDK 15 [#9263](https://github.com/mapbox/mapbox-gl-native/pull/9263) +* Snapshot with view content [#9263](https://github.com/mapbox/mapbox-gl-native/pull/9263) +* Update source changed javadoc [#9243](https://github.com/mapbox/mapbox-gl-native/pull/9243) +* Run tests on UI-thread [#9198](https://github.com/mapbox/mapbox-gl-native/pull/9198) +* Fix trackball on worker thread [#9305](https://github.com/mapbox/mapbox-gl-native/pull/9305) + +## 5.1.0-beta.4 - June 9, 2017 + +* Option to disable location change animation [#9210](https://github.com/mapbox/mapbox-gl-native/pull/9210) +* Invalidating MyLocationView bearing when not following [#9212](https://github.com/mapbox/mapbox-gl-native/pull/9212) +* Remove upgrade runtime exceptions [#9191](https://github.com/mapbox/mapbox-gl-native/pull/9191) +* Check source usage before removal [#9129](https://github.com/mapbox/mapbox-gl-native/pull/9129) +* Fix tracking mode + camera race condition [#9133](https://github.com/mapbox/mapbox-gl-native/pull/9133) +* Harden orientation changes [#9128](https://github.com/mapbox/mapbox-gl-native/pull/9128) +* Infinite location animation updates [#9194](https://github.com/mapbox/mapbox-gl-native/pull/9194) +* Invoke callback with valid fling gestures [#9192](https://github.com/mapbox/mapbox-gl-native/pull/9192) +* Keep location tracking after screen rotation [#9187](https://github.com/mapbox/mapbox-gl-native/pull/9187) +* Update components with camera values when animating [#9174](https://github.com/mapbox/mapbox-gl-native/pull/9174) +* Validate if gestures should execute [#9173](https://github.com/mapbox/mapbox-gl-native/pull/9173) +* Custom location source and LOST integration [#9142](https://github.com/mapbox/mapbox-gl-native/pull/9142) + +## 5.1.0-beta.3 - May 26, 2017 + +* Add binding support for Light [#9013](https://github.com/mapbox/mapbox-gl-native/pull/9013) +* Update attribution with new Mapbox wordmark [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774) +* LatLngBounds bearing default value [#9102](https://github.com/mapbox/mapbox-gl-native/pull/9102) +* Stop location updates when toggling MyLocationView [#9099](https://github.com/mapbox/mapbox-gl-native/pull/9099) +* Horizontally rotated in snapshot [#9083](https://github.com/mapbox/mapbox-gl-native/pull/9083) +* Disable letter spacing for Arabic text [#9071](https://github.com/mapbox/mapbox-gl-native/pull/9071) +* Correct bearing conversion when animating the map [#9050](https://github.com/mapbox/mapbox-gl-native/pull/9050) +* Don't leak selected markers when removing [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047) +* Bump tools and support lib version [#9046](https://github.com/mapbox/mapbox-gl-native/pull/9046) +* MarkerView deselect events with OnMarkerViewClickListener [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047) +* LOST update to v3.0.0 [#9112](https://github.com/mapbox/mapbox-gl-native/pull/9112) +* Convert dp to pixels for meters per pixel at latitude [#9048](https://github.com/mapbox/mapbox-gl-native/pull/9048) + +## 5.1.0-beta.2 - May 12, 2017 + +5.1.0-beta.2 builds further on 5.1.0-beta.1 and adds: + +* When a layer is added, reload its source's tiles [#8963](https://github.com/mapbox/mapbox-gl-native/pull/8963) +* Update release script to support CircleCI builds [#8950](https://github.com/mapbox/mapbox-gl-native/pull/8950) +* URL getter on Sources [#8959](https://github.com/mapbox/mapbox-gl-native/pull/8959) +* Build SNAPSHOT from release branch CI configuration [#8958](https://github.com/mapbox/mapbox-gl-native/pull/8958) +* Fix UI test filter in Makefile [#8960](https://github.com/mapbox/mapbox-gl-native/pull/8960) +* Bump & fixup dependencies [#8921](https://github.com/mapbox/mapbox-gl-native/pull/8921) +* Ignore already deleted region [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920) +* Keep offline observer when timeout occurs [#8919](https://github.com/mapbox/mapbox-gl-native/pull/8919) +* Show error message when no browser installed [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920) +* Reset observers of removed Sources and Layers [#8900](https://github.com/mapbox/mapbox-gl-native/pull/8900) +* Only build custom layer .so for debug builds [#8885](https://github.com/mapbox/mapbox-gl-native/pull/8885) +* Update localizations [#8883](https://github.com/mapbox/mapbox-gl-native/pull/8883) +* Reset observers of removed Sources and Layers [#8862](https://github.com/mapbox/mapbox-gl-native/pull/8862) +* Remove force style cascade [#8866](https://github.com/mapbox/mapbox-gl-native/pull/8866) +* Update proguard config [#8944](https://github.com/mapbox/mapbox-gl-native/pull/8944) +* Update LOST to 2.3.0-SNAPSHOT [#8872](https://github.com/mapbox/mapbox-gl-native/pull/8872) +* Update logo [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774) +* Camera change listener v2.0 [#8644](https://github.com/mapbox/mapbox-gl-native/pull/8644) +* Allow filesource url transform reset [#8957](https://github.com/mapbox/mapbox-gl-native/pull/8957) + +## 5.1.0-beta.1 - May 2, 2017 + +5.1.0-beta.1 builds further on 5.0.2 and adds: + +* Support for FillExtrusionLayer [#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431) +* Limit Viewport [#8622](https://github.com/mapbox/mapbox-gl-native/pull/8622) +* Transition Properties for Layer attributes [#8509](https://github.com/mapbox/mapbox-gl-native/pull/8509) +* Style wide transition duration and transition offset in milliseconds [#8576](https://github.com/mapbox/mapbox-gl-native/pull/8576) +* Transifex integration, Catalan & Dutch translations [#8556](https://github.com/mapbox/mapbox-gl-native/pull/8556) +* LatLngBounds includes with another bounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517) +* LatLngBounds includes takes in account LatLng on the edges (cfr. core) [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517) +* LatLngBounds facility getters/setters for LatLnbg on the edges of the bounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517) +* Expose world bounds in LatLngBounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517) +* OfflineRegion are validated if the bounds is found in the world bounds, else onError will be invoked [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517) +* Polygon holes [#8557](https://github.com/mapbox/mapbox-gl-native/pull/8557) and [#8722](https://github.com/mapbox/mapbox-gl-native/pull/8722) +* Custom location source [#8710](https://github.com/mapbox/mapbox-gl-native/pull/8710) +* Expose source layer identifier [#8709](https://github.com/mapbox/mapbox-gl-native/pull/8709) +* Ensure surface is created after display and context [#8759](https://github.com/mapbox/mapbox-gl-native/pull/8759) +* Harden telemetry event dispatch [#8767](https://github.com/mapbox/mapbox-gl-native/pull/8767) +* Move LatLngBounds calculation for CameraUpdateFactory to core [#8765](https://github.com/mapbox/mapbox-gl-native/pull/8765) +* Spanish, Lithuanian, and Vietnamese localizations [#8852](https://github.com/mapbox/mapbox-gl-native/pull/8852) +* Warning when updating a non-added annotation [#8832](https://github.com/mapbox/mapbox-gl-native/pull/8832) +* Share location source between components [#8825](https://github.com/mapbox/mapbox-gl-native/pull/8825) +* Test application runtime permissions for pre lollipop devices [#8823](https://github.com/mapbox/mapbox-gl-native/pull/8823) +* Do not call OnMarkerClick listener twice [#8804](https://github.com/mapbox/mapbox-gl-native/pull/8804) +* Rework instrumentation tests [#8793](https://github.com/mapbox/mapbox-gl-native/pull/8793) +* Set first render flag to false when destroying the surface [#8739](https://github.com/mapbox/mapbox-gl-native/pull/8739) +* Post resetting tracking settings to avoid race condition reset [#8738](https://github.com/mapbox/mapbox-gl-native/pull/8738) +* Expose Source Layer identifier [#8709](https://github.com/mapbox/mapbox-gl-native/pull/8709) +* Derived source attribution [#8630](https://github.com/mapbox/mapbox-gl-native/pull/8630) +* Consistent use of duration unit [#8578](https://github.com/mapbox/mapbox-gl-native/pull/8578) +* Swedish localization [#8883](https://github.com/mapbox/mapbox-gl-native/pull/8883) +* Streets v10, Outdoors v10, Satellite Streets v10, Traffic Day v2, Traffic Night v2 [#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301) + +## 5.0.2 - April 3, 2017 + +5.0.2 is a patch release that contains the following changes: + +* Binary shader caching [#8604](https://github.com/mapbox/mapbox-gl-native/pull/8604) +* Fix resource transform callback [#8582](https://github.com/mapbox/mapbox-gl-native/pull/8582) +* Restore onTouch behaviour to 4.x version [#8585](https://github.com/mapbox/mapbox-gl-native/pull/8585) +* Restore anchoring after updating MarkerView Icon [#8519](https://github.com/mapbox/mapbox-gl-native/pull/8519) + +## 5.0.1 - March 22nd, 2017 + +5.0.1 is a patch release that addresses a shader precision issue that created a rendering problem on some devices. + +* Use `highp` for color attributes [#8385](https://github.com/mapbox/mapbox-gl-native/issues/8385) + +## 5.0.0 - March 17th, 2017 + +5.0.0 final release contains: + +* Support for data-driven styles [#7752](https://github.com/mapbox/mapbox-gl-native/pull/7752) +* Additional APIs to manage runtime styling layers [#8195](https://github.com/mapbox/mapbox-gl-native/pull/8195) +* Allow query all features in sources (`querySourceFeatures`) [#5792](https://github.com/mapbox/mapbox-gl-native/issues/5792) +* Improve accessibility TalkBack support by including content description in views [#8230](https://github.com/mapbox/mapbox-gl-native/pull/8230) +* Consistent double tap zoom acceleration [#7514](https://github.com/mapbox/mapbox-gl-native/issues/7514) +* Allow zooming/scaling to use `AnimationOptions` [#8181](https://github.com/mapbox/mapbox-gl-native/pull/8181) +* Cleanup inconsistencies `float` vs `double` [#4445](https://github.com/mapbox/mapbox-gl-native/issues/4445) +* Add `mapbox_` prefix to attributes [#6482](https://github.com/mapbox/mapbox-gl-native/issues/6482) +* Update LOST to 2.x [#6573](https://github.com/mapbox/mapbox-gl-native/issues/6537) +* MAS submodules (`geojson`, `telemetry`) are now smaller to reduce the overall method count [#7642](https://github.com/mapbox/mapbox-gl-native/pull/7642) +* Telemetry Service is now include automatically via Manifest merge to simplify set up [#8338](https://github.com/mapbox/mapbox-gl-native/pull/8338) +* Support for Android Nougat [#5910](5910-move-listener-logic-for-nougat) + - Move location listening logic to `onStart`/`onStop` activity lifecylce methods +* Removal of `accessToken` on `MapView` and `MapboxMap` [#5621](https://github.com/mapbox/mapbox-gl-native/issues/5621) +* Introduction of new make targets [#5940](https://github.com/mapbox/mapbox-gl-native/issues/5940) + - Targets for testing, running and using external tools directly from the command line +* Cleanup Gradle files [#6009](https://github.com/mapbox/mapbox-gl-native/issues/6009) + - Introducing single purpose `.gradle` files +* Checkstyle integration [#7442](https://github.com/mapbox/mapbox-gl-native/pull/7442) +* Transform refactor [#6532](https://github.com/mapbox/mapbox-gl-native/issues/6532) + - All camera related code is moved to a dedicated transform class cfr. core architecture +* Encapsulate gestures [#6557](https://github.com/mapbox/mapbox-gl-native/issues/6557) + - All gesture event code is encapsulated in `MapGestureDetector` + - All key event code is encapsulated in `MapKeyListener` +* Transparent background for `MyLocationView` [#7116](https://github.com/mapbox/mapbox-gl-native/issues/7116) +* Correctly scale accuracy circle for `MyLocationView` [#8255](https://github.com/mapbox/mapbox-gl-native/pull/8255) +* Update documentation on generate sanity tests [#7147](https://github.com/mapbox/mapbox-gl-native/issues/7147) +* Update documentation on style templates [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157) +* Fix `NullPointerException` during save instance state [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157) +* Move management style to core [#7275](https://github.com/mapbox/mapbox-gl-native/issues/7275) +* Fix `OnCameraChange` not called for the final position of animation bug [#7350](https://github.com/mapbox/mapbox-gl-native/issues/7350) +* `MapboxAccountManager` refactor [#6534](https://github.com/mapbox/mapbox-gl-native/issues/6534) + - Consolidating the location where tokens are set + - Rename to reflect the increased responsibilities introduced in prior releases +* AnnotationManager refactor [#6067](https://github.com/mapbox/mapbox-gl-native/issues/6067) + - Extracting all business logic related to annotations into a separate class cfr. to core and the iOS codebase +* Gesture handling improvements: + - Fix missing call to `onFling` when while pinch zooming [#7666](https://github.com/mapbox/mapbox-gl-native/issues/7666) + - Round tap-zoom gestures to nearest integer [#8027](https://github.com/mapbox/mapbox-gl-native/pull/8027) +* Support for style-wide transition animation duration and delay [#6779](https://github.com/mapbox/mapbox-gl-native/issues/6779) +* Allow callback parameter for style setting [#8262](https://github.com/mapbox/mapbox-gl-native/issues/8262) +* Support for all animated camera changes to configure dismissing tracking modes [#7854](https://github.com/mapbox/mapbox-gl-native/issues/7854) +* Avoid disabling location tracking on all gestures [#7878](https://github.com/mapbox/mapbox-gl-native/issues/7878) +* `LatLng` objects produced by the SDK are wrapped by default [#4522](https://github.com/mapbox/mapbox-gl-native/issues/4522) +* Proguard update for new SDK packages [#8437](https://github.com/mapbox/mapbox-gl-native/pull/8437) +* Javadoc cleanup [#8438](https://github.com/mapbox/mapbox-gl-native/pull/8438) +* MarkerViewClickListener and MapClickListener called simultaneously [#8447](https://github.com/mapbox/mapbox-gl-native/pull/8447) +* Fix LOST v2.0.0 integration [#8445](https://github.com/mapbox/mapbox-gl-native/pull/8445) +* Crash with OnMapChangeListener [#8380](https://github.com/mapbox/mapbox-gl-native/pull/8380) +* Feature query crash [#8374](https://github.com/mapbox/mapbox-gl-native/pull/8374) +* flyTo fix [#8302](https://github.com/mapbox/mapbox-gl-native/pull/8302) +* Don't dispatch MarkerView motion event up to MapView [#8447](https://github.com/mapbox/mapbox-gl-native/pull/8447) + +## 5.0.0-beta.3 - March 10th, 2017 + +5.0.0-beta.3 focuses on addressing stability issues and bug fixes. It also includes: + +* Allow query all features in sources (`querySourceFeatures`) [#5792](https://github.com/mapbox/mapbox-gl-native/issues/5792) +* Improve accessibility TalkBack support by including content description in views [#8230](https://github.com/mapbox/mapbox-gl-native/pull/8230) +* Allow zooming/scaling to use `AnimationOptions` [#8181](https://github.com/mapbox/mapbox-gl-native/pull/8181) +* Telemetry Service is now include automatically via Manifest merge to simplify set up [#8338](https://github.com/mapbox/mapbox-gl-native/pull/8338) +* Correctly scale accuracy circle for `MyLocationView` [#8255](https://github.com/mapbox/mapbox-gl-native/pull/8255) +* Round tap-zoom gestures to nearest integer [#8027](https://github.com/mapbox/mapbox-gl-native/pull/8027) +* Allow callback parameter for style setting [#8262](https://github.com/mapbox/mapbox-gl-native/issues/8262) +* Avoid disabling location tracking on all gestures [#7878](https://github.com/mapbox/mapbox-gl-native/issues/7878) + +## 5.0.0-beta.2 - March 1st, 2017 + +5.0.0-beta.2 focuses on addressing stability issues and bug fixes. It also includes: + +* Data-driven styling for `{text,icon}-{color,opacity,halo-color,halo-blur,halo-width}` [#7939](https://github.com/mapbox/mapbox-gl-native/pull/7939) +* Additional APIs to manage runtime styling layers [#8195](https://github.com/mapbox/mapbox-gl-native/pull/8195) + +## 5.0.0-beta.1 - February 14th, 2017 + +* Support for data-driven styles [#7752](https://github.com/mapbox/mapbox-gl-native/pull/7752) +* Consistent double tap zoom acceleration [#7514](https://github.com/mapbox/mapbox-gl-native/issues/7514) +* Cleanup inconsistencies `float` vs `double` [#4445](https://github.com/mapbox/mapbox-gl-native/issues/4445) +* Add `mapbox_` prefix to attributes [#6482](https://github.com/mapbox/mapbox-gl-native/issues/6482) +* Update LOST to 2.0.0 [#6573](https://github.com/mapbox/mapbox-gl-native/issues/6537) +* MAS submodules (geojson, telemetry) are now smaller to reduce the overall method count [#7642](https://github.com/mapbox/mapbox-gl-native/pull/7642) +* Support for Android Nougat [#5910](5910-move-listener-logic-for-nougat) + - Move location listening logic to onStart/onStop Activity lifecylce methods +* Removal of `accessToken` on `MapView` and `MapboxMap` [#5621](https://github.com/mapbox/mapbox-gl-native/issues/5621) +* Introduction of new make targets [#5940](https://github.com/mapbox/mapbox-gl-native/issues/5940) + - Targets for testing, running and using external tools directly from the command line +* Cleanup Gradle files [#6009](https://github.com/mapbox/mapbox-gl-native/issues/6009) + - Introducing single purpose `.gradle` files +* Checkstyle integration [#7442](https://github.com/mapbox/mapbox-gl-native/pull/7442) +* Transform refactor [#6532](https://github.com/mapbox/mapbox-gl-native/issues/6532) + - All camera related code is moved to a dedicated transform class cfr. core architecture +* Encapsulate Gestures [#6557](https://github.com/mapbox/mapbox-gl-native/issues/6557) + - All gesture event code is encapsulated in `MapGestureDetector` + - All key event code is encapsulated in `MapKeyListener` +* Transparent background for `MyLocationView` [#7116](https://github.com/mapbox/mapbox-gl-native/issues/7116) +* Update documentation on generate sanity tests [#7147](https://github.com/mapbox/mapbox-gl-native/issues/7147) +* Update documentation on style templates [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157) +* `NullPointerException` during save instance state [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157) +* Move management style to core [#7275](https://github.com/mapbox/mapbox-gl-native/issues/7275) +* `OnCameraChange` not called for the final position of animation bug [#7350](https://github.com/mapbox/mapbox-gl-native/issues/7350) +* `MapboxAccountManager` refactor [#6534](https://github.com/mapbox/mapbox-gl-native/issues/6534) + - Consolidating the location where tokens are set + - Rename to reflect the increased responsibilities introduced in prior releases +* AnnotationManager refactor [#6067](https://github.com/mapbox/mapbox-gl-native/issues/6067) + - Extracting all business logic related to annotations into a separate class cfr. to core and the iOS codebase +* Gesture handling bugs + - Avoid calls to onFling when while pinch zooming [#7666](https://github.com/mapbox/mapbox-gl-native/issues/7666) +* Support for style-wide transition animation duration and delay [#6779](https://github.com/mapbox/mapbox-gl-native/issues/6779) +* Support for all animated camera changes to configure dismissing tracking modes [#7854](https://github.com/mapbox/mapbox-gl-native/issues/7854) +* `LatLng` objects produced by the SDK are wrapped by default for [compatibility](https://developers.google.com/android/reference/com/google/android/gms/maps/model/LatLng) with the Google Maps API on Android [#4522](https://github.com/mapbox/mapbox-gl-native/issues/4522) + +## 4.2.2 - January 27, 2017 + +Mapbox Android 4.2.2 builds further on v4.2.1 and resolves: +* OnFling gesture improvements + - Improve fling by calculating animation time based on velocity [#7676](https://github.com/mapbox/mapbox-gl-native/pull/7676) + - Avoid triggering a fling after a scale gesture [#7675](https://github.com/mapbox/mapbox-gl-native/issues/7675) +* Deselect marker on infowindow click [#7784](https://github.com/mapbox/mapbox-gl-native/issues/7784) +* Update build tools to Bitrise supported one [#7729](https://github.com/mapbox/mapbox-gl-native/issues/7729) +* Removal of redudant log statements in native_map_view.cpp [#7801](https://github.com/mapbox/mapbox-gl-native/issues/7801) +* Invalidate markersviews when updating their position [#7794](https://github.com/mapbox/mapbox-gl-native/issues/7794) +* Avoid clustering unclusterable GeoJSON [#7633](https://github.com/mapbox/mapbox-gl-native/pull/7633) +* Prevent null pointer exceptions when receiving connecitivy change events [#6858](https://github.com/mapbox/mapbox-gl-native/issues/6858) + +## 4.2.1 - December 22, 2016 + +Mapbox Android 4.2.1 is a bugfix release build on top of 4.2.0 and resolves: + +* Gesture handling bugs + - Reverse fling when tilted [#7383](https://github.com/mapbox/mapbox-gl-native/pull/7383) + - Rotation is hard trigger [#7299](https://github.com/mapbox/mapbox-gl-native/pull/7299) +* Null pointer exception on TrackingSettings [#7505](https://github.com/mapbox/mapbox-gl-native/pull/7505) +* Patches to our CI integration [#7363](https://github.com/mapbox/mapbox-gl-native/pull/7363) & [#7385](https://github.com/mapbox/mapbox-gl-native/pull/7385) +* Screen density is now correctly applied for attributes [#7327](https://github.com/mapbox/mapbox-gl-native/pull/7327) +* Usage of LocalBroadCastReceiver [#7511](https://github.com/mapbox/mapbox-gl-native/pull/7511) + +## 4.2.0 - December 14, 2016 + +Mapbox Android 4.2.0 contains all 4.2.0-beta.5 changes and adds: + +* Adds additional documentation to APIs +* Resolved issue with marker views occasionally not showing up until a gesture was performed on map [#7239](https://github.com/mapbox/mapbox-gl-native/pull/7239) +* Added horizontal accuracy to location events [#7237](https://github.com/mapbox/mapbox-gl-native/pull/7237) +* Resolved issue with changing visibility of a layer [#7242](https://github.com/mapbox/mapbox-gl-native/pull/7242) +* Proguard improvement and fixes + +## 4.2.0-beta.5 - October 25, 2016 + +Mapbox Android 4.2.0-beta.5 adds no new features, only bug fixes. + +## 4.2.0-beta.4 - October 25, 2016 + +Mapbox Android 4.2.0-beta.4 contains all 4.2.0-beta.3 changes and adds: + +* Query rendered features by source [#6516](https://github.com/mapbox/mapbox-gl-native/issues/6516) +* Decreased logging for release builds [#6787](https://github.com/mapbox/mapbox-gl-native/pull/6787) +* setConnected method to manually set a connected flag [#6618](https://github.com/mapbox/mapbox-gl-native/pull/6618) + +## 4.2.0-beta.3 - September 21, 2016 + +Mapbox Android 4.2.0-beta.3 contains all 4.2.0-beta.2 changes and adds: + +* Configurable API endpoint [#6309](https://github.com/mapbox/mapbox-gl-native/pull/6309) +* Adjusted logging level for failed OkHttp requests [6356](https://github.com/mapbox/mapbox-gl-native/issues/6356) +* Offline improvements: + - Fix SQLite crashes by reverting WAL journal mode [#6320](https://github.com/mapbox/mapbox-gl-native/pull/6320) + +## 4.2.0-beta.2 - August 25, 2016 + +Mapbox Android 4.2.0-beta.2 contains all 4.2.0-beta.1 changes and adds: + +* Query rendered features [#5869](https://github.com/mapbox/mapbox-gl-native/issues/5869) +* Clustering [#5852](https://github.com/mapbox/mapbox-gl-native/issues/5852) +* Integrated support for [Mapbox Android Services](https://www.mapbox.com/android-sdk/#mapbox_android_services) +* Offline improvements: + - Enable external storage to host the tiles database [#5589](https://github.com/mapbox/mapbox-gl-native/issues/5589) + - Stop delivering status updates when offline download is canceled [#5538](https://github.com/mapbox/mapbox-gl-native/issues/5538) + - Update SQLite schema with WAL journal mode and normal sync [#5796](https://github.com/mapbox/mapbox-gl-native/pull/5796) + - Check for network connectivity before requesting resources [#6123](https://github.com/mapbox/mapbox-gl-native/pull/6123) + +## 4.2.0-beta.1 - August 6, 2016 + +Mapbox Android 4.2.0 introduces the Runtime Style API and improves performance. + +* Runtime Style API ([#5610](https://github.com/mapbox/mapbox-gl-native/issues/5610)) +* Earcut ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444)) +* Map view rendered with `SurfaceView` for improved performance [#5000](https://github.com/mapbox/mapbox-gl-native/issues/5000) + +## 4.1.1 - July 19, 2016 + +Mapbox Android 4.1.1 is a patch release and is recommended to upgrade to it as soon as possible. + +* Default Styles Caching Crash ([#5722](https://github.com/mapbox/mapbox-gl-native/issues/5722)) + +## 4.1.0 - June 29, 2016 + +Mapbox Android 4.1.0 builds off our ambitious 4.0.0 version with 3 major new features being released. + +* View Based Annotations ([#3276](https://github.com/mapbox/mapbox-gl-native/issues/3276)) +* UserLocationView Refactor ([#4396](https://github.com/mapbox/mapbox-gl-native/issues/4396)) +* MapboxAccountManager ([#5004](https://github.com/mapbox/mapbox-gl-native/issues/5004)) + +## 4.1.0-beta.3 - June 20, 2016 + +* New samples: + * [Location picker](https://github.com/mapbox/mapbox-gl-native/pull/5391) + * [Animate and rotate multiple markers](https://github.com/mapbox/mapbox-gl-native/issues/5299) + * [Scaling marker activity](https://github.com/mapbox/mapbox-gl-native/issues/5409) +* Marker improvements: + * [Expose MarkerView alpha](https://github.com/mapbox/mapbox-gl-native/pull/5329) + * [Icon should be optional for MarkerView](https://github.com/mapbox/mapbox-gl-native/pull/5328) + * [Expose an API to enable selection/deselection of markers on a map tap](https://github.com/mapbox/mapbox-gl-native/pull/5312) + * [Bring selected MarkerView to the front](https://github.com/mapbox/mapbox-gl-native/pull/5294) +* [Make gesture focal point configurable](https://github.com/mapbox/mapbox-gl-native/pull/5332) + +## 4.1.0-beta.2 - June 8, 2016 + +* Dynamically Update InfoWindow ([#5237](https://github.com/mapbox/mapbox-gl-native/issues/5237)) +* armeabi ABI Work On armv7 Devices ([#3985](https://github.com/mapbox/mapbox-gl-native/issues/3985)) +* Remove Adapter Requirement For MarkerView ([#5214](https://github.com/mapbox/mapbox-gl-native/issues/5214)) +* Always Current Version Style URL Constants ([#5193](https://github.com/mapbox/mapbox-gl-native/issues/5193)) +* Random NullPointerException On Telemetry ([#5186](https://github.com/mapbox/mapbox-gl-native/issues/5186)) + +## 4.1.0-beta.1 - May 26, 2016 + +Mapbox Android 4.1.0 builds off our ambitious 4.0.0 version with 3 major new features being released. To help us produce the highest quality SDK possible we're releasing an official Beta release first so that everyone has time to explore it and help hardened it before the official 4.1.0 Final Release. + +* View Based Annotations ([#3276](https://github.com/mapbox/mapbox-gl-native/issues/3276)) +* UserLocationView Refactor ([#4396](https://github.com/mapbox/mapbox-gl-native/issues/4396)) +* MapboxAccountManager ([#5004](https://github.com/mapbox/mapbox-gl-native/issues/5004)) + +## 4.0.1 - May 12, 2016 + +Mapbox Android 4.0.1 is a patch release to make this bug fix available sooner. + +* MapboxMap.removeAnnotations() doesn't remove markers ([#4553](https://github.com/mapbox/mapbox-gl-native/issues/4553)) + +## 4.0.0 - March 30, 2016 + +Mapbox Android 4.0.0 contains the following 3 major new features. + +* MapboxMap API Change ([#3145](https://github.com/mapbox/mapbox-gl-native/issues/3145)) +* Offline Maps ([#3891](https://github.com/mapbox/mapbox-gl-native/issues/3891)) +* Telemetry ([#2421](https://github.com/mapbox/mapbox-gl-native/issues/2421)) + +## 4.0.0-rc.1 - March 25, 2016 + +* Default Value Bug Fix for MapboxMapOptions ([#4398](https://github.com/mapbox/mapbox-gl-native/issues/4398)) +* NullPointerException When Scrolling ([#4424](https://github.com/mapbox/mapbox-gl-native/issues/4424)) +* Platform Specific CHANGELOGS ([#4432](https://github.com/mapbox/mapbox-gl-native/issues/4432)) +* Introduce LatLng.wrap() ([#4475](https://github.com/mapbox/mapbox-gl-native/issues/4475)) + +## 4.0.0-beta.2 - March 21, 2016 + +* arm64 ABI Support ([#3128](https://github.com/mapbox/mapbox-gl-native/issues/3128)) +* Unify Offline And Cache Databases ([#4362](https://github.com/mapbox/mapbox-gl-native/issues/4362)) +* Offline Database Vacuuming ([#4342](https://github.com/mapbox/mapbox-gl-native/pull/4342)) +* Telemetry User Agent Fix ([#4328](https://github.com/mapbox/mapbox-gl-native/issues/4328)) +* OnCameraChange Bug Fix ([#4327](https://github.com/mapbox/mapbox-gl-native/issues/4327)) +* OnCameraChangeListener vs getCameraPosition ([#4326](https://github.com/mapbox/mapbox-gl-native/issues/4326)) + +## 4.0.0-beta.1 - March 15, 2016 + +Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major new features being released. To help us produce the highest quality SDK possible we're releasing an official Beta release first so that everyone has time to explore it and help hardened it before the official 4.0.0 Final Release. + +* MapboxMap API Change ([#3145](https://github.com/mapbox/mapbox-gl-native/issues/3145)) +* Offline Maps ([#3891](https://github.com/mapbox/mapbox-gl-native/issues/3891)) +* Telemetry ([#2421](https://github.com/mapbox/mapbox-gl-native/issues/2421)) + +## 3.2.0 - January 28, 2016 + +* Fixed crash caused by annotation image with non-integer width or height ([#3031](https://github.com/mapbox/mapbox-gl-native/issues/3031)) +* Tracking Mode Reverses Bearing Fix ([#3664](https://github.com/mapbox/mapbox-gl-native/issues/3664)) +* GPS Extra Rotation Fix ([#3661](https://github.com/mapbox/mapbox-gl-native/issues/3661)) +* Added new methods for getting and setting the min and max zoom levels: `getMinZoom`, `setMinZoom`, `getMaxZoom`, `setMaxZoom`. ([#509](https://github.com/mapbox/mapbox-gl-native/issues/509)) + +## 3.1.0 - January 20, 2016 + +* Camera API Callback Improvements ([#3412](https://github.com/mapbox/mapbox-gl-native/issues/3412)) +* Coordinate Deprecated For LatLng ([#3309](https://github.com/mapbox/mapbox-gl-native/issues/3309)) +* Responsive User Dot Location Tracking ([#2049](https://github.com/mapbox/mapbox-gl-native/issues/2049)) + +## 3.0.0 - December 21, 2015 + +* Added Camera API ([#3244](https://github.com/mapbox/mapbox-gl-native/issues/3244)) +* Custom Layer Support ([#3248](https://github.com/mapbox/mapbox-gl-native/issues/3348)) +* Reverse Tilt Gesutre Detection ([#3245](https://github.com/mapbox/mapbox-gl-native/issues/3245)) +* Decoupled Location Provider ([#2954](https://github.com/mapbox/mapbox-gl-native/issues/2954)) + +## 2.3.0 - December 4, 2015 + +* Added Tilt / Pitch Support ([#2805](https://github.com/mapbox/mapbox-gl-native/issues/2805)) +* Keep InfoWindow Open When Panning ([#3121](https://github.com/mapbox/mapbox-gl-native/issues/3121)) +* Concurrent Multiple Open InfoWindows ([#3115](https://github.com/mapbox/mapbox-gl-native/issues/3115)) +* OkHttp Replace curl ([#2856](https://github.com/mapbox/mapbox-gl-native/issues/2856)) +* GPS and Compass Customization Support ([#2858](https://github.com/mapbox/mapbox-gl-native/issues/2858)) + +## 2.2.0 - October 28, 2015 + +- New User Dot location graphics ([#2732](https://github.com/mapbox/mapbox-gl-native/issues/2732)) +- Custom Drawable Markers ([#2744](https://github.com/mapbox/mapbox-gl-native/issues/2744)) +- `MapView.setOnInfoWindowClickListener()` support ([#2448](https://github.com/mapbox/mapbox-gl-native/issues/2448)) +- Completed Annotations API ([#1716](https://github.com/mapbox/mapbox-gl-native/issues/1716)) +- Satellite Streets Style ([#2739](https://github.com/mapbox/mapbox-gl-native/issues/2739)) +- **RESOLVED** Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802)) + +## 2.1.0 - October 21, 2015 + +- Initial Android release. diff --git a/DISTRIBUTE.md b/DISTRIBUTE.md new file mode 100644 index 000000000..8f2bec19d --- /dev/null +++ b/DISTRIBUTE.md @@ -0,0 +1,57 @@ +# Distributing Mapbox GL Native for Android + +Depending on your use case, you may want to support all or just a subset of [Android ABIs](http://developer.android.com/ndk/guides/abis.html). This document covers building an `.aar` file from the Mapbox Maps SDK for Android and building `.so` files for specific ABIs. In normal circumstances an application developer will use [APK splits](https://developer.android.com/studio/build/configure-apk-splits.html) to optimize this at application level. + +##### Build types + +With a `BUILDTYPE` var you can specify the build type for the `.so` and `.aar` files: + +```bash +BUILDTYPE=Debug or BUILDTYPE=Release +``` + +##### Creating an Android Archive file that supports all ABIs + +```sh +BUILDTYPE=Release make apackage +``` + +This will build native libraries to support following ABIs: +- armeabi +- armeabi-v7a +- arm64-v8a +- x86 +- x86_64 +- mips + +After succesfully finish building the native libraries, gradle will build the MapboxAndroidSDK module and generate an Android Archive file in `MapboxAndroidSDK/build/outputs/aar `. The packaged native libraries can be found in `MapboxAndroidSDK/src/main/jniLibs/`. + +##### Build native libraries for a specific ABI + +```sh +make android-lib-%% +``` + +In the command above you'll need to replace `%%` with an ABI key listed below: + +| ABI Key | Android ABI | +| ------- | ----------- | +| arm-v5 | armeabi | +| arm-v7 | armeabi-v7a | +| arm-v8 | arm64-v8a | +| x86 | x86 | +| x86-64 | x86_64 | +| mips | mips | + +For example, to build the arm64-v8a ABI the Makefile target would be: + +```sh +make android-lib-arm-v8 +``` + +It's also possible to build multiple ABI (without having to build them all) by running the Makefile multiple times. For example to build arm64-v8a and x86_64 in the same project the commands would be: + +```sh +make android-lib-arm-v8 +make android-lib-arm-x86-64 +``` diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..8423a34a6 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,227 @@ + +## Additional Mapbox GL licenses +Mapbox GL uses portions of the Android Arch-Common. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Arch-Runtime. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Lifecycle LiveData. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Lifecycle LiveData Core. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Lifecycle Runtime. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Lifecycle ViewModel. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Lifecycle-Common. +URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Annotations. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Async Layout Inflater. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library collections. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library compat. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Coordinator Layout. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library core UI. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library core utils. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Cursor Adapter. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Custom View. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Custom View. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Document File. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Drawer Layout. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library fragment. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Interpolators. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library loader. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Local Broadcast Manager. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Print. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library Sliding Pane Layout. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Android Support Library View Pager. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Gson. +License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Accounts SDK for Android. +URL: [https://github.com/mapbox/mapbox-accounts-android](https://github.com/mapbox/mapbox-accounts-android) +License: [Mapbox Terms of Service](https://www.mapbox.com/tos/) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Android Core Library. +URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Android Gestures Library. +URL: [https://github.com/mapbox/mapbox-gestures-android](https://github.com/mapbox/mapbox-gestures-android) +License: [BSD](https://opensource.org/licenses/BSD-2-Clause) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Android Telemetry Library. +URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Java SDK. +URL: [https://github.com/mapbox/mapbox-java](https://github.com/mapbox/mapbox-java) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Mapbox Java SDK. +URL: [https://github.com/mapbox/mapbox-java](https://github.com/mapbox/mapbox-java) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the OkHttp. +License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Okio. +License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the SoLoader. +URL: [https://github.com/facebook/soloader](https://github.com/facebook/soloader) +License: [Apache-2](https://github.com/facebook/soloader/blob/master/LICENSE) + +=========================================================================== + +Mapbox GL uses portions of the VersionedParcelable and friends. +URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) +License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + +Mapbox GL uses portions of the Gradle License Plugin. +URL: [https://github.com/jaredsburrows/gradle-license-plugin](https://github.com/jaredsburrows/gradle-license-plugin) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + diff --git a/MapboxGLAndroidSDK/.gitignore b/MapboxGLAndroidSDK/.gitignore new file mode 100644 index 000000000..e44384742 --- /dev/null +++ b/MapboxGLAndroidSDK/.gitignore @@ -0,0 +1,2 @@ +dependency-graph-mapbox-libraries.png +src/test/resources/mobile-event* diff --git a/MapboxGLAndroidSDK/build.gradle b/MapboxGLAndroidSDK/build.gradle new file mode 100644 index 000000000..5ee3af61e --- /dev/null +++ b/MapboxGLAndroidSDK/build.gradle @@ -0,0 +1,105 @@ +apply plugin: 'com.android.library' +apply plugin: "com.jaredsburrows.license" +apply plugin: 'kotlin-android' +apply from: "${rootDir}/gradle/native-build.gradle" + +dependencies { + lintChecks project(":MapboxGLAndroidSDKLint") + api dependenciesList.mapboxAndroidTelemetry + api dependenciesList.mapboxJavaGeoJSON + api dependenciesList.mapboxAndroidGestures + api dependenciesList.mapboxAndroidAccounts + implementation dependenciesList.mapboxJavaTurf + implementation dependenciesList.supportAnnotations + implementation dependenciesList.supportFragmentV4 + implementation dependenciesList.okhttp3 + implementation dependenciesList.soLoader + testImplementation dependenciesList.junit + testImplementation dependenciesList.mockito + testImplementation dependenciesList.mockk + testImplementation dependenciesList.robolectric + testImplementation dependenciesList.kotlinLib + testImplementation dependenciesList.commonsIO +} + +android { + compileSdkVersion androidVersions.compileSdkVersion + + defaultConfig { + minSdkVersion androidVersions.minSdkVersion + targetSdkVersion androidVersions.targetSdkVersion + buildConfigField "String", "GIT_REVISION_SHORT", String.format("\"%s\"", getGitRevision()) + buildConfigField "String", "MAPBOX_SDK_IDENTIFIER", String.format("\"%s\"", "mapbox-maps-android") + buildConfigField "String", "MAPBOX_SDK_VERSION", String.format("\"%s\"", project.VERSION_NAME) + buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) + buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"mapbox-maps-android/%s\"", project.VERSION_NAME) + consumerProguardFiles 'proguard-rules.pro' + } + + // build native libraries + List nativeTargets = ["mapbox-gl"] + if (project.hasProperty("mapbox.with_test")) { + nativeTargets.add("mbgl-test") + } + if (project.hasProperty("mapbox.with_benchmark")) { + nativeTargets.add("mbgl-benchmark") + } + nativeBuild(nativeTargets) + + // avoid naming conflicts, force usage of prefix + resourcePrefix 'mapbox_' + + sourceSets { + // limit amount of exposed library resources + main.res.srcDirs += 'src/main/res-public' + } + + lintOptions { + disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission', 'WrongThreadInterprocedural' + checkAllWarnings true + warningsAsErrors false + } + + testOptions { + unitTests { + returnDefaultValues true + + // Roboelectric 4.0 required config + // http://robolectric.org/migrating/#migrating-to-40 + includeAndroidResources = true + } + } + + buildTypes { + debug { + testCoverageEnabled true + jniDebuggable true + } + } +} + +licenseReport { + generateHtmlReport = false + generateJsonReport = true + copyHtmlReportToAssets = false + copyJsonReportToAssets = false +} + +def static getGitRevision() { + def cmd = "git rev-parse --short HEAD" + def proc = cmd.execute() + def ref = proc.text.trim() + return ref +} + +configurations { + all*.exclude group: 'commons-logging', module: 'commons-logging' + all*.exclude group: 'commons-collections', module: 'commons-collections' +} +apply from: "${rootDir}/gradle/gradle-javadoc.gradle" +apply from: "${rootDir}/gradle/gradle-checkstyle.gradle" +apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle" +apply from: "${rootDir}/gradle/gradle-update-vendor-modules.gradle" +apply from: "${rootDir}/gradle/android-nitpick.gradle" +apply from: "${rootDir}/gradle/gradle-bintray.gradle" +apply from: "${rootDir}/gradle/jacoco-report.gradle" \ No newline at end of file diff --git a/MapboxGLAndroidSDK/lint.xml b/MapboxGLAndroidSDK/lint.xml new file mode 100644 index 000000000..3a244199a --- /dev/null +++ b/MapboxGLAndroidSDK/lint.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/MapboxGLAndroidSDK/proguard-rules.pro b/MapboxGLAndroidSDK/proguard-rules.pro new file mode 100644 index 000000000..f592efa6b --- /dev/null +++ b/MapboxGLAndroidSDK/proguard-rules.pro @@ -0,0 +1,41 @@ +# By default, the flags in this file are appended to flags specified +# in ../sdk/tools/proguard/proguard-android.txt, +# contents of this file will be appended into proguard-android.txt +-keepattributes Signature, *Annotation*, EnclosingMethod + +# Reflection on classes from native code +-keep class com.google.gson.JsonArray { *; } +-keep class com.google.gson.JsonElement { *; } +-keep class com.google.gson.JsonObject { *; } +-keep class com.google.gson.JsonPrimitive { *; } +-dontnote com.google.gson.** + +# dontnote for keeps the entry point x but not the descriptor class y +-dontnote com.mapbox.mapboxsdk.maps.MapboxMap$OnFpsChangedListener +-dontnote com.mapbox.mapboxsdk.style.layers.PropertyValue +-dontnote com.mapbox.mapboxsdk.maps.MapboxMap +-dontnote com.mapbox.mapboxsdk.maps.MapboxMapOptions +-dontnote com.mapbox.mapboxsdk.log.LoggerDefinition +-dontnote com.mapbox.android.core.location.LocationEnginePriority + +# config for okhttp 3.11.0, https://github.com/square/okhttp/pull/3354 +-dontwarn javax.annotation.** +-dontnote okhttp3.internal.** +-dontwarn org.codehaus.** + +# config for mapbox-sdk-geojson:3.0.1 +-keep class com.mapbox.geojson.** { *; } +-dontwarn com.google.auto.value.** + +# config for additional notes +-dontnote org.robolectric.Robolectric +-dontnote libcore.io.Memory +-dontnote com.google.protobuf.** +-dontnote android.net.** +-dontnote org.apache.http.** + +# config for mapbox-sdk-services +# while we don't include this dependency directly +# a large amount of users combine it with our SDK +# we aren't able to provide a proguard config in that project (jar vs aar) +-dontwarn com.sun.xml.internal.ws.spi.db.* \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/MapboxGLAndroidSDK/src/main/AndroidManifest.xml new file mode 100644 index 000000000..dcbec69bf --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java new file mode 100644 index 000000000..5b8f10e01 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java @@ -0,0 +1,170 @@ +package com.mapbox.mapboxsdk; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; +import android.text.format.DateUtils; + +import com.mapbox.android.accounts.v1.MapboxAccounts; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.log.Logger; + +import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_PREFERENCE_SKU_TOKEN; + +/** + * REMOVAL OR MODIFICATION OF THE FOLLOWING CODE VIOLATES THE MAPBOX TERMS + * OF SERVICE + *

+ * The following code is used to access Mapbox's Mapping APIs. + *

+ * Removal or modification of this code when used with Mapbox's Mapping APIs + * can result in termination of your agreement and/or your account with + * Mapbox. + *

+ * Using this code to access Mapbox Mapping APIs from outside the Mapbox Maps + * SDK also violates the Mapbox Terms of Service. On Android, Mapping APIs + * should be accessed using the methods documented at + * https://www.mapbox.com/android. + *

+ * You can access the Mapbox Terms of Service at https://www.mapbox.com/tos/ + */ +class AccountsManager { + private static final String TAG = "Mbgl-AccountsManager"; + private static final String PREFERENCE_USER_ID = "com.mapbox.mapboxsdk.accounts.userid"; + private static final String PREFERENCE_TIMESTAMP = "com.mapbox.mapboxsdk.accounts.timestamp"; + + private SharedPreferences sharedPreferences; + private String skuToken; + private long timestamp; + private boolean isManaged; + + AccountsManager() { + isManaged = isSkuTokenManaged(); + initialize(); + } + + @VisibleForTesting + AccountsManager(SharedPreferences sharedPreferences, boolean isManaged) { + this.sharedPreferences = sharedPreferences; + this.isManaged = isManaged; + initialize(); + } + + private void initialize() { + retrieveSkuTokenAndTimestamp(); + if (isManaged) { + String userId = validateUserId(); + validateRotation(userId); + } + } + + private boolean isSkuTokenManaged() { + boolean value = MapboxConstants.DEFAULT_MANAGE_SKU_TOKEN; + try { + // Try getting a custom value from the app Manifest + ApplicationInfo appInfo = retrieveApplicationInfo(); + if (appInfo.metaData != null) { + value = appInfo.metaData.getBoolean( + MapboxConstants.KEY_META_DATA_MANAGE_SKU_TOKEN, + MapboxConstants.DEFAULT_MANAGE_SKU_TOKEN + ); + } + } catch (Exception exception) { + Logger.e(TAG, "Failed to read the package metadata: ", exception); + } + + return value; + } + + private ApplicationInfo retrieveApplicationInfo() throws PackageManager.NameNotFoundException { + return Mapbox.getApplicationContext().getPackageManager().getApplicationInfo( + Mapbox.getApplicationContext().getPackageName(), + PackageManager.GET_META_DATA); + } + + private void retrieveSkuTokenAndTimestamp() { + SharedPreferences sharedPreferences = getSharedPreferences(); + skuToken = sharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, ""); + timestamp = sharedPreferences.getLong(PREFERENCE_TIMESTAMP, 0L); + } + + private String validateUserId() { + SharedPreferences sharedPreferences = getSharedPreferences(); + String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); + if (TextUtils.isEmpty(userId)) { + userId = generateUserId(); + SharedPreferences.Editor editor = getSharedPreferences().edit(); + editor.putString(PREFERENCE_USER_ID, userId); + editor.apply(); + } + + return userId; + } + + private void validateRotation(String userId) { + if (TextUtils.isEmpty(skuToken) || timestamp == 0L) { + skuToken = generateSkuToken(userId); + timestamp = persistRotation(skuToken); + } + } + + String getSkuToken() { + if (isManaged) { + if (isExpired()) { + SharedPreferences sharedPreferences = getSharedPreferences(); + String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); + skuToken = generateSkuToken(userId); + timestamp = persistRotation(skuToken); + } + } else { + SharedPreferences sharedPreferences = getSharedPreferences(); + String notManagedSkuToken = sharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, ""); + skuToken = notManagedSkuToken; + } + return skuToken; + } + + private boolean isExpired() { + return isExpired(getNow(), timestamp); + } + + static boolean isExpired(long now, long then) { + return ((now - then) > DateUtils.HOUR_IN_MILLIS); + } + + private long persistRotation(String skuToken) { + long now = getNow(); + SharedPreferences.Editor editor = getSharedPreferences().edit(); + editor.putLong(PREFERENCE_TIMESTAMP, now); + editor.putString(KEY_PREFERENCE_SKU_TOKEN, skuToken); + editor.apply(); + return now; + } + + @NonNull + private SharedPreferences getSharedPreferences() { + if (sharedPreferences == null) { + sharedPreferences = Mapbox.getApplicationContext() + .getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE); + } + return sharedPreferences; + } + + static long getNow() { + return System.currentTimeMillis(); + } + + @NonNull + private String generateUserId() { + return MapboxAccounts.obtainEndUserId(); + } + + @NonNull + private String generateSkuToken(String userId) { + return MapboxAccounts.obtainMapsSkuUserToken(userId); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java new file mode 100644 index 000000000..ee9f4b3b6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java @@ -0,0 +1,55 @@ +package com.mapbox.mapboxsdk; + +import com.mapbox.mapboxsdk.log.Logger; + +/** + * Loads the mapbox-gl shared library + *

+ * By default uses the {@link System#loadLibrary(String)}, + * use {@link #setLibraryLoader(LibraryLoader)} to provide an alternative library loading hook. + *

+ */ +public abstract class LibraryLoader { + + private static final String TAG = "Mbgl-LibraryLoader"; + + private static final LibraryLoader DEFAULT = Mapbox.getModuleProvider() + .createLibraryLoaderProvider() + .getDefaultLibraryLoader(); + + private static volatile LibraryLoader loader = DEFAULT; + + private static boolean loaded; + + /** + * 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. + *

+ * Catches UnsatisfiedLinkErrors and prints a warning to logcat. + *

+ */ + public static void load() { + try { + if (!loaded) { + loaded = true; + loader.load("mapbox-gl"); + } + } catch (UnsatisfiedLinkError error) { + loaded = false; + String message = "Failed to load native shared library."; + Logger.e(TAG, message, error); + MapStrictMode.strictModeViolation(message, error); + } + } + + public abstract void load(String name); +} + diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoaderProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoaderProvider.java new file mode 100644 index 000000000..c9d98bf76 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoaderProvider.java @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk; + +/** + * Injects the default library loader. + */ +public interface LibraryLoaderProvider { + + /** + * Creates and returns a the default Library Loader. + * + * @return the default library loader + */ + LibraryLoader getDefaultLibraryLoader(); + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictMode.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictMode.java new file mode 100644 index 000000000..c7f995964 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictMode.java @@ -0,0 +1,46 @@ +package com.mapbox.mapboxsdk; + +/** + * Using this class you can enable a strict mode that will throw the {@link MapStrictModeException} + * whenever the map would fail silently otherwise. + */ +public class MapStrictMode { + private static volatile boolean strictModeEnabled; + + /** + * Set the strict mode that will throw the {@link MapStrictModeException} + * whenever the map would fail silently otherwise. + * + * @param strictModeEnabled true to enable the strict mode, false otherwise + */ + public static synchronized void setStrictModeEnabled(boolean strictModeEnabled) { + MapStrictMode.strictModeEnabled = strictModeEnabled; + } + + /** + * Internal use. Called whenever the strict mode violation occurs. + */ + public static void strictModeViolation(String message) { + if (strictModeEnabled) { + throw new MapStrictModeException(message); + } + } + + /** + * Internal use. Called whenever the strict mode violation occurs. + */ + public static void strictModeViolation(String message, Throwable throwable) { + if (strictModeEnabled) { + throw new MapStrictModeException(String.format("%s - %s", message, throwable)); + } + } + + /** + * Internal use. Called whenever the strict mode violation occurs. + */ + public static void strictModeViolation(Throwable throwable) { + if (strictModeEnabled) { + throw new MapStrictModeException(String.format("%s", throwable)); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictModeException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictModeException.java new file mode 100644 index 000000000..5bfddabf9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapStrictModeException.java @@ -0,0 +1,7 @@ +package com.mapbox.mapboxsdk; + +class MapStrictModeException extends RuntimeException { + MapStrictModeException(String message) { + super(String.format("Map detected an error that would fail silently otherwise: %s", message)); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java new file mode 100644 index 000000000..01c82ddad --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -0,0 +1,225 @@ +package com.mapbox.mapboxsdk; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; + +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.TelemetryDefinition; +import com.mapbox.mapboxsdk.net.ConnectivityReceiver; +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.utils.ThreadUtils; + +/** + * The entry point to initialize the Mapbox Android SDK. + *

+ * Obtain a reference by calling {@link #getInstance(Context, String)}. Usually this class is configured in + * Application#onCreate() and is responsible for the active access token, application context, and + * connectivity state. + *

+ */ +@UiThread +@SuppressLint("StaticFieldLeak") +public final class Mapbox { + + private static final String TAG = "Mbgl-Mapbox"; + private static ModuleProvider moduleProvider; + private static Mapbox INSTANCE; + + private Context context; + @Nullable + private String accessToken; + @Nullable + private TelemetryDefinition telemetry; + @Nullable + private AccountsManager accounts; + + /** + * Get an instance of Mapbox. + *

+ * This class manages the Mapbox access token, application context, and connectivity state. + *

+ * + * @param context Android context which holds or is an application context + * @param accessToken Mapbox access token + * @return the single instance of Mapbox + */ + @UiThread + @NonNull + public static synchronized Mapbox getInstance(@NonNull Context context, @Nullable String accessToken) { + ThreadUtils.init(context); + ThreadUtils.checkThread(TAG); + if (INSTANCE == null) { + Context appContext = context.getApplicationContext(); + FileSource.initializeFileDirsPaths(appContext); + INSTANCE = new Mapbox(appContext, accessToken); + if (isAccessTokenValid(accessToken)) { + initializeTelemetry(); + INSTANCE.accounts = new AccountsManager(); + } + ConnectivityReceiver.instance(appContext); + } + return INSTANCE; + } + + Mapbox(@NonNull Context context, @Nullable String accessToken) { + this.context = context; + this.accessToken = accessToken; + } + + /** + * Get the current active access token for this application. + * + * @return Mapbox access token + */ + @Nullable + public static String getAccessToken() { + validateMapbox(); + return INSTANCE.accessToken; + } + + /** + * Set the current active accessToken. + */ + public static void setAccessToken(String accessToken) { + validateMapbox(); + INSTANCE.accessToken = accessToken; + + // cleanup telemetry which is dependent on an access token + if (INSTANCE.telemetry != null) { + INSTANCE.telemetry.disableTelemetrySession(); + INSTANCE.telemetry = null; + } + + // initialize components dependent on a token + if (isAccessTokenValid(accessToken)) { + initializeTelemetry(); + INSTANCE.accounts = new AccountsManager(); + } else { + INSTANCE.accounts = null; + } + FileSource.getInstance(getApplicationContext()).setAccessToken(accessToken); + } + + /** + * Returns a SKU token, refreshed if necessary. This method is meant for internal SDK + * usage only. + * + * @return the SKU token + */ + public static String getSkuToken() { + if (INSTANCE.accounts == null) { + throw new MapboxConfigurationException( + "A valid access token parameter is required when using a Mapbox service." + + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens." + + "Currently provided token is: " + INSTANCE.accessToken); + } + return INSTANCE.accounts.getSkuToken(); + } + + /** + * Application context + * + * @return the application context + */ + @NonNull + public static Context getApplicationContext() { + validateMapbox(); + return INSTANCE.context; + } + + /** + * Manually sets the connectivity state of the app. This is useful for apps which control their + * own connectivity state and want to bypass any checks to the ConnectivityManager. + * + * @param connected flag to determine the connectivity state, true for connected, false for + * disconnected, and null for ConnectivityManager to determine. + */ + public static synchronized void setConnected(Boolean connected) { + validateMapbox(); + ConnectivityReceiver.instance(INSTANCE.context).setConnected(connected); + } + + /** + * Determines whether we have an internet connection available. Please do not rely on this + * method in your apps. This method is used internally by the SDK. + * + * @return true if there is an internet connection, false otherwise + */ + public static synchronized Boolean isConnected() { + validateMapbox(); + return ConnectivityReceiver.instance(INSTANCE.context).isConnected(); + } + + /** + * Initializes telemetry + */ + private static void initializeTelemetry() { + try { + INSTANCE.telemetry = getModuleProvider().obtainTelemetry(); + } catch (Exception exception) { + String message = "Error occurred while initializing telemetry"; + Logger.e(TAG, message, exception); + MapStrictMode.strictModeViolation(message, exception); + } + } + + /** + * Get an instance of Telemetry if initialised + * + * @return instance of telemetry + */ + @Nullable + public static TelemetryDefinition getTelemetry() { + return INSTANCE.telemetry; + } + + /** + * Get the module provider + * + * @return moduleProvider + */ + @NonNull + public static ModuleProvider getModuleProvider() { + if (moduleProvider == null) { + moduleProvider = new ModuleProviderImpl(); + } + return moduleProvider; + } + + /** + * Runtime validation of Mapbox creation. + */ + private static void validateMapbox() { + if (INSTANCE == null) { + throw new MapboxConfigurationException(); + } + } + + /** + * Runtime validation of Mapbox access token + * + * @param accessToken the access token to validate + * @return true is valid, false otherwise + */ + static boolean isAccessTokenValid(@Nullable String accessToken) { + if (accessToken == null) { + return false; + } + + accessToken = accessToken.trim().toLowerCase(MapboxConstants.MAPBOX_LOCALE); + return accessToken.length() != 0 && (accessToken.startsWith("pk.") || accessToken.startsWith("sk.")); + } + + /** + * Internal use. Check if the {@link Mapbox#INSTANCE} is present. + */ + public static boolean hasInstance() { + return INSTANCE != null; + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java new file mode 100644 index 000000000..9749290eb --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java @@ -0,0 +1,38 @@ +package com.mapbox.mapboxsdk; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.http.HttpRequest; +import com.mapbox.mapboxsdk.maps.TelemetryDefinition; + +/** + * Injects concrete instances of configurable abstractions + */ +public interface ModuleProvider { + + /** + * Create a new concrete implementation of HttpRequest. + * + * @return a new instance of an HttpRequest + */ + @NonNull + HttpRequest createHttpRequest(); + + /** + * Get the concrete implementation of TelemetryDefinition + * + * @return a single instance of Telemetry + */ + @Nullable + TelemetryDefinition obtainTelemetry(); + + + /** + * Get the concrete implementation of LibraryLoaderProvider + * + * @return a new instance of LibraryLoaderProvider + */ + @NonNull + LibraryLoaderProvider createLibraryLoaderProvider(); + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java new file mode 100644 index 000000000..2de111c97 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java @@ -0,0 +1,30 @@ +package com.mapbox.mapboxsdk; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.http.HttpRequest; +import com.mapbox.mapboxsdk.maps.TelemetryDefinition; +import com.mapbox.mapboxsdk.module.http.HttpRequestImpl; +import com.mapbox.mapboxsdk.module.loader.LibraryLoaderProviderImpl; +import com.mapbox.mapboxsdk.module.telemetry.TelemetryImpl; + +public class ModuleProviderImpl implements ModuleProvider { + + @Override + @NonNull + public HttpRequest createHttpRequest() { + return new HttpRequestImpl(); + } + + @Override + @Nullable + public TelemetryDefinition obtainTelemetry() { + return new TelemetryImpl(); + } + + @NonNull + @Override + public LibraryLoaderProvider createLibraryLoaderProvider() { + return new LibraryLoaderProviderImpl(); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java new file mode 100644 index 000000000..8ea226649 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java @@ -0,0 +1,153 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.support.annotation.NonNull; + +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +/** + * Annotation is an overlay on top of a Map. + *

+ * Known subclasses are {@link Polygon}, {@link Polyline} and {@link Marker}. + *

+ *

+ * This class manages attachment to a map and identification, but does not require + * content to be placed at a geographical point. + *

+ * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public abstract class Annotation implements Comparable { + + /** + *

+ * The annotation id + *

+ * Internal C++ id is stored as unsigned int. + */ + private long id = -1; // -1 unless added to a MapView + protected MapboxMap mapboxMap; + protected MapView mapView; + + protected Annotation() { + } + + /** + *

+ * Gets the annotation's unique ID. + *

+ * This ID is unique for a MapView instance and is suitable for associating your own extra + * data with. + * + * @return the assigned id. + */ + public long getId() { + return id; + } + + /** + * Do not use this method, used internally by the SDK. + */ + public void remove() { + if (mapboxMap == null) { + return; + } + mapboxMap.removeAnnotation(this); + } + + /** + * Do not use this method, used internally by the SDK. + * + * @param id the assigned id + */ + public void setId(long id) { + this.id = id; + } + + /** + * Do not use this method, used internally by the SDK. + * + * @param mapboxMap the hosting mapbox map + */ + public void setMapboxMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } + + /** + * Gets the hosting mapbox map. + * + * @return the MapboxMap + */ + protected MapboxMap getMapboxMap() { + return mapboxMap; + } + + /** + * Do not use this method, used internally by the SDK. + * + * @param mapView the hosting map view + */ + public void setMapView(MapView mapView) { + this.mapView = mapView; + } + + /** + * Gets the hosting map view. + * + * @return The MapView + */ + protected MapView getMapView() { + return mapView; + } + + /** + * Compares this Annotation object with another Annotation. + * + * @param annotation Another Annotation to compare with this object. + * @return returns 0 if id's match, 1 if id is lower, -1 if id is higher of another Annotation + */ + @Override + public int compareTo(@NonNull Annotation annotation) { + if (id < annotation.getId()) { + return 1; + } else if (id > annotation.getId()) { + return -1; + } + return 0; + } + + /** + * Checks if this Annotation object is equal to another Annotation. + * + * @param object Another Annotation to check equality with this object. + * @return returns true both id's match else returns false. + */ + @Override + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } + if (object == null || !(object instanceof Annotation)) { + return false; + } + Annotation that = (Annotation) object; + return id == that.getId(); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + return (int) (getId() ^ (getId() >>> 32)); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java new file mode 100644 index 000000000..220544815 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Deprecated +class ArrowDirection { + @IntDef( {LEFT, RIGHT, TOP, BOTTOM}) + @Retention(RetentionPolicy.SOURCE) + @interface Value { + } + + static final int LEFT = 0; + static final int RIGHT = 1; + static final int TOP = 2; + static final int BOTTOM = 3; + + @Value + private final int value; + + ArrowDirection(@Value int value) { + this.value = value; + } + + @Value + public int getValue() { + return value; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java new file mode 100644 index 000000000..384ff8c0a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java @@ -0,0 +1,124 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.geometry.LatLng; + +/** + * Abstract builder class for composing custom Marker objects. + *

+ * Extending this class requires implementing Parceable interface. + * + * @param Type of the marker to be composed + * @param Type of the builder to be used for composing a custom Marker + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public abstract class BaseMarkerOptions> implements Parcelable { + + protected LatLng position; + protected String snippet; + protected String title; + protected Icon icon; + + /** + * Set the geographical location of the Marker. + * + * @param position the location to position the {@link Marker}. + * @return the object for which the method was called. + */ + public T position(LatLng position) { + this.position = position; + return getThis(); + } + + /** + * Set the snippet of the Marker. + * + * @param snippet the snippet of the {@link Marker}. + * @return the object for which the method was called. + */ + public T snippet(String snippet) { + this.snippet = snippet; + return getThis(); + } + + /** + * Set the title of the Marker. + * + * @param title the title of the {@link Marker}. + * @return the object for which the method was called. + */ + public T title(String title) { + this.title = title; + return getThis(); + } + + /** + * Set the icon of the Marker. + * + * @param icon the icon of the {@link Marker}. + * @return the object for which the method was called. + */ + public T icon(Icon icon) { + this.icon = icon; + return getThis(); + } + + /** + * Set the icon of the Marker. + * + * @param icon the icon of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setIcon(Icon icon) { + return icon(icon); + } + + /** + * Set the geographical location of the Marker. + * + * @param position the location to position the {@link Marker}. + * @return the object for which the method was called. + */ + public T setPosition(LatLng position) { + return position(position); + } + + /** + * Set the snippet of the Marker. + * + * @param snippet the snippet of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setSnippet(String snippet) { + return snippet(snippet); + } + + /** + * Set the title of the Marker. + * + * @param title the title of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setTitle(String title) { + return title(title); + } + + /** + * Get the instance of the object for which this method was called. + * + * @return the object for which the this method was called. + */ + public abstract T getThis(); + + /** + * Get the Marker. + * + * @return the Marker created from this builder. + */ + public abstract U getMarker(); + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java new file mode 100644 index 000000000..b94721a80 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java @@ -0,0 +1,82 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.support.annotation.Keep; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +/** + * Multipoint is an abstract annotation for combining geographical locations. + * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public abstract class BasePointCollection extends Annotation { + + @Keep + private List points; + @Keep + private float alpha = 1.0f; + + protected BasePointCollection() { + super(); + points = new ArrayList<>(); + } + + /** + * Returns a copy of the points. + * + * @return A {@link List} of points. + */ + @NonNull + public List getPoints() { + return new ArrayList<>(points); + } + + /** + * Sets the points of this polyline. This method will take a copy of the points, so further + * mutations to points will have no effect on this polyline. + * + * @param points A {@link List} of {@link LatLng} points making up the polyline. + */ + public void setPoints(@NonNull List points) { + this.points = new ArrayList<>(points); + update(); + } + + /** + * Add a point to the polyline. + * + * @param point A {@link LatLng} point to be added. + */ + public void addPoint(LatLng point) { + points.add(point); + update(); + } + + /** + * Value between 0 and 1 defining the polyline alpha. + * + * @return float value between 0 and 1. + */ + public float getAlpha() { + return alpha; + } + + /** + * Set this {@link BasePointCollection}s alpha. + * + * @param alpha float value between 0 and 1. + */ + public void setAlpha(float alpha) { + this.alpha = alpha; + update(); + } + + abstract void update(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java new file mode 100644 index 000000000..0768f9c2e --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java @@ -0,0 +1,315 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; + +@Deprecated +class Bubble extends Drawable { + + private RectF rect; + private float arrowWidth; + private float arrowHeight; + private float arrowPosition; + private float cornersRadius; + @NonNull + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private float strokeWidth; + private Paint strokePaint; + private Path strokePath; + @NonNull + private Path path = new Path(); + + Bubble(@NonNull RectF rect, @NonNull ArrowDirection arrowDirection, float arrowWidth, float arrowHeight, + float arrowPosition, float cornersRadius, int bubbleColor, float strokeWidth, int strokeColor) { + this.rect = rect; + this.arrowWidth = arrowWidth; + this.arrowHeight = arrowHeight; + this.arrowPosition = arrowPosition; + this.cornersRadius = cornersRadius; + paint.setColor(bubbleColor); + this.strokeWidth = strokeWidth; + + if (strokeWidth > 0) { + strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + strokePaint.setColor(strokeColor); + strokePath = new Path(); + initPath(arrowDirection, path, strokeWidth); + initPath(arrowDirection, strokePath, 0); + } else { + initPath(arrowDirection, path, 0); + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (strokeWidth > 0) { + canvas.drawPath(strokePath, strokePaint); + } + canvas.drawPath(path, paint); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + paint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + paint.setColorFilter(cf); + } + + @Override + public int getIntrinsicWidth() { + return (int) rect.width(); + } + + @Override + public int getIntrinsicHeight() { + return (int) rect.height(); + } + + private void initPath(@NonNull ArrowDirection arrowDirection, @NonNull Path path, float strokeWidth) { + switch (arrowDirection.getValue()) { + case ArrowDirection.LEFT: + if (cornersRadius <= 0) { + initLeftSquarePath(rect, path, strokeWidth); + break; + } + + if (strokeWidth > 0 && strokeWidth > cornersRadius) { + initLeftSquarePath(rect, path, strokeWidth); + break; + } + + initLeftRoundedPath(rect, path, strokeWidth); + break; + case ArrowDirection.TOP: + if (cornersRadius <= 0) { + initTopSquarePath(rect, path, strokeWidth); + break; + } + + if (strokeWidth > 0 && strokeWidth > cornersRadius) { + initTopSquarePath(rect, path, strokeWidth); + break; + } + + initTopRoundedPath(rect, path, strokeWidth); + break; + case ArrowDirection.RIGHT: + if (cornersRadius <= 0) { + initRightSquarePath(rect, path, strokeWidth); + break; + } + + if (strokeWidth > 0 && strokeWidth > cornersRadius) { + initRightSquarePath(rect, path, strokeWidth); + break; + } + + initRightRoundedPath(rect, path, strokeWidth); + break; + case ArrowDirection.BOTTOM: + if (cornersRadius <= 0) { + initBottomSquarePath(rect, path, strokeWidth); + break; + } + + if (strokeWidth > 0 && strokeWidth > cornersRadius) { + initBottomSquarePath(rect, path, strokeWidth); + break; + } + + initBottomRoundedPath(rect, path, strokeWidth); + break; + } + } + + private void initLeftSquarePath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(arrowWidth + rect.left + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.width() - strokeWidth, rect.top + strokeWidth); + + path.lineTo(rect.right - strokeWidth, rect.bottom - strokeWidth); + + path.lineTo(rect.left + arrowWidth + strokeWidth, rect.bottom - strokeWidth); + + path.lineTo(rect.left + arrowWidth + strokeWidth, arrowHeight + arrowPosition - (strokeWidth / 2)); + path.lineTo(rect.left + strokeWidth + strokeWidth, arrowPosition + arrowHeight / 2); + path.lineTo(rect.left + arrowWidth + strokeWidth, arrowPosition + (strokeWidth / 2)); + + path.lineTo(rect.left + arrowWidth + strokeWidth, rect.top + strokeWidth); + + path.close(); + } + + private void initLeftRoundedPath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(arrowWidth + rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.width() - cornersRadius - strokeWidth, rect.top + strokeWidth); + path.arcTo(new RectF(rect.right - cornersRadius, rect.top + strokeWidth, rect.right - strokeWidth, + cornersRadius + rect.top), 270, 90); + + path.lineTo(rect.right - strokeWidth, rect.bottom - cornersRadius - strokeWidth); + path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius, + rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90); + + path.lineTo(rect.left + arrowWidth + cornersRadius + strokeWidth, rect.bottom - strokeWidth); + + path.arcTo(new RectF(rect.left + arrowWidth + strokeWidth, rect.bottom - cornersRadius, + cornersRadius + rect.left + arrowWidth, rect.bottom - strokeWidth), 90, 90); + + path.lineTo(rect.left + arrowWidth + strokeWidth, arrowHeight + arrowPosition - (strokeWidth / 2)); + + path.lineTo(rect.left + strokeWidth + strokeWidth, arrowPosition + arrowHeight / 2); + + path.lineTo(rect.left + arrowWidth + strokeWidth, arrowPosition + (strokeWidth / 2)); + + path.lineTo(rect.left + arrowWidth + strokeWidth, rect.top + cornersRadius + strokeWidth); + + path.arcTo(new RectF(rect.left + arrowWidth + strokeWidth, rect.top + strokeWidth, cornersRadius + + rect.left + arrowWidth, cornersRadius + rect.top), 180, 90); + + path.close(); + } + + private void initTopSquarePath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + arrowPosition + strokeWidth, rect.top + arrowHeight + strokeWidth); + + path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.top + arrowHeight + strokeWidth); + path.lineTo(rect.left + arrowWidth / 2 + arrowPosition, rect.top + strokeWidth + strokeWidth); + path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.top + arrowHeight + strokeWidth); + path.lineTo(rect.right - strokeWidth, rect.top + arrowHeight + strokeWidth); + + path.lineTo(rect.right - strokeWidth, rect.bottom - strokeWidth); + + path.lineTo(rect.left + strokeWidth, rect.bottom - strokeWidth); + + path.lineTo(rect.left + strokeWidth, rect.top + arrowHeight + strokeWidth); + + path.lineTo(rect.left + arrowPosition + strokeWidth, rect.top + arrowHeight + strokeWidth); + + path.close(); + } + + private void initTopRoundedPath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + Math.min(arrowPosition, cornersRadius) + strokeWidth, rect.top + arrowHeight + + strokeWidth); + path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.top + arrowHeight + strokeWidth); + path.lineTo(rect.left + arrowWidth / 2 + arrowPosition, rect.top + strokeWidth + strokeWidth); + path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.top + arrowHeight + strokeWidth); + path.lineTo(rect.right - cornersRadius - strokeWidth, rect.top + arrowHeight + strokeWidth); + + path.arcTo(new RectF(rect.right - cornersRadius, + rect.top + arrowHeight + strokeWidth, rect.right - strokeWidth, cornersRadius + rect.top + arrowHeight), + 270, 90); + path.lineTo(rect.right - strokeWidth, rect.bottom - cornersRadius - strokeWidth); + + path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius, + rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90); + path.lineTo(rect.left + cornersRadius + strokeWidth, rect.bottom - strokeWidth); + + path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius, + cornersRadius + rect.left, rect.bottom - strokeWidth), 90, 90); + + path.lineTo(rect.left + strokeWidth, rect.top + arrowHeight + cornersRadius + strokeWidth); + + path.arcTo(new RectF(rect.left + strokeWidth, rect.top + arrowHeight + strokeWidth, cornersRadius + + rect.left, cornersRadius + rect.top + arrowHeight), 180, 90); + + path.close(); + } + + private void initRightSquarePath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.width() - arrowWidth - strokeWidth, rect.top + strokeWidth); + + path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + (strokeWidth / 2)); + path.lineTo(rect.right - strokeWidth - strokeWidth, arrowPosition + arrowHeight / 2); + path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + arrowHeight - (strokeWidth / 2)); + + path.lineTo(rect.right - arrowWidth - strokeWidth, rect.bottom - strokeWidth); + + path.lineTo(rect.left + strokeWidth, rect.bottom - strokeWidth); + path.lineTo(rect.left + strokeWidth, rect.top + strokeWidth); + + path.close(); + } + + private void initRightRoundedPath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.width() - cornersRadius - arrowWidth - strokeWidth, rect.top + strokeWidth); + path.arcTo(new RectF(rect.right - cornersRadius - arrowWidth, + rect.top + strokeWidth, rect.right - arrowWidth - strokeWidth, cornersRadius + rect.top), 270, 90); + + path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + (strokeWidth / 2)); + path.lineTo(rect.right - strokeWidth - strokeWidth, arrowPosition + arrowHeight / 2); + path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + arrowHeight - (strokeWidth / 2)); + path.lineTo(rect.right - arrowWidth - strokeWidth, rect.bottom - cornersRadius - strokeWidth); + + path.arcTo(new RectF(rect.right - cornersRadius - arrowWidth, rect.bottom - cornersRadius, + rect.right - arrowWidth - strokeWidth, rect.bottom - strokeWidth), 0, 90); + path.lineTo(rect.left + arrowWidth + strokeWidth, rect.bottom - strokeWidth); + + path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius, + cornersRadius + rect.left, rect.bottom - strokeWidth), 90, 90); + + path.arcTo(new RectF(rect.left + strokeWidth, rect.top + strokeWidth, cornersRadius + + rect.left, cornersRadius + rect.top), 180, 90); + path.close(); + } + + private void initBottomSquarePath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.right - strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.right - strokeWidth, rect.bottom - arrowHeight - strokeWidth); + + path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth); + path.lineTo(rect.left + arrowPosition + arrowWidth / 2, rect.bottom - strokeWidth - strokeWidth); + path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth); + path.lineTo(rect.left + arrowPosition + strokeWidth, rect.bottom - arrowHeight - strokeWidth); + + path.lineTo(rect.left + strokeWidth, rect.bottom - arrowHeight - strokeWidth); + path.lineTo(rect.left + strokeWidth, rect.top + strokeWidth); + path.close(); + } + + private void initBottomRoundedPath(@NonNull RectF rect, @NonNull Path path, float strokeWidth) { + path.moveTo(rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth); + path.lineTo(rect.width() - cornersRadius - strokeWidth, rect.top + strokeWidth); + path.arcTo(new RectF(rect.right - cornersRadius, + rect.top + strokeWidth, rect.right - strokeWidth, cornersRadius + rect.top), 270, 90); + + path.lineTo(rect.right - strokeWidth, rect.bottom - arrowHeight - cornersRadius - strokeWidth); + path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius - arrowHeight, + rect.right - strokeWidth, rect.bottom - arrowHeight - strokeWidth), 0, 90); + + path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth); + path.lineTo(rect.left + arrowPosition + arrowWidth / 2, rect.bottom - strokeWidth - strokeWidth); + path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth); + path.lineTo(rect.left + Math.min(cornersRadius, arrowPosition) + strokeWidth, rect.bottom - arrowHeight + - strokeWidth); + + path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius - arrowHeight, + cornersRadius + rect.left, rect.bottom - arrowHeight - strokeWidth), 90, 90); + path.lineTo(rect.left + strokeWidth, rect.top + cornersRadius + strokeWidth); + path.arcTo(new RectF(rect.left + strokeWidth, rect.top + strokeWidth, cornersRadius + + rect.left, cornersRadius + rect.top), 180, 90); + path.close(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java new file mode 100644 index 000000000..f4a1484f8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java @@ -0,0 +1,350 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.RectF; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.widget.LinearLayout; + +import com.mapbox.mapboxsdk.R; + +/** + * Bubble View for Android with custom stroke width and color, arrow size, position and direction. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public class BubbleLayout extends LinearLayout { + + public static final float DEFAULT_STROKE_WIDTH = -1; + private ArrowDirection arrowDirection; + private float arrowWidth; + private float arrowHeight; + private float arrowPosition; + private float cornersRadius; + private Bubble bubble; + private int bubbleColor; + private float strokeWidth; + private int strokeColor; + + /** + * Creates an instance of bubble layout. + * + * @param context The context used to inflate this bubble layout + */ + public BubbleLayout(@NonNull 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(@NonNull 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(@NonNull Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.mapbox_BubbleLayout); + @ArrowDirection.Value + int location = a.getInt(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowDirection, + ArrowDirection.LEFT); + arrowDirection = new ArrowDirection(location); + arrowWidth = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowWidth, + convertDpToPixel(8, context)); + arrowHeight = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowHeight, + convertDpToPixel(8, context)); + arrowPosition = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowPosition, + convertDpToPixel(12, context)); + cornersRadius = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_cornersRadius, 0); + bubbleColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_bubbleColor, Color.WHITE); + strokeWidth = + a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeWidth, DEFAULT_STROKE_WIDTH); + strokeColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeColor, Color.GRAY); + + a.recycle(); + initPadding(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + initDrawable(0, getWidth(), 0, getHeight()); + } + + @Override + protected void dispatchDraw(@NonNull Canvas canvas) { + if (bubble != null) { + bubble.draw(canvas); + } + super.dispatchDraw(canvas); + } + + static float convertDpToPixel(float dp, Context context) { + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + 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 + */ + @NonNull + public BubbleLayout setArrowDirection(ArrowDirection arrowDirection) { + resetPadding(); + this.arrowDirection = arrowDirection; + initPadding(); + 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 + */ + @NonNull + public BubbleLayout setArrowWidth(float arrowWidth) { + resetPadding(); + this.arrowWidth = arrowWidth; + initPadding(); + 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 + */ + @NonNull + public BubbleLayout setArrowHeight(float arrowHeight) { + resetPadding(); + this.arrowHeight = arrowHeight; + initPadding(); + 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 + */ + @NonNull + public BubbleLayout setArrowPosition(float arrowPosition) { + resetPadding(); + this.arrowPosition = arrowPosition; + initPadding(); + 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 + */ + @NonNull + 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 + */ + @NonNull + 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 + */ + @NonNull + public BubbleLayout setStrokeWidth(float strokeWidth) { + resetPadding(); + this.strokeWidth = strokeWidth; + initPadding(); + 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 + */ + @NonNull + public BubbleLayout setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + requestLayout(); + return this; + } + + private void initPadding() { + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + switch (arrowDirection.getValue()) { + case ArrowDirection.LEFT: + paddingLeft += arrowWidth; + break; + case ArrowDirection.RIGHT: + paddingRight += arrowWidth; + break; + case ArrowDirection.TOP: + paddingTop += arrowHeight; + break; + case ArrowDirection.BOTTOM: + paddingBottom += arrowHeight; + break; + } + if (strokeWidth > 0) { + paddingLeft += strokeWidth; + paddingRight += strokeWidth; + paddingTop += strokeWidth; + paddingBottom += strokeWidth; + } + setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); + } + + private void initDrawable(int left, int right, int top, int bottom) { + if (right < left || bottom < top) { + return; + } + + RectF rectF = new RectF(left, top, right, bottom); + bubble = new Bubble(rectF, arrowDirection, arrowWidth, arrowHeight, arrowPosition, cornersRadius, + bubbleColor, strokeWidth, strokeColor); + } + + private void resetPadding() { + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + switch (arrowDirection.getValue()) { + case ArrowDirection.LEFT: + paddingLeft -= arrowWidth; + break; + case ArrowDirection.RIGHT: + paddingRight -= arrowWidth; + break; + case ArrowDirection.TOP: + paddingTop -= arrowHeight; + break; + case ArrowDirection.BOTTOM: + paddingBottom -= arrowHeight; + break; + } + if (strokeWidth > 0) { + paddingLeft -= strokeWidth; + paddingRight -= strokeWidth; + paddingTop -= strokeWidth; + paddingBottom -= strokeWidth; + } + setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java new file mode 100644 index 000000000..055bfe536 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java @@ -0,0 +1,35 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.ViewGroup; +import android.widget.PopupWindow; + +import com.mapbox.mapboxsdk.R; + +@Deprecated +class BubblePopupHelper { + + @NonNull + static PopupWindow create(@NonNull Context context, @NonNull BubbleLayout bubbleLayout) { + PopupWindow popupWindow = new PopupWindow(context); + + popupWindow.setContentView(bubbleLayout); + popupWindow.setOutsideTouchable(true); + popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); + popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); + popupWindow.setAnimationStyle(android.R.style.Animation_Dialog); + // change background color to transparent + Drawable drawable; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + drawable = context.getDrawable(R.drawable.mapbox_popup_window_transparent); + } else { + drawable = context.getResources().getDrawable(R.drawable.mapbox_popup_window_transparent); + } + popupWindow.setBackgroundDrawable(drawable); + + return popupWindow; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java new file mode 100644 index 000000000..7ace11350 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java @@ -0,0 +1,124 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Bitmap; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.DisplayMetrics; + +import java.nio.ByteBuffer; + +/** + * Icon is the visual representation of a Marker on a MapView. + * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public class Icon { + + private Bitmap mBitmap; + private String mId; + + Icon(String id, Bitmap bitmap) { + mId = id; + mBitmap = bitmap; + } + + /** + * String identifier for this icon. + * + * @return String identifier for this icon. + */ + public String getId() { + return mId; + } + + /** + * Get the bitmap being used for this icon. + * + * @return The bitmap being used for the icon. + */ + public Bitmap getBitmap() { + if (mBitmap != null && mBitmap.getConfig() != Bitmap.Config.ARGB_8888) { + mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false); + } + return mBitmap; + } + + /** + * Get the icon bitmap scale. + *

+ * Requires the bitmap to be set before calling this method. + *

+ * + * @return the scale of the bitmap + */ + public float getScale() { + if (mBitmap == null) { + throw new IllegalStateException("Required to set a Icon before calling getScale"); + } + float density = mBitmap.getDensity(); + if (density == Bitmap.DENSITY_NONE) { + density = DisplayMetrics.DENSITY_DEFAULT; + } + return density / DisplayMetrics.DENSITY_DEFAULT; + } + + /** + * Get the icon bitmap bytes. + *

+ * Requires the bitmap to be set before calling this method. + *

+ * + * @return the bytes of the bitmap + */ + @NonNull + public byte[] toBytes() { + if (mBitmap == null) { + throw new IllegalStateException("Required to set a Icon before calling toBytes"); + } + ByteBuffer buffer = ByteBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight()); + mBitmap.copyPixelsToBuffer(buffer); + return buffer.array(); + } + + /** + * Compares this icon object with another icon and determines if they match. + * + * @param object Another iconi to compare with this object. + * @return True if the icon being passed in matches this icon object. Else, false. + */ + @Override + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + Icon icon = (Icon) object; + return mBitmap.equals(icon.mBitmap) && mId.equals(icon.mId); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 0; + if (mBitmap != null) { + result = mBitmap.hashCode(); + } + if (mId != null) { + result = 31 * result + mId.hashCode(); + } + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java new file mode 100644 index 000000000..9f0fa62cd --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java @@ -0,0 +1,188 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.util.DisplayMetrics; +import android.view.WindowManager; + +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.exceptions.TooManyIconsException; +import com.mapbox.mapboxsdk.utils.BitmapUtils; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Factory for creating Icons from bitmap images. + *

+ * icon is used to display bitmaps on top of the map using {@link Marker}. + *

+ * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class IconFactory { + + private static final String ICON_ID_PREFIX = "com.mapbox.icons.icon_"; + + private Context context; + @SuppressLint("StaticFieldLeak") + private static IconFactory instance; + private Icon defaultMarker; + private BitmapFactory.Options options; + + 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()); + } + return instance; + } + + private IconFactory(@NonNull Context context) { + this.context = context; + DisplayMetrics realMetrics = null; + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + realMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getRealMetrics(realMetrics); + } + wm.getDefaultDisplay().getMetrics(metrics); + + options = new BitmapFactory.Options(); + options.inScaled = true; + options.inDensity = DisplayMetrics.DENSITY_DEFAULT; + options.inTargetDensity = metrics.densityDpi; + if (realMetrics != null) { + options.inScreenDensity = realMetrics.densityDpi; + } + } + + /** + * Creates an icon from a given Bitmap image. + * + * @param bitmap image used for creating the Icon. + * @return The icon using the given Bitmap image. + */ + public Icon fromBitmap(@NonNull Bitmap bitmap) { + if (nextId < 0) { + throw new TooManyIconsException(); + } + String id = ICON_ID_PREFIX + ++nextId; + return new Icon(id, bitmap); + } + + /** + * Creates an icon using the resource ID of a Bitmap image. + * + * @param resourceId The resource ID of a Bitmap image. + * @return The icon that was loaded from the asset or {@code null} if failed to load. + */ + public Icon fromResource(@DrawableRes int resourceId) { + Drawable drawable = BitmapUtils.getDrawableFromRes(context, resourceId); + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + return fromBitmap(bitmapDrawable.getBitmap()); + } else { + throw new IllegalArgumentException("Failed to decode image. The resource provided must be a Bitmap."); + } + } + + /** + * Provides an icon using the default marker icon used for {@link Marker}. + * + * @return An icon with the default {@link Marker} icon. + */ + public Icon defaultMarker() { + if (defaultMarker == null) { + defaultMarker = fromResource(R.drawable.mapbox_marker_icon_default); + } + return defaultMarker; + } + + private Icon fromInputStream(@NonNull InputStream is) { + Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); + return fromBitmap(bitmap); + } + + /** + * 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 Icon that was loaded from the asset or null if failed to load. + */ + public Icon fromAsset(@NonNull String assetName) { + InputStream is; + try { + is = context.getAssets().open(assetName); + } catch (IOException ioException) { + MapStrictMode.strictModeViolation(ioException); + return null; + } + return fromInputStream(is); + } + + /** + * Creates an Icon using the absolute file path of a Bitmap image. + * + * @param absolutePath The absolute path of the Bitmap image. + * @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); + return fromBitmap(bitmap); + } + + /** + * 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 Icon that was loaded from the asset or null if failed to load. + * @see + * Using the Internal Storage + */ + public Icon fromFile(@NonNull String fileName) { + FileInputStream is; + try { + is = context.openFileInput(fileName); + } catch (FileNotFoundException fileNotFoundException) { + MapStrictMode.strictModeViolation(fileNotFoundException); + return null; + } + return fromInputStream(is); + } + + /** + * Create an Icon using a previously created icon identifier along with a provided Bitmap. + * + * @param iconId The Icon identifier you'd like to recreate. + * @param bitmap a Bitmap used to replace the current one. + * @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/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java new file mode 100644 index 000000000..5bd9aaef1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -0,0 +1,351 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.content.res.Resources; +import android.graphics.PointF; +import android.os.Build; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.TextView; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +import java.lang.ref.WeakReference; + +/** + * {@code InfoWindow} is a tooltip shown when a {@link Marker} is tapped. Only + * one info window is displayed at a time. When the user clicks on a marker, the currently open info + * window will be closed and the new info window will be displayed. If the user clicks the same + * marker while its info window is currently open, the info window will be closed. + *

+ * The info window is drawn oriented against the device's screen, centered above its associated + * marker by default. The default info window contains the title in bold and snippet text below the title. + * While either the title and + * snippet are optional, at least one is required to open the info window. + *

+ * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public class InfoWindow { + + private WeakReference boundMarker; + private WeakReference mapboxMap; + protected WeakReference view; + + private float markerHeightOffset; + private float markerWidthOffset; + private float viewWidthOffset; + private float viewHeightOffset; + private PointF coordinates; + private boolean isVisible; + + @LayoutRes + private int layoutRes; + + InfoWindow(MapView mapView, int layoutResId, MapboxMap mapboxMap) { + layoutRes = layoutResId; + View view = LayoutInflater.from(mapView.getContext()).inflate(layoutResId, mapView, false); + initialize(view, mapboxMap); + } + + InfoWindow(@NonNull View view, MapboxMap mapboxMap) { + initialize(view, mapboxMap); + } + + private void initialize(@NonNull View view, MapboxMap mapboxMap) { + this.mapboxMap = new WeakReference<>(mapboxMap); + isVisible = false; + this.view = new WeakReference<>(view); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MapboxMap mapboxMap = InfoWindow.this.mapboxMap.get(); + if (mapboxMap != null) { + MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener = mapboxMap.getOnInfoWindowClickListener(); + boolean handledDefaultClick = false; + if (onInfoWindowClickListener != null) { + handledDefaultClick = onInfoWindowClickListener.onInfoWindowClick(getBoundMarker()); + } + + if (!handledDefaultClick) { + // default behavior: close it when clicking on the tooltip: + closeInfoWindow(); + } + } + } + }); + + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + MapboxMap mapboxMap = InfoWindow.this.mapboxMap.get(); + if (mapboxMap != null) { + MapboxMap.OnInfoWindowLongClickListener listener = mapboxMap.getOnInfoWindowLongClickListener(); + if (listener != null) { + listener.onInfoWindowLongClick(getBoundMarker()); + } + } + return true; + } + }); + } + + private void closeInfoWindow() { + MapboxMap mapbox = mapboxMap.get(); + Marker marker = boundMarker.get(); + if (marker != null && mapbox != null) { + mapbox.deselectMarker(marker); + } + close(); + } + + /** + * Open the info window at the specified position. + * + * @param boundMarker The marker on which is hooked the view. + * @param position to place the window on the map. + * @param offsetX The offset of the view to the position, in pixels. This allows to offset + * the view from the object position. + * @param offsetY The offset of the view to the position, in pixels. This allows to offset + * the view from the object position. + * @return this {@link InfoWindow}. + */ + @NonNull + InfoWindow open(@NonNull MapView mapView, Marker boundMarker, @NonNull LatLng position, int offsetX, int offsetY) { + setBoundMarker(boundMarker); + + MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, + MapView.LayoutParams.WRAP_CONTENT); + + MapboxMap mapboxMap = this.mapboxMap.get(); + View view = this.view.get(); + if (view != null && mapboxMap != null) { + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + + markerHeightOffset = offsetY; + markerWidthOffset = -offsetX; + + // Calculate default Android x,y coordinate + coordinates = mapboxMap.getProjection().toScreenLocation(position); + float x = coordinates.x - (view.getMeasuredWidth() / 2) + offsetX; + float y = coordinates.y - view.getMeasuredHeight() + offsetY; + + if (view instanceof BubbleLayout) { + // only apply repositioning/margin for InfoWindowView + Resources resources = mapView.getContext().getResources(); + + // get right/left popup window + float rightSideInfowWindow = x + view.getMeasuredWidth(); + float leftSideInfoWindow = x; + + // get right/left map view + final float mapRight = mapView.getRight(); + final float mapLeft = mapView.getLeft(); + + float marginHorizontal = resources.getDimension(R.dimen.mapbox_infowindow_margin); + float tipViewOffset = resources.getDimension(R.dimen.mapbox_infowindow_tipview_width) / 2; + float tipViewMarginLeft = view.getMeasuredWidth() / 2 - tipViewOffset; + + boolean outOfBoundsLeft = false; + boolean outOfBoundsRight = false; + + // only optimise margins if view is inside current viewport + if (coordinates.x >= 0 && coordinates.x <= mapView.getWidth() + && coordinates.y >= 0 && coordinates.y <= mapView.getHeight()) { + + // if out of bounds right + if (rightSideInfowWindow > mapRight) { + outOfBoundsRight = true; + x -= rightSideInfowWindow - mapRight; + tipViewMarginLeft += rightSideInfowWindow - mapRight + tipViewOffset; + rightSideInfowWindow = x + view.getMeasuredWidth(); + } + + // fit screen left + if (leftSideInfoWindow < mapLeft) { + outOfBoundsLeft = true; + x += mapLeft - leftSideInfoWindow; + tipViewMarginLeft -= mapLeft - leftSideInfoWindow + tipViewOffset; + leftSideInfoWindow = x; + } + + // Add margin right + if (outOfBoundsRight && mapRight - rightSideInfowWindow < marginHorizontal) { + x -= marginHorizontal - (mapRight - rightSideInfowWindow); + tipViewMarginLeft += marginHorizontal - (mapRight - rightSideInfowWindow) - tipViewOffset; + leftSideInfoWindow = x; + } + + // Add margin left + if (outOfBoundsLeft && leftSideInfoWindow - mapLeft < marginHorizontal) { + x += marginHorizontal - (leftSideInfoWindow - mapLeft); + tipViewMarginLeft -= (marginHorizontal - (leftSideInfoWindow - mapLeft)) - tipViewOffset; + } + } + + // Adjust tipView + ((BubbleLayout) view).setArrowPosition(tipViewMarginLeft); + } + + // set anchor popupwindowview + view.setX(x); + view.setY(y); + + // Calculate x-offset and y-offset for update method + viewWidthOffset = x - coordinates.x - offsetX; + viewHeightOffset = -view.getMeasuredHeight() + offsetY; + + + close(); // if it was already opened + mapView.addView(view, lp); + isVisible = true; + } + return this; + } + + /** + * Close this {@link InfoWindow} if it is visible, otherwise calling this will do nothing. + * + * @return This {@link InfoWindow} + */ + @NonNull + InfoWindow close() { + MapboxMap mapboxMap = this.mapboxMap.get(); + if (isVisible && mapboxMap != null) { + isVisible = false; + View view = this.view.get(); + if (view != null && view.getParent() != null) { + ((ViewGroup) view.getParent()).removeView(view); + } + + Marker marker = getBoundMarker(); + MapboxMap.OnInfoWindowCloseListener listener = mapboxMap.getOnInfoWindowCloseListener(); + if (listener != null) { + listener.onInfoWindowClose(marker); + } + + setBoundMarker(null); + } + return this; + } + + /** + * Constructs the view that is displayed when the InfoWindow opens. This retrieves data from + * overlayItem and shows it in the tooltip. + * + * @param overlayItem the tapped overlay item + */ + void adaptDefaultMarker(@NonNull Marker overlayItem, MapboxMap mapboxMap, @NonNull MapView mapView) { + View view = this.view.get(); + if (view == null) { + view = LayoutInflater.from(mapView.getContext()).inflate(layoutRes, mapView, false); + initialize(view, mapboxMap); + } + this.mapboxMap = new WeakReference<>(mapboxMap); + String title = overlayItem.getTitle(); + TextView titleTextView = ((TextView) view.findViewById(R.id.infowindow_title)); + if (!TextUtils.isEmpty(title)) { + titleTextView.setText(title); + titleTextView.setVisibility(View.VISIBLE); + } else { + titleTextView.setVisibility(View.GONE); + } + + String snippet = overlayItem.getSnippet(); + TextView snippetTextView = ((TextView) view.findViewById(R.id.infowindow_description)); + if (!TextUtils.isEmpty(snippet)) { + snippetTextView.setText(snippet); + snippetTextView.setVisibility(View.VISIBLE); + } else { + snippetTextView.setVisibility(View.GONE); + } + } + + @NonNull + InfoWindow setBoundMarker(Marker boundMarker) { + this.boundMarker = new WeakReference<>(boundMarker); + return this; + } + + @Nullable + Marker getBoundMarker() { + if (boundMarker == null) { + return null; + } + return boundMarker.get(); + } + + /** + * Will result in getting this {@link InfoWindow} and updating the view being displayed. + */ + public void update() { + MapboxMap mapboxMap = this.mapboxMap.get(); + Marker marker = boundMarker.get(); + View view = this.view.get(); + if (mapboxMap != null && marker != null && view != null) { + coordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + + if (view instanceof BubbleLayout) { + view.setX(coordinates.x + viewWidthOffset - markerWidthOffset); + } else { + view.setX(coordinates.x - (view.getMeasuredWidth() / 2) - markerWidthOffset); + } + view.setY(coordinates.y + viewHeightOffset); + } + } + + void onContentUpdate() { + //recalculate y-offset and update position + View view = this.view.get(); + if (view != null) { + ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); + if (viewTreeObserver.isAlive()) { + viewTreeObserver.addOnGlobalLayoutListener(contentUpdateListener); + } + } + } + + @Nullable + private final ViewTreeObserver.OnGlobalLayoutListener contentUpdateListener = + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + View view = InfoWindow.this.view.get(); + if (view != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + view.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } else { + view.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + viewHeightOffset = -view.getMeasuredHeight() + markerHeightOffset; + update(); + } + } + }; + + /** + * Retrieve this {@link InfoWindow}'s current view being used. + * + * @return This {@link InfoWindow}'s current View. + */ + @Nullable + public View getView() { + return view != null ? view.get() : null; + } + + boolean isVisible() { + return isVisible; + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java new file mode 100644 index 000000000..c26af9436 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -0,0 +1,278 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.View; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +/** + * Marker is an annotation that shows an icon image at a geographical location. The default marker + * uses a provided icon. This icon can be customized using {@link IconFactory} to generate an + * {@link Icon} using a provided image. Markers are added to the map by first giving a + * {@link LatLng} and using {@link MapboxMap#addMarker(MarkerOptions)}. The marker icon will be + * centered at this position so it is common to add padding to the icon image before usage. + *

+ * Markers are designed to be interactive. They receive click events by default, and are often used + * with event listeners to bring up info windows. An {@link InfoWindow} is displayed by default when + * either a title or snippet is provided. + *

+ * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public class Marker extends Annotation { + + @Keep + private LatLng position; + private String snippet; + @Nullable + private Icon icon; + //Redundantly stored for JNI access + @Nullable + @Keep + private String iconId; + private String title; + + @Nullable + private InfoWindow infoWindow; + private boolean infoWindowShown; + + private int topOffsetPixels; + private int rightOffsetPixels; + + /** + * Constructor + */ + Marker() { + super(); + } + + /** + * Creates a instance of {@link Marker} using the builder of Marker. + * + * @param baseMarkerOptions The builder used to construct the Marker. + */ + public Marker(BaseMarkerOptions baseMarkerOptions) { + this(baseMarkerOptions.position, baseMarkerOptions.icon, baseMarkerOptions.title, baseMarkerOptions.snippet); + } + + Marker(LatLng position, Icon icon, String title, String snippet) { + this.position = position; + this.title = title; + this.snippet = snippet; + setIcon(icon); + } + + /** + * Returns the position of the marker. + * + * @return A {@link LatLng} object specifying the marker's current position. + */ + public LatLng getPosition() { + return position; + } + + /** + * Gets the snippet of the marker. + * + * @return A string containing the marker's snippet. + */ + public String getSnippet() { + return snippet; + } + + /** + * Gets the snippet of the marker. + * + * @return A string containing the marker's snippet. + */ + public String getTitle() { + return title; + } + + /** + * Do not use this method, used internally by the SDK. + */ + public void hideInfoWindow() { + if (infoWindow != null) { + infoWindow.close(); + } + infoWindowShown = false; + } + + /** + * Do not use this method, used internally by the SDK. + * + * @return true if the infoWindow is shown + */ + public boolean isInfoWindowShown() { + return infoWindowShown; + } + + /** + * Sets the location of the marker. + * + * @param position A {@link LatLng} defining the marker position. + */ + public void setPosition(LatLng position) { + this.position = position; + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); + } + } + + /** + * Sets the snippet of the marker. + * + * @param snippet A String used in the marker info window. If {@code null}, the snippet is + * cleared. + */ + public void setSnippet(String snippet) { + this.snippet = snippet; + refreshInfoWindowContent(); + } + + /** + * Sets the icon of the marker. + * + * @param icon The {@link Icon} to be used as Marker image + */ + public void setIcon(@Nullable Icon icon) { + this.icon = icon; + this.iconId = icon != null ? icon.getId() : null; + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); + } + } + + /** + * Gets the {@link Icon} currently used for the marker. If no Icon was set for the marker, the + * default icon will be returned. + * + * @return The {@link Icon} the marker is using. + */ + @Nullable + public Icon getIcon() { + return icon; + } + + /** + * Sets the title of the marker. + * + * @param title A String used in the marker info window. If {@code null}, the title is + * cleared. + */ + public void setTitle(String title) { + this.title = title; + refreshInfoWindowContent(); + } + + /** + * Gets the {@link InfoWindow} the marker is using. If the marker hasn't had an info window + * defined, this will return {@code null}. + * + * @return The info window the marker is using. + */ + @Nullable + public InfoWindow getInfoWindow() { + return infoWindow; + } + + /** + * Update only for default Marker's InfoWindow content for Title and Snippet + */ + private void refreshInfoWindowContent() { + if (isInfoWindowShown() && mapView != null && mapboxMap != null && mapboxMap.getInfoWindowAdapter() == null) { + InfoWindow infoWindow = getInfoWindow(mapView); + if (mapView.getContext() != null) { + infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); + } + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); + } + infoWindow.onContentUpdate(); + } + } + + /** + * Do not use this method, used internally by the SDK. Use {@link MapboxMap#selectMarker(Marker)} + * if you want to programmatically display the markers info window. + * + * @param mapboxMap The hosting mapbox map. + * @param mapView The hosting map view. + * @return The info window that was shown. + */ + @Nullable + public InfoWindow showInfoWindow(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) { + setMapboxMap(mapboxMap); + setMapView(mapView); + MapboxMap.InfoWindowAdapter infoWindowAdapter = getMapboxMap().getInfoWindowAdapter(); + if (infoWindowAdapter != null) { + // end developer is using a custom InfoWindowAdapter + View content = infoWindowAdapter.getInfoWindow(this); + if (content != null) { + infoWindow = new InfoWindow(content, mapboxMap); + showInfoWindow(infoWindow, mapView); + return infoWindow; + } + } + + InfoWindow infoWindow = getInfoWindow(mapView); + if (mapView.getContext() != null) { + infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); + } + return showInfoWindow(infoWindow, mapView); + } + + @NonNull + private InfoWindow showInfoWindow(InfoWindow iw, MapView mapView) { + iw.open(mapView, this, getPosition(), rightOffsetPixels, topOffsetPixels); + infoWindowShown = true; + return iw; + } + + @Nullable + private InfoWindow getInfoWindow(@NonNull MapView mapView) { + if (infoWindow == null && mapView.getContext() != null) { + infoWindow = new InfoWindow(mapView, R.layout.mapbox_infowindow_content, getMapboxMap()); + } + return infoWindow; + } + + /** + * Do not use this method, used internally by the SDK. + * + * @param topOffsetPixels the top offset pixels. + */ + public void setTopOffsetPixels(int topOffsetPixels) { + this.topOffsetPixels = topOffsetPixels; + } + + /** + * Do not use this method, used internally by the SDK. + * + * @param rightOffsetPixels the right offset pixels. + */ + public void setRightOffsetPixels(int rightOffsetPixels) { + this.rightOffsetPixels = rightOffsetPixels; + } + + /** + * Returns a String with the marker position. + * + * @return A String with the marker position. + */ + @Override + public String toString() { + return "Marker [position[" + getPosition() + "]]"; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java new file mode 100644 index 000000000..62c3d378e --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java @@ -0,0 +1,195 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; +import com.mapbox.mapboxsdk.geometry.LatLng; + +/** + *

+ * Builder for composing {@link Marker} objects. See {@link Marker} for additional information. + *

+ *

Example

+ *
+ * mapView.addMarker(new MarkerOptions()
+ *   .title("Intersection")
+ *   .snippet("H St NW with 15th St NW")
+ *   .position(new LatLng(38.9002073, -77.03364419)));
+ * 
+ * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class MarkerOptions extends BaseMarkerOptions implements Parcelable { + + /** + * Defines options for a Marker. + */ + public MarkerOptions() { + } + + protected MarkerOptions(Parcel in) { + position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); + snippet(in.readString()); + title(in.readString()); + if (in.readByte() != 0) { + // this means we have an icon + String iconId = in.readString(); + Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader()); + Icon icon = new Icon(iconId, iconBitmap); + icon(icon); + } + } + + @NonNull + @Override + public MarkerOptions getThis() { + return this; + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @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. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(getPosition(), flags); + out.writeString(getSnippet()); + out.writeString(getTitle()); + Icon icon = getIcon(); + out.writeByte((byte) (icon != null ? 1 : 0)); + if (icon != null) { + out.writeString(getIcon().getId()); + out.writeParcelable(getIcon().getBitmap(), flags); + } + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return Marker The build marker + */ + public Marker getMarker() { + if (position == null) { + throw new InvalidMarkerPositionException(); + } + + return new Marker(position, icon, title, snippet); + } + + /** + * Returns the position set for this {@link MarkerOptions} object. + * + * @return A {@link LatLng} object specifying the marker's current position. + */ + public LatLng getPosition() { + return position; + } + + /** + * Gets the snippet set for this {@link MarkerOptions} object. + * + * @return A string containing the marker's snippet. + */ + public String getSnippet() { + return snippet; + } + + /** + * Gets the title set for this {@link MarkerOptions} object. + * + * @return A string containing the marker's title. + */ + public String getTitle() { + return title; + } + + /** + * Gets the custom icon set for this {@link MarkerOptions} object. + * + * @return A {@link Icon} object that the marker is using. If the icon wasn't set, default icon + * will return. + */ + public Icon getIcon() { + return icon; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MarkerOptions createFromParcel(@NonNull Parcel in) { + return new MarkerOptions(in); + } + + public MarkerOptions[] newArray(int size) { + return new MarkerOptions[size]; + } + }; + + /** + * Compares this {@link MarkerOptions} object with another {@link MarkerOptions} and + * determines if their properties match. + * + * @param o Another {@link MarkerOptions} to compare with this object. + * @return True if marker properties match this {@link MarkerOptions} object. + * Else, false. + */ + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MarkerOptions marker = (MarkerOptions) o; + + if (getPosition() != null ? !getPosition().equals(marker.getPosition()) : marker.getPosition() != null) { + return false; + } + if (getSnippet() != null ? !getSnippet().equals(marker.getSnippet()) : marker.getSnippet() != null) { + return false; + } + if (getIcon() != null ? !getIcon().equals(marker.getIcon()) : marker.getIcon() != null) { + return false; + } + return !(getTitle() != null ? !getTitle().equals(marker.getTitle()) : marker.getTitle() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getPosition() != null ? getPosition().hashCode() : 0); + result = 31 * result + (getSnippet() != null ? getSnippet().hashCode() : 0); + result = 31 * result + (getIcon() != null ? getIcon().hashCode() : 0); + result = 31 * result + (getTitle() != null ? getTitle().hashCode() : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java new file mode 100644 index 000000000..5f6cef8d4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java @@ -0,0 +1,109 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Color; +import android.support.annotation.Keep; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +import java.util.ArrayList; +import java.util.List; + +/** + * Polygon is a geometry annotation that's a closed loop of coordinates. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class Polygon extends BasePointCollection { + + @Keep + private int fillColor = Color.BLACK; // default fillColor is black + @Keep + private int strokeColor = Color.BLACK; // default strokeColor is black + @Keep + private List> holes; + + Polygon() { + super(); + holes = new ArrayList<>(); + } + + /** + * Get the color of the fill region of the polygon. + * + * @return The color of the fill. + */ + public int getFillColor() { + return fillColor; + } + + /** + * Get the color of the stroke of the polygon. + * + * @return The color of the stroke. + */ + public int getStrokeColor() { + return strokeColor; + } + + /** + * Returns a copy of the holes. + * + * @return A {@link List} of {@link List} of {@link LatLng} points making up the holes. + */ + public List> getHoles() { + return new ArrayList<>(holes); + } + + /** + * Sets the color of the fill region of the polygon. + * + * @param color The color in ARGB format. + */ + public void setFillColor(int color) { + fillColor = color; + update(); + } + + /** + * Sets the color of the stroke of the polygon. + * + * @param color The color in ARGB format. + */ + public void setStrokeColor(int color) { + strokeColor = color; + update(); + } + + /** + * Sets the holes of this polygon. This method will take a copy of the holes, so further + * mutations to holes will have no effect on this polygon. + * + * @param holes A {@link List} of {@link List} of {@link LatLng} points making up the holes. + */ + public void setHoles(@NonNull List> holes) { + this.holes = new ArrayList<>(holes); + update(); + } + + /** + * Add a hole to the polygon. + * + * @param hole A {@link List} of {@link List} of {@link LatLng} points making up the hole to be added. + */ + void addHole(List hole) { + holes.add(hole); + update(); + } + + @Override + void update() { + MapboxMap mapboxMap = getMapboxMap(); + if (mapboxMap != null) { + mapboxMap.updatePolygon(this); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java new file mode 100644 index 000000000..452420fcb --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java @@ -0,0 +1,308 @@ +package com.mapbox.mapboxsdk.annotations; + + +import android.os.Parcel; +import android.os.Parcelable; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +/** + * Builder for composing {@link Polygon} objects. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class PolygonOptions implements Parcelable { + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PolygonOptions createFromParcel(@NonNull Parcel in) { + return new PolygonOptions(in); + } + + public PolygonOptions[] newArray(int size) { + return new PolygonOptions[size]; + } + }; + + private PolygonOptions(Parcel in) { + polygon = new Polygon(); + List pointsList = new ArrayList<>(); + in.readList(pointsList, LatLng.class.getClassLoader()); + addAll(pointsList); + List> holes = new ArrayList<>(); + in.readList(holes, LatLng.class.getClassLoader()); + addAllHoles(holes); + alpha(in.readFloat()); + fillColor(in.readInt()); + strokeColor(in.readInt()); + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @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. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeList(getPoints()); + out.writeList(getHoles()); + out.writeFloat(getAlpha()); + out.writeInt(getFillColor()); + out.writeInt(getStrokeColor()); + } + + private Polygon polygon; + + /** + * Defines options for a polygon. + */ + public PolygonOptions() { + polygon = new Polygon(); + } + + /** + * Adds a vertex to the outline of the polygon being built. + * + * @param point {@link LatLng} point to be added to polygon geometry. + * @return This {@link PolygonOptions} object with the given point added to the outline. + */ + @NonNull + public PolygonOptions add(LatLng point) { + polygon.addPoint(point); + return this; + } + + /** + * Adds vertices to the outline of the polygon being built. + * + * @param points {@link LatLng} points to be added to polygon geometry. + * @return This {@link PolygonOptions} object with the given points added to the outline. + */ + @NonNull + public PolygonOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Adds vertices to the outline of the polygon being built. + * + * @param points {@link Iterable} list made up of {@link LatLng} points defining the polygon + * geometry + * @return This {@link PolygonOptions} object with the given points added to the outline. + */ + @NonNull + public PolygonOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Adds a hole to the outline of the polygon being built. + * + * @param hole {@link List} list made up of {@link LatLng} points defining the hole + * @return This {@link PolygonOptions} object with the given hole added to the outline. + */ + @NonNull + public PolygonOptions addHole(List hole) { + polygon.addHole(hole); + return this; + } + + /** + * Adds holes to the outline of the polygon being built. + * + * @param holes {@link List} list made up of {@link LatLng} holes to be added to polygon geometry + * @return This {@link PolygonOptions} object with the given holes added to the outline. + */ + @NonNull + public PolygonOptions addHole(List... holes) { + for (List hole : holes) { + addHole(hole); + } + return this; + } + + /** + * Adds holes to the outline of the polygon being built. + * + * @param holes {@link Iterable} list made up of {@link List} list of {@link LatLng} holes defining the hole geometry + * @return This {@link PolygonOptions} object with the given holes added to the outline. + */ + @NonNull + public PolygonOptions addAllHoles(Iterable> holes) { + for (List hole : holes) { + addHole(hole); + } + return this; + } + + /** + * Set the alpha value of the polyline. + * + * @param alpha float value between 0 (not visible) and 1. + * @return This {@link PolygonOptions} object with the given polygon alpha value. + */ + @NonNull + public PolygonOptions alpha(float alpha) { + polygon.setAlpha(alpha); + return this; + } + + /** + * Gets the alpha set for this {@link PolygonOptions} object. + * + * @return float value between 0 and 1 defining the alpha. + */ + public float getAlpha() { + return polygon.getAlpha(); + } + + /** + * Specifies the polygon's fill color, as 32-bit ARGB. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolylineOptions} object with a new color set. + */ + @NonNull + public PolygonOptions fillColor(int color) { + polygon.setFillColor(color); + return this; + } + + /** + * Gets the fill color set for this {@link PolygonOptions} object. + * + * @return The fill color of the polygon in ARGB format. + */ + public int getFillColor() { + return polygon.getFillColor(); + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return Polygon the Polygon to return + */ + public Polygon getPolygon() { + return polygon; + } + + /** + * Specifies the polygon's stroke color, as 32-bit ARGB. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolygonOptions} object with a new stroke color set. + */ + @NonNull + public PolygonOptions strokeColor(int color) { + polygon.setStrokeColor(color); + return this; + } + + /** + * Gets the stroke color set for this {@link PolygonOptions} object. + * + * @return The stroke color of the polygon in ARGB format. + */ + public int getStrokeColor() { + return polygon.getStrokeColor(); + } + + /** + * Gets the points set for this {@link PolygonOptions} object. + * + * @return The list made up of {@link LatLng} points defining the polygon. + */ + public List getPoints() { + // the getter gives us a copy, which is the safe thing to do... + return polygon.getPoints(); + } + + /** + * Gets the holes set for this {@link PolygonOptions} object. + * + * @return The list made up of {@link List} of {@link List} of {@link LatLng} points defining the holes. + */ + public List> getHoles() { + return polygon.getHoles(); + } + + + /** + * Compares this {@link PolygonOptions} object with another {@link PolygonOptions} and + * determines if their color, alpha, stroke color, and vertices match. + * + * @param o Another {@link PolygonOptions} to compare with this object. + * @return True if color, alpha, stroke color, vertices and holes match this {@link PolygonOptions} + * {@link PolygonOptions} object. Else, false. + */ + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PolygonOptions polygon = (PolygonOptions) o; + + if (Float.compare(polygon.getAlpha(), getAlpha()) != 0) { + return false; + } + if (getFillColor() != polygon.getFillColor()) { + return false; + } + if (getStrokeColor() != polygon.getStrokeColor()) { + return false; + } + if (getPoints() != null ? !getPoints().equals(polygon.getPoints()) : polygon.getPoints() != null) { + return false; + } + return !(getHoles() != null ? !getHoles().equals(polygon.getHoles()) : polygon.getHoles() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); + result = 31 * result + getFillColor(); + result = 31 * result + getStrokeColor(); + result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); + result = 31 * result + (getHoles() != null ? getHoles().hashCode() : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java new file mode 100644 index 000000000..76ea15215 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java @@ -0,0 +1,71 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Color; +import android.support.annotation.Keep; + +import com.mapbox.mapboxsdk.maps.MapboxMap; + +/** + * Polyline is a geometry feature with an unclosed list of coordinates drawn as a line + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class Polyline extends BasePointCollection { + + @Keep + private int color = Color.BLACK; // default color is black + @Keep + private float width = 10; // As specified by Google API Docs (in pixels) + + Polyline() { + super(); + } + + /** + * Gets the color of this polyline. + * + * @return The color in ARGB format. + */ + public int getColor() { + return color; + } + + /** + * Gets the width of this polyline. + * + * @return The width in screen pixels. + */ + public float getWidth() { + return width; + } + + /** + * Sets the color of the polyline. + * + * @param color - the color in ARGB format + */ + public void setColor(int color) { + this.color = color; + update(); + } + + /** + * Sets the width of the polyline. + * + * @param width in pixels + */ + public void setWidth(float width) { + this.width = width; + update(); + } + + @Override + void update() { + MapboxMap mapboxMap = getMapboxMap(); + if (mapboxMap != null) { + mapboxMap.updatePolyline(this); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java new file mode 100644 index 000000000..6a54f948b --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java @@ -0,0 +1,250 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.os.Parcel; +import android.os.Parcelable; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import java.util.ArrayList; +import java.util.List; + +/** + * Builder for composing {@link Polyline} objects. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ +@Deprecated +public final class PolylineOptions implements Parcelable { + + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PolylineOptions createFromParcel(@NonNull Parcel in) { + return new PolylineOptions(in); + } + + public PolylineOptions[] newArray(int size) { + return new PolylineOptions[size]; + } + }; + + private PolylineOptions(Parcel in) { + polyline = new Polyline(); + ArrayList pointsList = new ArrayList<>(); + in.readList(pointsList, LatLng.class.getClassLoader()); + addAll(pointsList); + alpha(in.readFloat()); + color(in.readInt()); + width(in.readFloat()); + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @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. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeList(getPoints()); + out.writeFloat(getAlpha()); + out.writeInt(getColor()); + out.writeFloat(getWidth()); + } + + private Polyline polyline; + + /** + * Defines options for a polyline. + */ + public PolylineOptions() { + polyline = new Polyline(); + } + + /** + * Adds a vertex to the end of the polyline being built. + * + * @param point {@link LatLng} point to be added to polyline geometry. + * @return This {@link PolylineOptions} object with the given point on the end. + */ + @NonNull + public PolylineOptions add(LatLng point) { + polyline.addPoint(point); + return this; + } + + /** + * Adds vertices to the end of the polyline being built. + * + * @param points {@link LatLng} points defining the polyline geometry. + * @return This {@link PolylineOptions} object with the given point on the end. + */ + @NonNull + public PolylineOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Adds vertices to the end of the polyline being built. + * + * @param points {@link Iterable} list made up of {@link LatLng} points defining the polyline + * geometry + * @return This {@link PolylineOptions} object with the given points on the end. + */ + @NonNull + public PolylineOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Set the alpha value of the polyline. + * + * @param alpha float value between 0 (not visible) and 1. + * @return This {@link PolylineOptions} object with the given polyline alpha value. + */ + @NonNull + public PolylineOptions alpha(float alpha) { + polyline.setAlpha(alpha); + return this; + } + + /** + * Gets the alpha set for this {@link PolylineOptions} object. + * + * @return float value between 0 and 1 defining the alpha. + */ + public float getAlpha() { + return polyline.getAlpha(); + } + + /** + * Sets the color of the polyline as a 32-bit ARGB color. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolylineOptions} object with a new color set. + */ + @NonNull + public PolylineOptions color(int color) { + polyline.setColor(color); + return this; + } + + /** + * Gets the color set for this {@link PolylineOptions} object. + * + * @return The color of the polyline in ARGB format. + */ + public int getColor() { + return polyline.getColor(); + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return PolyLine The polyline build by this class. + */ + public Polyline getPolyline() { + return polyline; + } + + /** + * Gets the width set for this {@link PolylineOptions} object. + * + * @return The width of the polyline in screen pixels. + */ + public float getWidth() { + return polyline.getWidth(); + } + + /** + * Sets the width of the polyline in screen pixels. The default is 10. + * + * @param width float value defining width of polyline using unit pixels. + * @return This {@link PolylineOptions} object with a new width set. + */ + @NonNull + public PolylineOptions width(float width) { + polyline.setWidth(width); + return this; + } + + /** + * Gets the points set for this {@link PolylineOptions} object. + * + * @return a {@link List} of {@link LatLng}s specifying the vertices of the polyline. + */ + public List getPoints() { + // the getter gives us a copy, which is the safe thing to do... + return polyline.getPoints(); + } + + /** + * Compares this {@link PolylineOptions} object with another {@link PolylineOptions} and + * determines if their color, alpha, width, and vertices match. + * + * @param o Another {@link PolylineOptions} to compare with this object. + * @return True if color, alpha, width, and vertices match this {@link PolylineOptions} object. + * Else, false. + */ + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PolylineOptions polyline = (PolylineOptions) o; + + if (Float.compare(polyline.getAlpha(), getAlpha()) != 0) { + return false; + } + if (getColor() != polyline.getColor()) { + return false; + } + if (Float.compare(polyline.getWidth(), getWidth()) != 0) { + return false; + } + return !(getPoints() != null ? !getPoints().equals(polyline.getPoints()) : polyline.getPoints() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); + result = 31 * result + getColor(); + result = 31 * result + (getWidth() != +0.0f ? Float.floatToIntBits(getWidth()) : 0); + result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/package-info.java new file mode 100644 index 000000000..1e2dc542f --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Annotation API classes. + */ +package com.mapbox.mapboxsdk.annotations; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java new file mode 100644 index 000000000..035614a90 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java @@ -0,0 +1,70 @@ +package com.mapbox.mapboxsdk.attribution; + +import android.support.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class Attribution { + + private static final String OPENSTREETMAP = "OpenStreetMap"; + private static final String OPENSTREETMAP_ABBR = "OSM"; + static final String TELEMETRY = "Telemetry Settings"; + static final String MAPBOX_URL = "https://www.mapbox.com/about/maps/"; + static final String TELEMETRY_URL = "https://www.mapbox.com/telemetry/"; + static final List IMPROVE_MAP_URLS = new ArrayList<>(); + + static { + // Using a List makes URL backwards compatible + IMPROVE_MAP_URLS.add("https://www.mapbox.com/feedback/"); + IMPROVE_MAP_URLS.add("https://www.mapbox.com/map-feedback/"); + IMPROVE_MAP_URLS.add("https://apps.mapbox.com/feedback/"); + } + + private String title; + private String url; + + Attribution(String title, String url) { + this.title = title; + this.url = url; + } + + public String getTitle() { + return title; + } + + public String getTitleAbbreviated() { + if (title.equals(OPENSTREETMAP)) { + return OPENSTREETMAP_ABBR; + } + return title; + } + + public String getUrl() { + return url; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Attribution that = (Attribution) o; + + if (title != null ? !title.equals(that.title) : that.title != null) { + return false; + } + return url != null ? url.equals(that.url) : that.url == null; + } + + @Override + public int hashCode() { + int result = title != null ? title.hashCode() : 0; + result = 31 * result + (url != null ? url.hashCode() : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java new file mode 100644 index 000000000..25d5de7ea --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java @@ -0,0 +1,68 @@ +package com.mapbox.mapboxsdk.attribution; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +public class AttributionLayout { + + @Nullable + private Bitmap logo; + @Nullable + private PointF anchorPoint; + private boolean shortText; + + public AttributionLayout(@Nullable Bitmap logo, @Nullable PointF anchorPoint, boolean shortText) { + this.logo = logo; + this.anchorPoint = anchorPoint; + this.shortText = shortText; + } + + @Nullable + public Bitmap getLogo() { + return logo; + } + + @Nullable + public PointF getAnchorPoint() { + return anchorPoint; + } + + public boolean isShortText() { + return shortText; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + AttributionLayout that = (AttributionLayout) o; + + if (logo != null ? !logo.equals(that.logo) : that.logo != null) { + return false; + } + return anchorPoint != null ? anchorPoint.equals(that.anchorPoint) : that.anchorPoint == null; + } + + @Override + public int hashCode() { + int result = logo != null ? logo.hashCode() : 0; + result = 31 * result + (anchorPoint != null ? anchorPoint.hashCode() : 0); + return result; + } + + @NonNull + @Override + public String toString() { + return "AttributionLayout{" + + "logo=" + logo + + ", anchorPoint=" + anchorPoint + + '}'; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java new file mode 100644 index 000000000..b40a7be24 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java @@ -0,0 +1,249 @@ +package com.mapbox.mapboxsdk.attribution; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.widget.TextView; + +import java.util.Arrays; +import java.util.List; + +public class AttributionMeasure { + + private Bitmap logo; + private Bitmap logoSmall; + private Bitmap snapshot; + private TextView textView; + private TextView textViewShort; + private float margin; + + private boolean shorterText; + + AttributionMeasure(Bitmap snapshot, Bitmap logo, Bitmap logoSmall, TextView tv, TextView tvShort, float margin) { + this.snapshot = snapshot; + this.logo = logo; + this.logoSmall = logoSmall; + this.textView = tv; + this.textViewShort = tvShort; + this.margin = margin; + } + + @Nullable + public AttributionLayout measure() { + Chain chain = new Chain( + new FullLogoLongTextCommand(), + new FullLogoShortTextCommand(), + new SmallLogoLongTextCommand(), + new SmallLogoShortTextCommand(), + new LongTextCommand(), + new ShortTextCommand(), + new NoTextCommand() + ); + + AttributionLayout attributionLayout = chain.start(this); + shorterText = attributionLayout.isShortText(); + return attributionLayout; + } + + + private static class FullLogoLongTextCommand implements Command { + @Nullable + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getLogoContainerWidth() + measure.getTextViewContainerWidth(); + boolean fitBounds = width <= measure.getMaxSize(); + if (fitBounds) { + PointF anchor = calculateAnchor(measure.snapshot, measure.textView, measure.margin); + return new AttributionLayout(measure.logo, anchor, false); + } + return null; + } + } + + private static class FullLogoShortTextCommand implements Command { + @Nullable + @Override + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getLogoContainerWidth() + measure.getTextViewShortContainerWidth(); + boolean fitBounds = width <= measure.getMaxSizeShort(); + if (fitBounds) { + PointF anchor = calculateAnchor(measure.snapshot, measure.textViewShort, measure.margin); + return new AttributionLayout(measure.logo, anchor, true); + } + return null; + } + } + + private static class SmallLogoLongTextCommand implements Command { + @Nullable + @Override + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getLogoSmallContainerWidth() + measure.getTextViewContainerWidth(); + boolean fitBounds = width <= measure.getMaxSize(); + if (fitBounds) { + PointF anchor = calculateAnchor(measure.snapshot, measure.textView, measure.margin); + return new AttributionLayout(measure.logoSmall, anchor, false); + } + return null; + } + } + + private static class SmallLogoShortTextCommand implements Command { + @Nullable + @Override + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getLogoContainerWidth() + measure.getTextViewShortContainerWidth(); + boolean fitBounds = width <= measure.getMaxSizeShort(); + if (fitBounds) { + PointF anchor = calculateAnchor(measure.snapshot, measure.textViewShort, measure.margin); + return new AttributionLayout(measure.logoSmall, anchor, true); + } + return null; + } + } + + private static class LongTextCommand implements Command { + @Nullable + @Override + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getTextViewContainerWidth() + measure.margin; + boolean fitBounds = width <= measure.getMaxSize(); + if (fitBounds) { + return new AttributionLayout(null, calculateAnchor(measure.snapshot, measure.textView, measure.margin), false); + } + return null; + } + } + + private static class ShortTextCommand implements Command { + @Nullable + @Override + public AttributionLayout execute(@NonNull AttributionMeasure measure) { + float width = measure.getTextViewShortContainerWidth() + measure.margin; + boolean fitBounds = width <= measure.getMaxSizeShort(); + if (fitBounds) { + PointF anchor = calculateAnchor(measure.snapshot, measure.textViewShort, measure.margin); + return new AttributionLayout(null, anchor, true); + } + return null; + } + } + + private static class NoTextCommand implements Command { + @NonNull + @Override + public AttributionLayout execute(AttributionMeasure measure) { + return new AttributionLayout(null, null, false); + } + } + + private static PointF calculateAnchor(Bitmap snapshot, TextView textView, float margin) { + return new PointF( + snapshot.getWidth() - textView.getMeasuredWidth() - margin, + snapshot.getHeight() - margin - textView.getMeasuredHeight() + ); + } + + public TextView getTextView() { + return shorterText ? textViewShort : textView; + } + + private class Chain { + public List commands; + + Chain(Command... commands) { + this.commands = Arrays.asList(commands); + } + + @Nullable + public AttributionLayout start(AttributionMeasure measure) { + AttributionLayout attributionLayout = null; + for (Command command : commands) { + attributionLayout = command.execute(measure); + if (attributionLayout != null) { + break; + } + } + return attributionLayout; + } + } + + public interface Command { + @Nullable + AttributionLayout execute(AttributionMeasure measure); + } + + private float getTextViewContainerWidth() { + return textView.getMeasuredWidth() + margin; + } + + private float getLogoContainerWidth() { + return logo.getWidth() + (2 * margin); + } + + private float getTextViewShortContainerWidth() { + return textViewShort.getMeasuredWidth() + margin; + } + + private float getLogoSmallContainerWidth() { + return logoSmall.getWidth() + (2 * margin); + } + + private float getMaxSize() { + return snapshot.getWidth() * 8 / 10; + } + + private float getMaxSizeShort() { + return snapshot.getWidth(); + } + + public static class Builder { + private Bitmap snapshot; + private Bitmap logo; + private Bitmap logoSmall; + private TextView textView; + private TextView textViewShort; + private float marginPadding; + + @NonNull + public Builder setSnapshot(Bitmap snapshot) { + this.snapshot = snapshot; + return this; + } + + @NonNull + public Builder setLogo(Bitmap logo) { + this.logo = logo; + return this; + } + + @NonNull + public Builder setLogoSmall(Bitmap logoSmall) { + this.logoSmall = logoSmall; + return this; + } + + @NonNull + public Builder setTextView(TextView textView) { + this.textView = textView; + return this; + } + + @NonNull + public Builder setTextViewShort(TextView textViewShort) { + this.textViewShort = textViewShort; + return this; + } + + @NonNull + public Builder setMarginPadding(float marginPadding) { + this.marginPadding = marginPadding; + return this; + } + + @NonNull + public AttributionMeasure build() { + return new AttributionMeasure(snapshot, logo, logoSmall, textView, textViewShort, marginPadding); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java new file mode 100644 index 000000000..ff59dbdf9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java @@ -0,0 +1,314 @@ +package com.mapbox.mapboxsdk.attribution; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.text.Html; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.URLSpan; +import com.mapbox.mapboxsdk.R; + +import java.lang.ref.WeakReference; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Responsible for parsing attribution data coming from Sources and MapSnapshot. + *

+ * Exposes multiple configuration options to manipulate data being parsed. + * Use the Options object to build these configurations. + *

+ */ +public class AttributionParser { + + private static final String IMPROVE_THIS_MAP = "Improve this map"; + private final WeakReference context; + private final Set attributions = new LinkedHashSet<>(); + private final String attributionData; + private final boolean withImproveMap; + private final boolean withCopyrightSign; + private final boolean withTelemetryAttribution; + private final boolean withMapboxAttribution; + + AttributionParser(WeakReference context, String attributionData, boolean withImproveMap, + boolean withCopyrightSign, boolean withTelemetryAttribution, boolean withMapboxAttribution) { + this.context = context; + this.attributionData = attributionData; + this.withImproveMap = withImproveMap; + this.withCopyrightSign = withCopyrightSign; + this.withTelemetryAttribution = withTelemetryAttribution; + this.withMapboxAttribution = withMapboxAttribution; + } + + /** + * Get parsed attributions. + * + * @return the attributions + */ + @NonNull + public Set getAttributions() { + return attributions; + } + + /** + * Get parsed attribution string. + * + * @return the parsed attribution string + */ + @NonNull + public String createAttributionString() { + return createAttributionString(false); + } + + /** + * Get parsed attribution string. + * + * @param shortenedOutput if attribution string should contain shortened output + * @return the parsed attribution string + */ + @NonNull + public String createAttributionString(boolean shortenedOutput) { + StringBuilder stringBuilder = new StringBuilder(withCopyrightSign ? "" : "© "); + int counter = 0; + for (Attribution attribution : attributions) { + counter++; + stringBuilder.append(!shortenedOutput ? attribution.getTitle() : attribution.getTitleAbbreviated()); + if (counter != attributions.size()) { + stringBuilder.append(" / "); + } + } + return stringBuilder.toString(); + } + + /** + * Main attribution for configuration + */ + protected void parse() { + parseAttributions(); + addAdditionalAttributions(); + } + + /** + * Parse attributions + */ + private void parseAttributions() { + SpannableStringBuilder htmlBuilder = (SpannableStringBuilder) fromHtml(attributionData); + URLSpan[] urlSpans = htmlBuilder.getSpans(0, htmlBuilder.length(), URLSpan.class); + for (URLSpan urlSpan : urlSpans) { + parseUrlSpan(htmlBuilder, urlSpan); + } + } + + /** + * Parse an URLSpan containing an attribution. + * + * @param htmlBuilder the html builder + * @param urlSpan the url span to be parsed + */ + private void parseUrlSpan(@NonNull SpannableStringBuilder htmlBuilder, @NonNull URLSpan urlSpan) { + String url = urlSpan.getURL(); + if (isUrlValid(url)) { + String anchor = parseAnchorValue(htmlBuilder, urlSpan); + if (isImproveThisMapAnchor(anchor)) { + anchor = translateImproveThisMapAnchor(anchor); + } + attributions.add(new Attribution(anchor, url)); + } + } + + /** + * Invoked to validate if an url is valid to be included in the final attribution. + * + * @param url the url to be validated + * @return if the url is valid + */ + private boolean isUrlValid(@NonNull String url) { + return isValidForImproveThisMap(url) && isValidForMapbox(url); + } + + /** + * Invoked to validate if an anchor is equal to Improve this map coming from tilesets. + * + * @param anchor the anchor to be validated + * @return if the url is valid + */ + private boolean isImproveThisMapAnchor(String anchor) { + return anchor.equals(IMPROVE_THIS_MAP); + } + + /** + * Invoked to replace the english Improve this map with localized variant. + * + * @param anchor the anchor to be translated + * @return the translated anchor + */ + private String translateImproveThisMapAnchor(String anchor) { + Context context = this.context.get(); + if (context != null) { + anchor = context.getString(R.string.mapbox_telemetryImproveMap); + } + return anchor; + } + + /** + * Invoked to validate if an url is valid for the improve map configuration. + * + * @param url the url to be validated + * @return if the url is valid for improve this map + */ + private boolean isValidForImproveThisMap(@NonNull String url) { + return withImproveMap || !(Attribution.IMPROVE_MAP_URLS.contains(url)); + } + + /** + * Invoked to validate if an url is valid for the Mapbox configuration. + * + * @param url the url to be validated + * @return if the url is valid for Mapbox + */ + private boolean isValidForMapbox(@NonNull String url) { + return withMapboxAttribution || !url.equals(Attribution.MAPBOX_URL); + } + + /** + * Parse the attribution by parsing the anchor value of html href tag. + * + * @param htmlBuilder the html builder + * @param urlSpan the current urlSpan + * @return the parsed anchor value + */ + @NonNull + private String parseAnchorValue(SpannableStringBuilder htmlBuilder, URLSpan urlSpan) { + int start = htmlBuilder.getSpanStart(urlSpan); + int end = htmlBuilder.getSpanEnd(urlSpan); + int length = end - start; + char[] charKey = new char[length]; + htmlBuilder.getChars(start, end, charKey, 0); + return stripCopyright(String.valueOf(charKey)); + } + + /** + * Utility to strip the copyright sign from an attribution + * + * @param anchor the attribution string to strip + * @return the stripped attribution string without the copyright sign + */ + @NonNull + private String stripCopyright(@NonNull String anchor) { + if (!withCopyrightSign && anchor.startsWith("© ")) { + anchor = anchor.substring(2, anchor.length()); + } + return anchor; + } + + /** + * Invoked to manually add attributions + */ + private void addAdditionalAttributions() { + if (withTelemetryAttribution) { + Context context = this.context.get(); + attributions.add( + new Attribution( + context != null ? context.getString(R.string.mapbox_telemetrySettings) : Attribution.TELEMETRY, + Attribution.TELEMETRY_URL + ) + ); + } + } + + /** + * Convert a string to a spanned html representation. + * + * @param html the string to convert + * @return the spanned html representation + */ + private static Spanned fromHtml(String html) { + Spanned result; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY); + } else { + result = Html.fromHtml(html); + } + return result; + } + + /** + * Builder to configure using an AttributionParser. + *

+ * AttributionData, set with {@link #withAttributionData(String...)}, is the only required property to build + * the underlying AttributionParser. Other properties include trimming the copyright sign, adding telemetry + * attribution or hiding attribution as improve this map and Mapbox. + *

+ */ + public static class Options { + private final WeakReference context; + private boolean withImproveMap = true; + private boolean withCopyrightSign = true; + private boolean withTelemetryAttribution = false; + private boolean withMapboxAttribution = true; + private String[] attributionDataStringArray; + + public Options(@NonNull Context context) { + this.context = new WeakReference<>(context); + } + + @NonNull + public Options withAttributionData(String... attributionData) { + this.attributionDataStringArray = attributionData; + return this; + } + + @NonNull + public Options withImproveMap(boolean withImproveMap) { + this.withImproveMap = withImproveMap; + return this; + } + + @NonNull + public Options withCopyrightSign(boolean withCopyrightSign) { + this.withCopyrightSign = withCopyrightSign; + return this; + } + + @NonNull + public Options withTelemetryAttribution(boolean withTelemetryAttribution) { + this.withTelemetryAttribution = withTelemetryAttribution; + return this; + } + + @NonNull + public Options withMapboxAttribution(boolean withMapboxAttribution) { + this.withMapboxAttribution = withMapboxAttribution; + return this; + } + + @NonNull + public AttributionParser build() { + if (attributionDataStringArray == null) { + throw new IllegalStateException("Using builder without providing attribution data"); + } + + String fullAttributionString = parseAttribution(attributionDataStringArray); + AttributionParser attributionParser = new AttributionParser( + context, + fullAttributionString, + withImproveMap, + withCopyrightSign, + withTelemetryAttribution, + withMapboxAttribution + ); + attributionParser.parse(); + return attributionParser; + } + + private String parseAttribution(String[] attribution) { + StringBuilder builder = new StringBuilder(); + for (String attr : attribution) { + if (!attr.isEmpty()) { + builder.append(attr); + } + } + return builder.toString(); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java new file mode 100644 index 000000000..57d840af5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Attribution API classes. + */ +package com.mapbox.mapboxsdk.attribution; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java new file mode 100644 index 000000000..e2341029f --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -0,0 +1,397 @@ +package com.mapbox.mapboxsdk.camera; + +import android.content.res.TypedArray; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.FloatRange; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.Size; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.utils.MathUtils; + +import java.util.Arrays; + +/** + * Resembles the position, angle, zoom and tilt of the user's viewpoint. + */ +public final class CameraPosition implements Parcelable { + + public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0, new double[] {0, 0, 0, 0}); + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public CameraPosition createFromParcel(Parcel in) { + double bearing = in.readDouble(); + LatLng target = in.readParcelable(LatLng.class.getClassLoader()); + double tilt = in.readDouble(); + double zoom = in.readDouble(); + double[] padding = new double[4]; + in.readDoubleArray(padding); + return new CameraPosition(target, zoom, tilt, bearing, padding); + } + + public CameraPosition[] newArray(int size) { + return new CameraPosition[size]; + } + }; + + /** + * Direction that the camera is pointing in, in degrees clockwise from north. + */ + @Keep + public final double bearing; + + /** + * The location that the camera is pointing at. + */ + @Keep + public final LatLng target; + + /** + * The angle, in degrees, of the camera angle from the nadir (directly facing the Earth). + * See {@link Builder#tilt(double)} for details of restrictions on the range of values. + */ + @Keep + public final double tilt; + + /** + * Zoom level near the center of the screen. See {@link Builder#zoom(double)} for the definition of the camera's + * zoom level. + */ + @Keep + public final double zoom; + + /** + * Padding in pixels. Specified in left, top, right, bottom order. + * See {@link Builder#padding(double[])} for the definition of the camera's padding. + */ + @Keep + public final double[] padding; + + /** + * Constructs a CameraPosition. + * + * @param target The target location to align with the center of the screen. + * @param zoom Zoom level at target. See zoom(float) for details of restrictions. + * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float) + * for details of restrictions. + * @param bearing Direction that the camera is pointing in, in degrees clockwise from north. + * This value will be normalized to be within 0 degrees inclusive and 360 degrees + * exclusive. + * @throws NullPointerException if target is null + * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive. + * @deprecated use {@link CameraPosition#CameraPosition(LatLng, double, double, double, double[])} instead. + */ + @Deprecated + CameraPosition(LatLng target, double zoom, double tilt, double bearing) { + this(target, zoom, tilt, bearing, null); + } + + /** + * Constructs a CameraPosition. + * + * @param target The target location to align with the center of the screen. + * @param zoom Zoom level at target. See zoom(float) for details of restrictions. + * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float) + * for details of restrictions. + * @param bearing Direction that the camera is pointing in, in degrees clockwise from north. + * This value will be normalized to be within 0 degrees inclusive and 360 degrees + * exclusive. + * @param padding Padding in pixels. Specified in left, top, right, bottom order. + * @throws NullPointerException if target is null + * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive. + */ + @Keep + CameraPosition(LatLng target, double zoom, double tilt, double bearing, double[] padding) { + this.target = target; + this.bearing = bearing; + this.tilt = tilt; + this.zoom = zoom; + this.padding = padding; + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @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. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(bearing); + out.writeParcelable(target, flags); + out.writeDouble(tilt); + out.writeDouble(zoom); + out.writeDoubleArray(padding); + } + + /** + * Returns a String with the camera target, zoom, bearing and tilt. + * + * @return A String with CameraPosition information. + */ + @Override + public String toString() { + return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt + + ", Padding:" + Arrays.toString(padding); + } + + /** + * Compares this {@link CameraPosition} object with another {@link CameraPosition} and + * determines if their target, zoom, tilt, and bearing match. + * + * @param o Another {@link CameraPosition} to compare with this object. + * @return True if target, zoom, tilt, and bearing match this {@link CameraPosition} object. + * Else, false. + */ + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + CameraPosition cameraPosition = (CameraPosition) o; + if (target != null && !target.equals(cameraPosition.target)) { + return false; + } else if (zoom != cameraPosition.zoom) { + return false; + } else if (tilt != cameraPosition.tilt) { + return false; + } else if (bearing != cameraPosition.bearing) { + return false; + } else if (!Arrays.equals(padding, cameraPosition.padding)) { + return false; + } + return true; + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(bearing); + result = (int) (temp ^ (temp >>> 32)); + result = 31 * result + (target != null ? target.hashCode() : 0); + temp = Double.doubleToLongBits(tilt); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(zoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + Arrays.hashCode(padding); + return result; + } + + /** + * Builder for composing CameraPosition objects. + */ + public static final class Builder { + + private double bearing = -1; + @Nullable + private LatLng target = null; + private double tilt = -1; + private double zoom = -1; + private double[] padding = null; + + /** + * Create an empty builder. + */ + public Builder() { + super(); + } + + /** + * Create a builder with an existing CameraPosition data. + * + * @param previous Existing CameraPosition values to use + */ + public Builder(@Nullable CameraPosition previous) { + super(); + if (previous != null) { + this.bearing = previous.bearing; + this.target = previous.target; + this.tilt = previous.tilt; + this.zoom = previous.zoom; + this.padding = previous.padding; + } + } + + /** + * Create a builder with an existing CameraPosition data. + * + * @param typedArray TypedArray containing attribute values + */ + public Builder(@Nullable TypedArray typedArray) { + super(); + if (typedArray != null) { + this.bearing = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraBearing, 0.0f); + double lat = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLat, 0.0f); + double lng = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLng, 0.0f); + this.target = new LatLng(lat, lng); + this.tilt = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTilt, 0.0f); + this.zoom = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoom, 0.0f); + } + } + + /** + * Create a builder from an existing CameraPositionUpdate update. + * + * @param update Update containing camera options + */ + public Builder(@Nullable CameraUpdateFactory.CameraPositionUpdate update) { + super(); + if (update != null) { + bearing = update.getBearing(); + target = update.getTarget(); + tilt = update.getTilt(); + zoom = update.getZoom(); + padding = update.getPadding(); + } + } + + /** + * Create builder from an existing CameraPositionUpdate update. + * + * @param update Update containing camera options + */ + public Builder(@Nullable CameraUpdateFactory.ZoomUpdate update) { + super(); + if (update != null) { + this.zoom = update.getZoom(); + } + } + + /** + * Sets the direction that the camera is pointing in, in degrees clockwise from north. + * + * @param bearing Bearing + * @return this + */ + @NonNull + public Builder bearing(double bearing) { + double direction = bearing; + + while (direction >= 360) { + direction -= 360; + } + while (direction < 0) { + direction += 360; + } + + this.bearing = direction; + return this; + } + + /** + * Sets the location where the camera is pointing at. + * + * @param location target of the camera + * @return this + */ + @NonNull + public Builder target(LatLng location) { + this.target = location; + return this; + } + + /** + * Set the tilt of the camera in degrees + *

+ * value is clamped to {@link MapboxConstants#MINIMUM_TILT} and {@link MapboxConstants#MAXIMUM_TILT}. + *

+ * + * @param tilt Tilt value of the camera + * @return this + */ + @NonNull + 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 of the camera + *

+ * Zoom ranges from {@link MapboxConstants#MINIMUM_ZOOM} to {@link MapboxConstants#MAXIMUM_ZOOM} + *

+ * + * @param zoom Zoom value of the camera + * @return this + */ + @NonNull + public Builder zoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, + to = MapboxConstants.MAXIMUM_ZOOM) double zoom) { + this.zoom = zoom; + return this; + } + + /** + * Padding in pixels that shifts the viewport by the specified amount. + * Applied padding is going to persist and impact following camera transformations. + *

+ * Specified in left, top, right, bottom order. + *

+ * + * @param padding Camera padding + * @return this + */ + @NonNull + public Builder padding(@Size(4) double[] padding) { + this.padding = padding; + return this; + } + + /** + * Padding in pixels that shifts the viewport by the specified amount. + * Applied padding is going to persist and impact following camera transformations. + *

+ * Specified in left, top, right, bottom order. + *

+ * + * @return this + */ + @NonNull + public Builder padding(double left, double top, double right, double bottom) { + this.padding = new double[] {left, top, right, bottom}; + return this; + } + + /** + * Builds the CameraPosition. + * + * @return CameraPosition + */ + public CameraPosition build() { + return new CameraPosition(target, zoom, tilt, bearing, padding); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java new file mode 100644 index 000000000..39b937210 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java @@ -0,0 +1,23 @@ +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 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/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java new file mode 100644 index 000000000..b611456f4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -0,0 +1,637 @@ +package com.mapbox.mapboxsdk.camera; + +import android.graphics.Point; +import android.graphics.PointF; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.mapboxsdk.maps.UiSettings; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * Factory for creating CameraUpdate objects. + */ +public final class CameraUpdateFactory { + + /** + * Returns a CameraUpdate that moves the camera to a specified CameraPosition. + * + * @param cameraPosition Camera Position to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) { + return new CameraPositionUpdate(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, + cameraPosition.zoom, cameraPosition.padding); + } + + /** + * Returns a CameraUpdate that 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 + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLng(@NonNull LatLng latLng) { + return new CameraPositionUpdate(-1, latLng, -1, -1, null); + } + + /** + * Returns a CameraUpdate that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level while maintaining + * current camera position bearing and tilt values. + *

+ * You can specify padding, in order to inset the bounding box from the map view's edges. + * The padding will not persist and impact following camera transformations. + *

+ * + * @param bounds Bounds to match Camera position with + * @param padding Padding added to the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int padding) { + return newLatLngBounds(bounds, padding, padding, padding, padding); + } + + /** + * Returns a CameraUpdate that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level while using + * provided bearing and tilt values. + *

+ * You can specify padding, in order to inset the bounding box from the map view's edges. + * The padding will not persist and impact following camera transformations. + *

+ * + * @param bounds Bounds to match Camera position with + * @param bearing Bearing to take in account when generating the bounds + * @param tilt Tilt to take in account when generating the bounds + * @param padding Padding added to the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, double bearing, double tilt, int padding) { + return newLatLngBounds(bounds, bearing, tilt, padding, padding, padding, padding); + } + + /** + * Returns a CameraUpdate that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level while maintaining + * current camera position bearing and tilt values. + *

+ * You can specify padding, in order to inset the bounding box from the map view's edges. + * The padding will not persist and impact following camera transformations. + *

+ * + * @param bounds Bounds to base the Camera position out of + * @param paddingLeft Padding left of the bounds + * @param paddingTop Padding top of the bounds + * @param paddingRight Padding right of the bounds + * @param paddingBottom Padding bottom of the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int paddingLeft, int paddingTop, + int paddingRight, int paddingBottom) { + return new CameraBoundsUpdate(bounds, null, null, paddingLeft, paddingTop, paddingRight, paddingBottom); + } + + /** + * Returns a CameraUpdate that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level while using + * provided bearing and tilt values. + *

+ * You can specify padding, in order to inset the bounding box from the map view's edges. + * The padding will not persist and impact following camera transformations. + *

+ * + * @param bounds Bounds to base the Camera position out of + * @param bearing Bearing to take in account when generating the bounds + * @param tilt Tilt to take in account when generating the bounds + * @param paddingLeft Padding left of the bounds + * @param paddingTop Padding top of the bounds + * @param paddingRight Padding right of the bounds + * @param paddingBottom Padding bottom of the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, double bearing, double tilt, + int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { + return new CameraBoundsUpdate(bounds, bearing, tilt, paddingLeft, paddingTop, paddingRight, paddingBottom); + } + + /** + * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude + * specified by a LatLng object taking the specified padding into account. + * + * @param latLng Target location to change to + * @param zoom Zoom level to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngZoom(@NonNull LatLng latLng, double zoom) { + return new CameraPositionUpdate(-1, latLng, -1, zoom, null); + } + + /** + * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude + * specified by a LatLng object, and moves to the given zoom level. + * Applied padding is going to persist and impact following camera transformations. + * + * @param latLng Target location to change to + * @param left Left padding + * @param top Top padding + * @param right Right padding + * @param bottom Bottom padding + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngPadding(@NonNull LatLng latLng, + double left, double top, double right, double bottom) { + return new CameraPositionUpdate(-1, latLng, -1, -1, new double[] {left, top, right, bottom}); + } + + /** + * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. + * + * @param amount Amount of zoom level to change with + * @param focus Focus point of zoom + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomBy(double amount, Point focus) { + return new ZoomUpdate(amount, focus.x, focus.y); + } + + /** + * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. + * + * @param amount Amount of zoom level to change with + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomBy(double amount) { + return new ZoomUpdate(ZoomUpdate.ZOOM_BY, amount); + } + + /** + * Returns a CameraUpdate that zooms in on the map by moving the viewpoint's height closer to + * the Earth's surface. The zoom increment is 1.0. + * + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomIn() { + return new ZoomUpdate(ZoomUpdate.ZOOM_IN); + } + + /** + * Returns a CameraUpdate that zooms out on the map by moving the viewpoint's height farther + * away from the Earth's surface. The zoom increment is -1.0. + * + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomOut() { + return new ZoomUpdate(ZoomUpdate.ZOOM_OUT); + } + + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular zoom level. + * + * @param zoom Zoom level to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomTo(double zoom) { + return new ZoomUpdate(ZoomUpdate.ZOOM_TO, zoom); + } + + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular bearing. + * + * @param bearing Bearing to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate bearingTo(double bearing) { + return new CameraPositionUpdate(bearing, null, -1, -1, null); + } + + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular tilt. + * + * @param tilt Tilt to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate tiltTo(double tilt) { + return new CameraPositionUpdate(-1, null, tilt, -1, null); + } + + /** + * Returns a CameraUpdate that when animated changes the camera padding. + * Applied padding is going to persist and impact following camera transformations. + *

+ * Specified in left, top, right, bottom order. + *

+ * + * @param padding Padding to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate paddingTo(double[] padding) { + return new CameraPositionUpdate(-1, null, -1, -1, padding); + } + + /** + * Returns a CameraUpdate that when animated changes the camera padding. + * Applied padding is going to persist and impact following camera transformations. + *

+ * Specified in left, top, right, bottom order. + *

+ * + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate paddingTo(double left, double top, double right, double bottom) { + return paddingTo(new double[] {left, top, right, bottom}); + } + + // + // CameraUpdate types + // + + static final class CameraPositionUpdate implements CameraUpdate { + + private final double bearing; + private final LatLng target; + private final double tilt; + private final double zoom; + private final double[] padding; + + CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom, double[] padding) { + this.bearing = bearing; + this.target = target; + this.tilt = tilt; + this.zoom = zoom; + this.padding = padding; + } + + public LatLng getTarget() { + return target; + } + + public double getBearing() { + return bearing; + } + + public double getTilt() { + return tilt; + } + + public double getZoom() { + return zoom; + } + + public double[] getPadding() { + return padding; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + if (target == null) { + CameraPosition previousPosition = mapboxMap.getCameraPosition(); + return new CameraPosition.Builder(this) + .target(previousPosition.target) + .build(); + } + return new CameraPosition.Builder(this).build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + CameraPositionUpdate that = (CameraPositionUpdate) o; + + if (Double.compare(that.bearing, bearing) != 0) { + return false; + } + if (Double.compare(that.tilt, tilt) != 0) { + return false; + } + if (Double.compare(that.zoom, zoom) != 0) { + return false; + } + if (target != null ? !target.equals(that.target) : that.target != null) { + return false; + } + return Arrays.equals(padding, that.padding); + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(bearing); + result = (int) (temp ^ (temp >>> 32)); + result = 31 * result + (target != null ? target.hashCode() : 0); + temp = Double.doubleToLongBits(tilt); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(zoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + Arrays.hashCode(padding); + return result; + } + + @Override + public String toString() { + return "CameraPositionUpdate{" + + "bearing=" + bearing + + ", target=" + target + + ", tilt=" + tilt + + ", zoom=" + zoom + + ", padding=" + Arrays.toString(padding) + + '}'; + } + } + + static final class CameraBoundsUpdate implements CameraUpdate { + + private final LatLngBounds bounds; + private final int[] padding; + private final Double bearing; + private final Double tilt; + + CameraBoundsUpdate(LatLngBounds bounds, Double bearing, Double tilt, int[] padding) { + this.bounds = bounds; + this.padding = padding; + this.bearing = bearing; + this.tilt = tilt; + } + + CameraBoundsUpdate(LatLngBounds bounds, Double bearing, Double tilt, int paddingLeft, + int paddingTop, int paddingRight, int paddingBottom) { + this(bounds, bearing, tilt, new int[] {paddingLeft, paddingTop, paddingRight, paddingBottom}); + } + + public LatLngBounds getBounds() { + return bounds; + } + + public int[] getPadding() { + return padding; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + if (bearing == null && tilt == null) { + // use current camera position tilt and bearing + return mapboxMap.getCameraForLatLngBounds(bounds, padding); + } else { + // use provided tilt and bearing + assert bearing != null; + assert tilt != null; + return mapboxMap.getCameraForLatLngBounds(bounds, padding, bearing, tilt); + } + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + CameraBoundsUpdate that = (CameraBoundsUpdate) o; + + if (!bounds.equals(that.bounds)) { + return false; + } + return Arrays.equals(padding, that.padding); + } + + @Override + public int hashCode() { + int result = bounds.hashCode(); + result = 31 * result + Arrays.hashCode(padding); + return result; + } + + @Override + public String toString() { + return "CameraBoundsUpdate{" + + "bounds=" + bounds + + ", padding=" + Arrays.toString(padding) + + '}'; + } + } + + static final class CameraMoveUpdate implements CameraUpdate { + + private float x; + private float y; + + CameraMoveUpdate(float x, float y) { + this.x = x; + this.y = y; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + UiSettings uiSettings = mapboxMap.getUiSettings(); + Projection projection = mapboxMap.getProjection(); + // Calculate the new center point + float viewPortWidth = uiSettings.getWidth(); + float viewPortHeight = uiSettings.getHeight(); + int[] padding = mapboxMap.getPadding(); + + // we inverse the map padding, is reapplied when using moveTo/easeTo or animateTo + PointF targetPoint = new PointF( + (viewPortWidth - padding[0] + padding[1]) / 2 + x, + (viewPortHeight + padding[1] - padding[3]) / 2 + y + ); + + LatLng latLng = projection.fromScreenLocation(targetPoint); + CameraPosition previousPosition = mapboxMap.getCameraPosition(); + CameraPosition position = + new CameraPosition.Builder() + .target(latLng) + .zoom(previousPosition.zoom) + .tilt(previousPosition.tilt) + .bearing(previousPosition.bearing) + .build(); + return position; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + CameraMoveUpdate that = (CameraMoveUpdate) o; + + if (Float.compare(that.x, x) != 0) { + return false; + } + return Float.compare(that.y, y) == 0; + } + + @Override + public int hashCode() { + int result = (x != +0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0); + return result; + } + + @Override + public String toString() { + return "CameraMoveUpdate{" + + "x=" + x + + ", y=" + y + + '}'; + } + } + + static final class ZoomUpdate implements CameraUpdate { + + @IntDef( {ZOOM_IN, ZOOM_OUT, ZOOM_BY, ZOOM_TO, ZOOM_TO_POINT}) + @Retention(RetentionPolicy.SOURCE) + @interface Type { + } + + static final int ZOOM_IN = 0; + static final int ZOOM_OUT = 1; + static final int ZOOM_BY = 2; + static final int ZOOM_TO = 3; + static final int ZOOM_TO_POINT = 4; + + @Type + private final int type; + private final double zoom; + private float x; + private float y; + + ZoomUpdate(@Type int type) { + this.type = type; + this.zoom = 0; + } + + ZoomUpdate(@Type int type, double zoom) { + this.type = type; + this.zoom = zoom; + } + + ZoomUpdate(double zoom, float x, float y) { + this.type = ZOOM_TO_POINT; + this.zoom = zoom; + this.x = x; + this.y = y; + } + + public double getZoom() { + return zoom; + } + + @Type + public int getType() { + return type; + } + + public float getX() { + return x; + } + + public float getY() { + return y; + } + + double transformZoom(double currentZoom) { + switch (getType()) { + case CameraUpdateFactory.ZoomUpdate.ZOOM_IN: + currentZoom++; + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_OUT: + currentZoom--; + if (currentZoom < 0) { + currentZoom = 0; + } + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_TO: + currentZoom = getZoom(); + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_BY: + currentZoom = currentZoom + getZoom(); + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT: + currentZoom = currentZoom + getZoom(); + break; + } + return currentZoom; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + CameraPosition cameraPosition = mapboxMap.getCameraPosition(); + if (getType() != CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT) { + return new CameraPosition.Builder(cameraPosition) + .zoom(transformZoom(cameraPosition.zoom)) + .build(); + } else { + return new CameraPosition.Builder(cameraPosition) + .zoom(transformZoom(cameraPosition.zoom)) + .target(mapboxMap.getProjection().fromScreenLocation(new PointF(getX(), getY()))) + .build(); + } + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ZoomUpdate that = (ZoomUpdate) o; + + if (type != that.type) { + return false; + } + if (Double.compare(that.zoom, zoom) != 0) { + return false; + } + if (Float.compare(that.x, x) != 0) { + return false; + } + return Float.compare(that.y, y) == 0; + } + + @Override + public int hashCode() { + int result; + long temp; + result = type; + temp = Double.doubleToLongBits(zoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (x != +0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0); + return result; + } + + @Override + public String toString() { + return "ZoomUpdate{" + + "type=" + type + + ", zoom=" + zoom + + ", x=" + x + + ", y=" + y + + '}'; + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/package-info.java new file mode 100644 index 000000000..04ef699c2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Camera API classes. + */ +package com.mapbox.mapboxsdk.camera; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java new file mode 100644 index 000000000..6f6e77792 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java @@ -0,0 +1,67 @@ +package com.mapbox.mapboxsdk.constants; + +/** + * Contains constants used throughout the sdk classes. + */ +public class GeometryConstants { + + /** + * The equatorial radius + * value in meters + */ + public static final int RADIUS_EARTH_METERS = 6378137; + + /** + * This constant represents the lowest longitude value available to represent a wrapped geolocation. + */ + public static final double MIN_WRAP_LONGITUDE = -180; + + /** + * This constant represents the highest longitude value available to represent a wrapped geolocation. + */ + public static final double MAX_WRAP_LONGITUDE = 180; + + /** + * This constant represents the lowest longitude value available to represent a geolocation. + */ + public static final double MIN_LONGITUDE = -Double.MAX_VALUE; + + /** + * This constant represents the highest longitude value available to represent a geolocation. + */ + public static final double MAX_LONGITUDE = Double.MAX_VALUE; + + /** + * This constant represents the lowest latitude value available to represent a geolocation. + */ + public static final double MIN_LATITUDE = -90; + + /** + * This constant represents the latitude span when representing a geolocation. + */ + public static final double LATITUDE_SPAN = 180; + + /** + * This constant represents the longitude span when representing a geolocation. + */ + public static final double LONGITUDE_SPAN = 360; + + /** + * This constant represents the highest latitude value available to represent a geolocation. + */ + public static final double MAX_LATITUDE = 90; + + /** + * Maximum latitude value in Mercator projection. + */ + public static final double MAX_MERCATOR_LATITUDE = 85.05112877980659; + + /** + * Minimum latitude value in Mercator projection. + */ + public static final double MIN_MERCATOR_LATITUDE = -85.05112877980659; + + private GeometryConstants() { + // Private constructor to prevent initializing of this class. + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java new file mode 100644 index 000000000..6156b3af7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -0,0 +1,232 @@ +package com.mapbox.mapboxsdk.constants; + +import java.util.Locale; + +/** + * MapboxConstants exposes Mapbox related constants + */ +public class MapboxConstants { + + /** + * Default Locale for data processing (ex: String.toLowerCase(MAPBOX_LOCALE, "foo")) + */ + public static final Locale MAPBOX_LOCALE = Locale.US; + + /** + * The name of the desired preferences file for Android's SharedPreferences. + */ + public static final String MAPBOX_SHARED_PREFERENCES = "MapboxSharedPreferences"; + + /** + * Key used to switch storage to external in AndroidManifest.xml + */ + public static final String KEY_META_DATA_SET_STORAGE_EXTERNAL = "com.mapbox.SetStorageExternal"; + + /** + * Default value for KEY_META_DATA_SET_STORAGE_EXTERNAL (default is internal storage) + */ + public static final boolean DEFAULT_SET_STORAGE_EXTERNAL = false; + + /** + * Key used to switch Tile Download Measuring on/off in AndroidManifest.xml + */ + public static final String KEY_META_DATA_MEASURE_TILE_DOWNLOAD_ON = "com.mapbox.MeasureTileDownloadOn"; + + /** + * Default value for KEY_META_DATA_MEASURE_TILE_DOWNLOAD_ON (default is off) + */ + public static final boolean DEFAULT_MEASURE_TILE_DOWNLOAD_ON = false; + + public static final String KEY_PREFERENCE_SKU_TOKEN = "com.mapbox.mapboxsdk.accounts.skutoken"; + + public static final String KEY_META_DATA_MANAGE_SKU_TOKEN = "com.mapbox.ManageSkuToken"; + + public static final boolean DEFAULT_MANAGE_SKU_TOKEN = true; + + /** + * Default value for font fallback for local ideograph fonts + */ + public static final String DEFAULT_FONT = "sans-serif"; + + /** + * Unmeasured state + */ + public static final float UNMEASURED = -1f; + + /** + * Default animation time + */ + public static final int ANIMATION_DURATION = 300; + + /** + * Default short animation time + */ + public static final int ANIMATION_DURATION_SHORT = 150; + + /** + * Animation time of a fling gesture + */ + public static final long ANIMATION_DURATION_FLING_BASE = ANIMATION_DURATION_SHORT; + + /** + * Velocity threshold for a fling gesture + */ + public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; + + /** + * Value by which the default rotation threshold will be increased when scaling + * + * @deprecated unused, see {@link com.mapbox.mapboxsdk.maps.UiSettings#setDisableRotateWhenScaling(boolean)} + */ + @Deprecated + public static final float ROTATION_THRESHOLD_INCREASE_WHEN_SCALING = 25f; + + /** + * Maximum absolute zoom change for multi-pointer scale velocity animation + */ + public static final double MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE = 2.5; + + /** + * Maximum possible zoom change during the quick zoom gesture executed across the whole screen + */ + public static final double QUICK_ZOOM_MAX_ZOOM_CHANGE = 4.0; + + /** + * Scale velocity animation duration multiplier. + */ + public static final double SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER = 150; + + /** + * Minimum angular velocity for rotation animation + * + * @deprecated unused, see {@link #ROTATE_VELOCITY_RATIO_THRESHOLD} + */ + @Deprecated + public static final float MINIMUM_ANGULAR_VELOCITY = 1.5f; + + /** + * Last scale span delta to XY velocity ratio required to execute scale velocity animation. + */ + public static final double SCALE_VELOCITY_RATIO_THRESHOLD = 4 * 1e-3; + + /** + * Last rotation delta to XY velocity ratio required to execute rotation velocity animation. + */ + public static final double ROTATE_VELOCITY_RATIO_THRESHOLD = 2.2 * 1e-4; + + /** + * Time within which user needs to lift fingers for velocity animation to start. + */ + public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L; + + /** + * Maximum angular velocity for rotation animation + */ + public static final float MAXIMUM_ANGULAR_VELOCITY = 30f; + + /** + * Factor to calculate tilt change based on pixel change during shove gesture. + */ + public static final float SHOVE_PIXEL_CHANGE_FACTOR = 0.1f; + + /** + * The currently supported minimum zoom level. + */ + public static final float MINIMUM_ZOOM = 0.0f; + + /** + * The currently supported maximum zoom level. + */ + public static final float MAXIMUM_ZOOM = 25.5f; + + /** + * The currently supported maximum tilt value. + */ + public static final double MAXIMUM_TILT = 60; + + /** + * The currently supported minimum tilt value. + */ + public static final double MINIMUM_TILT = 0; + + /** + * The currently supported maximum direction + */ + public static final double MAXIMUM_DIRECTION = 360; + + /** + * The currently supported minimum direction + */ + public static final double MINIMUM_DIRECTION = 0; + + /** + * The currently used minimum scale factor to clamp to when a quick zoom gesture occurs + * + * @deprecated unused + */ + @Deprecated + 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 + * + * @deprecated unused + */ + @Deprecated + public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.15f; + + /** + * Zoom value multiplier for scale gestures. + */ + public static final float ZOOM_RATE = 0.65f; + + /** + * Fragment Argument Key for MapboxMapOptions + */ + public static final String FRAG_ARG_MAPBOXMAPOPTIONS = "MapboxMapOptions"; + + /** + * Layer Id of annotations layer + */ + public static final String LAYER_ID_ANNOTATIONS = "com.mapbox.annotations.points"; + + // Save instance state keys + public static final String STATE_HAS_SAVED_STATE = "mapbox_savedState"; + public static final String STATE_CAMERA_POSITION = "mapbox_cameraPosition"; + public static final String STATE_ZOOM_ENABLED = "mapbox_zoomEnabled"; + public static final String STATE_SCROLL_ENABLED = "mapbox_scrollEnabled"; + public static final String STATE_ROTATE_ENABLED = "mapbox_rotateEnabled"; + public static final String STATE_TILT_ENABLED = "mapbox_tiltEnabled"; + public static final String STATE_DOUBLE_TAP_ENABLED = "mapbox_doubleTapEnabled"; + public static final String STATE_QUICK_ZOOM_ENABLED = "mapbox_quickZoom"; + public static final String STATE_ZOOM_RATE = "mapbox_zoomRate"; + public static final String STATE_DEBUG_ACTIVE = "mapbox_debugActive"; + public static final String STATE_COMPASS_ENABLED = "mapbox_compassEnabled"; + public static final String STATE_COMPASS_GRAVITY = "mapbox_compassGravity"; + public static final String STATE_COMPASS_MARGIN_LEFT = "mapbox_compassMarginLeft"; + public static final String STATE_COMPASS_MARGIN_TOP = "mapbox_compassMarginTop"; + public static final String STATE_COMPASS_MARGIN_RIGHT = "mapbox_compassMarginRight"; + public static final String STATE_COMPASS_MARGIN_BOTTOM = "mapbox_compassMarginBottom"; + public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "mapbox_compassFade"; + public static final String STATE_COMPASS_IMAGE_BITMAP = "mapbox_compassImage"; + public static final String STATE_LOGO_GRAVITY = "mapbox_logoGravity"; + public static final String STATE_LOGO_MARGIN_LEFT = "mapbox_logoMarginLeft"; + public static final String STATE_LOGO_MARGIN_TOP = "mapbox_logoMarginTop"; + public static final String STATE_LOGO_MARGIN_RIGHT = "mapbox_logoMarginRight"; + public static final String STATE_LOGO_MARGIN_BOTTOM = "mapbox_logoMarginBottom"; + public static final String STATE_LOGO_ENABLED = "mapbox_logoEnabled"; + public static final String STATE_ATTRIBUTION_GRAVITY = "mapbox_attrGravity"; + public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "mapbox_attrMarginLeft"; + public static final String STATE_ATTRIBUTION_MARGIN_TOP = "mapbox_attrMarginTop"; + 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_DESELECT_MARKER_ON_TAP = "mapbox_deselectMarkerOnTap"; + public static final String STATE_USER_FOCAL_POINT = "mapbox_userFocalPoint"; + public static final String STATE_SCALE_ANIMATION_ENABLED = "mapbox_scaleAnimationEnabled"; + public static final String STATE_ROTATE_ANIMATION_ENABLED = "mapbox_rotateAnimationEnabled"; + public static final String STATE_FLING_ANIMATION_ENABLED = "mapbox_flingAnimationEnabled"; + public static final String STATE_INCREASE_ROTATE_THRESHOLD = "mapbox_increaseRotateThreshold"; + public static final String STATE_DISABLE_ROTATE_WHEN_SCALING = "mapbox_disableRotateWhenScaling"; + public static final String STATE_INCREASE_SCALE_THRESHOLD = "mapbox_increaseScaleThreshold"; +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java new file mode 100644 index 000000000..3dbae9de4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java @@ -0,0 +1,14 @@ +package com.mapbox.mapboxsdk.constants; + +@Deprecated +public class TelemetryConstants { + + public static final String TWO_FINGER_TAP = "TwoFingerTap"; + public static final String DOUBLE_TAP = "DoubleTap"; + public static final String SINGLE_TAP = "SingleTap"; + public static final String PAN = "Pan"; + public static final String PINCH = "Pinch"; + public static final String ROTATION = "Rotation"; + public static final String PITCH = "Pitch"; + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/package-info.java new file mode 100644 index 000000000..165394c03 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Constant API classes. + */ +package com.mapbox.mapboxsdk.constants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java new file mode 100644 index 000000000..32e852d31 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java @@ -0,0 +1,8 @@ +package com.mapbox.mapboxsdk.exceptions; + +public class CalledFromWorkerThreadException extends RuntimeException { + + public CalledFromWorkerThreadException(String message) { + super(message); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java new file mode 100644 index 000000000..0d16c53b8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk.exceptions; + +/** + * A ConversionException is thrown when a conversion failed to execute. + */ +public class ConversionException extends RuntimeException { + + public ConversionException(String detailMessage) { + super(detailMessage); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java new file mode 100644 index 000000000..1f6b0efc4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java @@ -0,0 +1,25 @@ +package com.mapbox.mapboxsdk.exceptions; + +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.maps.MapView; + +/** + *

+ * 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. + *

+ * You cannot modify a {@code Icon} after it has been added to the map in a {@code Marker} + * + * @see MapView + * @see Icon + * @see Marker + */ +public class IconBitmapChangedException extends RuntimeException { + + public IconBitmapChangedException() { + super("The added Marker has an Icon with a bitmap that has been modified. An Icon cannot be modified" + + "after it has been added to the map in a Marker."); + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java new file mode 100644 index 000000000..c1d038581 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java @@ -0,0 +1,12 @@ +package com.mapbox.mapboxsdk.exceptions; + +/** + * An InvalidLatLngBoundsException is thrown by LatLngBounds + * when there aren't enough LatLng to create a bounds. + */ +public class InvalidLatLngBoundsException extends RuntimeException { + + public InvalidLatLngBoundsException(int latLngsListSize) { + super("Cannot create a LatLngBounds from " + latLngsListSize + " items"); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java new file mode 100644 index 000000000..44ee83265 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java @@ -0,0 +1,16 @@ +package com.mapbox.mapboxsdk.exceptions; + +/** + * A InvalidMarkerPositionException is thrown when a Marker object is created with an invalid LatLng position. + */ +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. " + + "Provide a non null LatLng as position to the Marker."); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java new file mode 100644 index 000000000..431de85f0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java @@ -0,0 +1,33 @@ +package com.mapbox.mapboxsdk.exceptions; + +import android.content.Context; +import android.support.annotation.NonNull; + +/** + * A MapboxConfigurationException is thrown by MapboxMap when the SDK hasn't been properly initialised. + *

+ * 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. + *

+ * + * @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 calling Mapbox.getInstance(Context context, String accessToken) before " + + "inflating or creating the view. The access token parameter is required when using a Mapbox service." + + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); + } + + /** + * Creates a Mapbox configuration exception thrown by MapboxMap when the SDK hasn't been properly initialised. + */ + public MapboxConfigurationException(@NonNull String message) { + super(message); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java new file mode 100644 index 000000000..bffc10dc0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java @@ -0,0 +1,20 @@ +package com.mapbox.mapboxsdk.exceptions; + +import com.mapbox.mapboxsdk.annotations.IconFactory; + +/** + *

+ * A TooManyIconsException is thrown by IconFactory when it + * cannot create a Icon because there are already too many icons created. + *

+ * You should try to reuse Icon objects whenever possible. + * + * @see IconFactory + */ +public class TooManyIconsException extends RuntimeException { + + public TooManyIconsException() { + super("Cannot create an Icon because there are already too many. Try reusing Icon objects whenever possible."); + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/package-info.java new file mode 100644 index 000000000..09ecd55c1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Exception API classes. + */ +package com.mapbox.mapboxsdk.exceptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java new file mode 100644 index 000000000..ce12489b4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -0,0 +1,334 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.FloatRange; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.constants.GeometryConstants; +import com.mapbox.turf.TurfMeasurement; + +import static com.mapbox.turf.TurfConstants.UNIT_METRES; + + +/** + * A geographical location which contains a single latitude, longitude pair, with + * optional altitude. + *

+ * Latitude and longitude are expressed as decimal degrees + * in the WGS84 datum. By default, altitude is 0.0, or sea level. + *

+ *

+ * Mapbox GL displays maps in the Mercator Projection and projects geographical + * data automatically, so all data enters in the WGS84 datum. + *

+ */ +public class LatLng implements Parcelable { + + /** + * Inner class responsible for recreating Parcels into objects. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LatLng createFromParcel(@NonNull Parcel in) { + return new LatLng(in); + } + + public LatLng[] newArray(int size) { + return new LatLng[size]; + } + }; + + @Keep + private double latitude; + @Keep + private double longitude; + private double altitude = 0.0; + + /** + * Construct a new latitude, longitude point at (0, 0) + */ + public LatLng() { + this.latitude = 0.0; + this.longitude = 0.0; + } + + /** + * Construct a new latitude, longitude point given double arguments + * + * @param latitude Latitude in degrees + * @param longitude Longitude in degrees + */ + @Keep + public LatLng(double latitude, double longitude) { + setLatitude(latitude); + setLongitude(longitude); + } + + /** + * Construct a new latitude, longitude, altitude point given double arguments + * + * @param latitude Latitude in degrees + * @param longitude Longitude in degress + * @param altitude Altitude in meters + */ + public LatLng(double latitude, double longitude, double altitude) { + setLatitude(latitude); + setLongitude(longitude); + setAltitude(altitude); + } + + /** + * Construct a new latitude, longitude, altitude point given location argument + * + * @param location Android Location + */ + public LatLng(Location location) { + this(location.getLatitude(), location.getLongitude(), location.getAltitude()); + } + + /** + * Construct a new latitude, longitude, altitude point given another latitude, longitude, altitude point. + * + * @param latLng LatLng to be cloned. + */ + 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()); + } + + /** + * Set the latitude, in degrees. + *

+ * This value is in the range of [-90, 90], see {@link GeometryConstants#MIN_LATITUDE} and + * {@link GeometryConstants#MAX_LATITUDE} + *

+ * + * @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) > GeometryConstants.MAX_LATITUDE) { + throw new IllegalArgumentException("latitude must be between -90 and 90"); + } + this.latitude = latitude; + } + + /** + * Get the latitude, in degrees. + *

+ * This value is in the range of [-90, 90], see {@link GeometryConstants#MIN_LATITUDE} and + * {@link GeometryConstants#MAX_LATITUDE} + *

+ * + * @return the latitude value in degrees + * @see GeometryConstants#MIN_LATITUDE + * @see GeometryConstants#MAX_LATITUDE + */ + public double getLatitude() { + return latitude; + } + + /** + * Set the longitude, in degrees. + *

+ * This value is in the range of [-180, 180], see {@link GeometryConstants#MIN_LONGITUDE} and + * {@link GeometryConstants#MAX_LONGITUDE} + *

+ * + * @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"); + } + if (Double.isInfinite(longitude)) { + throw new IllegalArgumentException("longitude must not be infinite"); + } + this.longitude = longitude; + } + + /** + * Get the longitude, in degrees. + *

+ * This value is in the range of [-180, 180], see {@link GeometryConstants#MIN_LONGITUDE} and + * {@link GeometryConstants#MAX_LONGITUDE} + *

+ * + * @return the longitude value in degrees + * @see GeometryConstants#MIN_LONGITUDE + * @see GeometryConstants#MAX_LONGITUDE + */ + 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 + */ + public double getAltitude() { + return altitude; + } + + /** + * Return a new LatLng object with a wrapped Longitude. This allows original data object + * to remain unchanged. + * + * @return new LatLng object with wrapped Longitude + */ + @NonNull + public LatLng wrap() { + return new LatLng(latitude, wrap(longitude, + GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE) + ); + } + + + /** + * Constrains value to the given range (including min & max) via modular arithmetic. + *

+ * 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(@Nullable Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + LatLng latLng = (LatLng) object; + + return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 + && 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; + long temp; + temp = Double.doubleToLongBits(latitude); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(longitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(altitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + /** + * Returns a string representation of the object. + * + * @return the string representation + */ + @NonNull + @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(@NonNull Parcel out, int flags) { + out.writeDouble(latitude); + out.writeDouble(longitude); + out.writeDouble(altitude); + } + + /** + * Calculate distance between two points + * + * @param other Other LatLng to compare to + * @return distance in meters + */ + public double distanceTo(@NonNull LatLng other) { + return TurfMeasurement.distance( + Point.fromLngLat(longitude, latitude), + Point.fromLngLat(other.getLongitude(), other.getLatitude()), + UNIT_METRES + ); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java new file mode 100644 index 000000000..263780f47 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -0,0 +1,608 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.FloatRange; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.constants.GeometryConstants; +import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; + +import java.util.ArrayList; +import java.util.List; + +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MAX_LATITUDE; +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MAX_LONGITUDE; +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MAX_WRAP_LONGITUDE; +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MIN_LATITUDE; +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MIN_LONGITUDE; +import static com.mapbox.mapboxsdk.constants.GeometryConstants.MIN_WRAP_LONGITUDE; + +/** + * A geographical area representing a latitude/longitude aligned rectangle. + *

+ * This class does not wrap values to the world bounds. + *

+ */ +public class LatLngBounds implements Parcelable { + + @Keep + private final double latitudeNorth; + @Keep + private final double latitudeSouth; + @Keep + private final double longitudeEast; + @Keep + private final double longitudeWest; + + /** + * Construct a new LatLngBounds based on its corners, given in NESW + * order. + *

+ * @since 7.0.0 LatLngBounds cannot be wrapped any more, i.e longitudeWest has to be + * less or equal to longitudeEast. + * + * For example, to represent bounds spanning 20 degrees crossing antimeridian with + * the NE point as (10, -170) and the SW point as (-10, 170), + * use (10, -190) and (-10, -170), or (10, -170) and (-10, -150). + * + * @param northLatitude Northern Latitude + * @param eastLongitude Eastern Longitude + * @param southLatitude Southern Latitude + * @param westLongitude Western Longitude + */ + @Keep + LatLngBounds(final double northLatitude, final double eastLongitude, + final double southLatitude, final double westLongitude) { + this.latitudeNorth = northLatitude; + this.longitudeEast = eastLongitude; + this.latitudeSouth = southLatitude; + this.longitudeWest = westLongitude; + } + + /** + * Returns the world bounds. + * + * @return the bounds representing the world + */ + public static LatLngBounds world() { + return LatLngBounds.from( + MAX_LATITUDE, MAX_WRAP_LONGITUDE, + MIN_LATITUDE, MIN_WRAP_LONGITUDE); + } + + /** + * Calculates the centerpoint of this LatLngBounds by simple interpolation and returns + * it as a point. This is a non-geodesic calculation which is not the geographic center. + * + * @return LatLng center of this LatLngBounds + */ + @NonNull + public LatLng getCenter() { + double latCenter = (this.latitudeNorth + this.latitudeSouth) / 2.0; + double longCenter = (this.longitudeEast + this.longitudeWest) / 2.0; + + return new LatLng(latCenter, longCenter); + } + + /** + * Get the north latitude value of this bounds. + * + * @return double latitude value for north + */ + public double getLatNorth() { + return this.latitudeNorth; + } + + /** + * Get the south latitude value of this bounds. + * + * @return double latitude value for south + */ + public double getLatSouth() { + return this.latitudeSouth; + } + + /** + * Get the east longitude value of this bounds. + * + * @return double longitude value for east + */ + public double getLonEast() { + return this.longitudeEast; + } + + /** + * Get the west longitude value of this bounds. + * + * @return double longitude value for west + */ + public double getLonWest() { + return this.longitudeWest; + } + + /** + * Get the latitude-longitude pair of the south west corner of this bounds. + * + * @return LatLng of the south west corner + */ + @NonNull + public LatLng getSouthWest() { + return new LatLng(latitudeSouth, longitudeWest); + } + + /** + * Get the latitude-longitude paur if the north east corner of this bounds. + * + * @return LatLng of the north east corner + */ + @NonNull + public LatLng getNorthEast() { + return new LatLng(latitudeNorth, longitudeEast); + } + + /** + * Get the latitude-longitude pair of the south east corner of this bounds. + * + * @return LatLng of the south east corner + */ + @NonNull + public LatLng getSouthEast() { + return new LatLng(latitudeSouth, longitudeEast); + } + + /** + * Get the latitude-longitude pair of the north west corner of this bounds. + * + * @return LatLng of the north west corner + */ + @NonNull + public LatLng getNorthWest() { + return new LatLng(latitudeNorth, longitudeWest); + } + + /** + * Get the area spanned by this LatLngBounds + * + * @return LatLngSpan area + */ + @NonNull + public LatLngSpan getSpan() { + return new LatLngSpan(getLatitudeSpan(), getLongitudeSpan()); + } + + /** + * Get the absolute distance, in degrees, between the north and + * south boundaries of this LatLngBounds + * + * @return Span distance + */ + public double getLatitudeSpan() { + return Math.abs(this.latitudeNorth - this.latitudeSouth); + } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this LatLngBounds + * + * @return Span distance + */ + public double getLongitudeSpan() { + return Math.abs(this.longitudeEast - this.longitudeWest); + } + + /** + * Validate if LatLngBounds is empty, determined if absolute distance is + * + * @return boolean indicating if span is empty + */ + public boolean isEmptySpan() { + return getLongitudeSpan() == 0.0 || getLatitudeSpan() == 0.0; + } + + /** + * Returns a string representaton of the object. + * + * @return the string representation + */ + @NonNull + @Override + public String toString() { + return "N:" + this.latitudeNorth + "; E:" + this.longitudeEast + "; S:" + this.latitudeSouth + + "; W:" + this.longitudeWest; + } + + /** + * Constructs a LatLngBounds that contains all of a list of LatLng + * objects. Empty lists will yield invalid LatLngBounds. + * + * @param latLngs List of LatLng objects + * @return LatLngBounds + */ + static LatLngBounds fromLatLngs(final List latLngs) { + double minLat = MAX_LATITUDE; + double minLon = MAX_LONGITUDE; + double maxLat = MIN_LATITUDE; + double maxLon = MIN_LONGITUDE; + + for (final LatLng gp : latLngs) { + final double latitude = gp.getLatitude(); + final double longitude = gp.getLongitude(); + minLat = Math.min(minLat, latitude); + minLon = Math.min(minLon, longitude); + maxLat = Math.max(maxLat, latitude); + maxLon = Math.max(maxLon, longitude); + } + + return new LatLngBounds(maxLat, maxLon, minLat, minLon); + } + + /** + * Return an array of LatLng objects resembling this bounds. + * + * @return an array of 2 LatLng objects. + */ + @NonNull + public LatLng[] toLatLngs() { + return new LatLng[] {getNorthEast(), getSouthWest()}; + } + + /** + * Constructs a LatLngBounds from doubles representing a LatLng pair. + *

+ * This values of latNorth and latSouth should be in the range of [-90, 90], + * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, + * otherwise IllegalArgumentException will be thrown. + * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. + *

+ * This method doesn't recalculate most east or most west boundaries. + * Note @since 7.0.0 lonEast and lonWest will NOT be wrapped to be in the range of [-180, 180], + * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE} + * lonEast should be greater or equal lonWest, otherwise IllegalArgumentException will be thrown. + *

+ */ + public static LatLngBounds from( + @FloatRange(from = MIN_LATITUDE, to = MAX_LATITUDE) double latNorth, + double lonEast, + @FloatRange(from = MIN_LATITUDE, to = MAX_LATITUDE) double latSouth, + double lonWest) { + + checkParams(latNorth, lonEast, latSouth, lonWest); + + return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); + } + + private static void checkParams( + @FloatRange(from = MIN_LATITUDE, to = MAX_LATITUDE) double latNorth, + double lonEast, + @FloatRange(from = MIN_LATITUDE, to = MAX_LATITUDE) double latSouth, + double lonWest) { + + if (Double.isNaN(latNorth) || Double.isNaN(latSouth)) { + throw new IllegalArgumentException("latitude must not be NaN"); + } + + if (Double.isNaN(lonEast) || Double.isNaN(lonWest)) { + throw new IllegalArgumentException("longitude must not be NaN"); + } + + if (Double.isInfinite(lonEast) || Double.isInfinite(lonWest)) { + throw new IllegalArgumentException("longitude must not be infinite"); + } + + if (latNorth > MAX_LATITUDE || latNorth < MIN_LATITUDE + || latSouth > MAX_LATITUDE || latSouth < MIN_LATITUDE) { + throw new IllegalArgumentException("latitude must be between -90 and 90"); + } + + if (latNorth < latSouth) { + throw new IllegalArgumentException("latNorth cannot be less than latSouth"); + } + + if (lonEast < lonWest) { + throw new IllegalArgumentException("lonEast cannot be less than 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_WRAP_LONGITUDE; + } + + /** + * Constructs a LatLngBounds from a Tile identifier. + *

+ * Returned bounds will have latitude in the range of Mercator projection. + * + * @param z Tile zoom level. + * @param x Tile X coordinate. + * @param y Tile Y coordinate. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE + */ + 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. + * @return the newly constructed bounds + */ + @NonNull + public LatLngBounds include(@NonNull LatLng latLng) { + return new LatLngBounds.Builder() + .include(getNorthEast()) + .include(getSouthWest()) + .include(latLng) + .build(); + } + + /** + * Determines whether this LatLngBounds matches another one via LatLng. + * + * @param o another object + * @return a boolean indicating whether the LatLngBounds are equal + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o instanceof LatLngBounds) { + LatLngBounds other = (LatLngBounds) o; + return latitudeNorth == other.getLatNorth() + && latitudeSouth == other.getLatSouth() + && longitudeEast == other.getLonEast() + && longitudeWest == other.getLonWest(); + } + return false; + } + + + private boolean containsLatitude(final double latitude) { + return (latitude <= this.latitudeNorth) + && (latitude >= this.latitudeSouth); + } + + private boolean containsLongitude(final double longitude) { + return (longitude <= this.longitudeEast) + && (longitude >= this.longitudeWest); + } + + /** + * Determines whether this LatLngBounds contains a point. + * + * @param latLng the point which may be contained + * @return true, if the point is contained within the bounds + */ + public boolean contains(@NonNull final LatLng latLng) { + return containsLatitude(latLng.getLatitude()) + && containsLongitude(latLng.getLongitude()); + } + + /** + * Determines whether this LatLngBounds contains another bounds. + * + * @param other the bounds which may be contained + * @return true, if the bounds is contained within the bounds + */ + public boolean contains(@NonNull final LatLngBounds other) { + return contains(other.getNorthEast()) + && contains(other.getSouthWest()); + } + + /** + * Returns a new LatLngBounds that stretches to contain both this and another LatLngBounds. + * + * @param bounds LatLngBounds to add + * @return LatLngBounds + */ + @NonNull + public LatLngBounds union(@NonNull LatLngBounds bounds) { + return unionNoParamCheck(bounds.getLatNorth(), bounds.getLonEast(), + bounds.getLatSouth(), bounds.getLonWest()); + } + + /** + * Returns a new LatLngBounds that stretches to contain both this and another LatLngBounds. + * + *

+ * This values of northLat and southLat should be in the range of [-90, 90], + * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, + * otherwise IllegalArgumentException will be thrown. + * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown. + * + *

+ * eastLon should be greater or equal westLon, otherwise IllegalArgumentException will be thrown. + * + * @param northLat Northern Latitude corner point + * @param eastLon Eastern Longitude corner point + * @param southLat Southern Latitude corner point + * @param westLon Western Longitude corner point + * @return LatLngBounds + */ + @NonNull + public LatLngBounds union(final double northLat, final double eastLon, + final double southLat, final double westLon) { + checkParams(northLat, eastLon, southLat, westLon); + return unionNoParamCheck(northLat, eastLon, southLat, westLon); + } + + private LatLngBounds unionNoParamCheck(final double northLat, final double eastLon, + final double southLat, final double westLon) { + + return new LatLngBounds((this.latitudeNorth < northLat) ? northLat : this.latitudeNorth, + (this.longitudeEast < eastLon) ? eastLon : this.longitudeEast, + (this.latitudeSouth > southLat) ? southLat : this.latitudeSouth, + (this.longitudeWest > westLon) ? westLon : this.longitudeWest); + } + + /** + * Returns a new LatLngBounds that is the intersection of this with another LatLngBounds, + * + * @param box LatLngBounds to intersect with + * @return LatLngBounds + */ + @Nullable + public LatLngBounds intersect(@NonNull LatLngBounds box) { + return intersectNoParamCheck(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest()); + } + + + /** + * Returns a new LatLngBounds that is the intersection of this with another box. + * + *

+ * This values of northLat and southLat should be in the range of [-90, 90], + * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, + * otherwise IllegalArgumentException will be thrown. + * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown. + * + *

+ * eastLon should be greater or equal westLon, otherwise IllegalArgumentException will be thrown. + * + * @param northLat Northern Latitude corner point + * @param eastLon Eastern Longitude corner point + * @param southLat Southern Latitude corner point + * @param westLon Western Longitude corner point + * @return LatLngBounds + */ + @NonNull + public LatLngBounds intersect(final double northLat, final double eastLon, + final double southLat, final double westLon) { + checkParams(northLat, eastLon, southLat, westLon); + return intersectNoParamCheck(northLat, eastLon, southLat, westLon); + } + + private LatLngBounds intersectNoParamCheck(final double northLat, final double eastLon, + final double southLat, final double westLon) { + + double minLonWest = Math.max(this.longitudeWest, westLon); + double maxLonEast = Math.min(this.longitudeEast, eastLon); + if (maxLonEast >= minLonWest) { + double minLatSouth = Math.max(this.latitudeSouth, southLat); + double maxLatNorth = Math.min(this.latitudeNorth, northLat); + if (maxLatNorth >= minLatSouth) { + return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest); + } + } + return null; + } + + + + /** + * Inner class responsible for recreating Parcels into objects. + */ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public LatLngBounds createFromParcel(@NonNull final Parcel in) { + return readFromParcel(in); + } + + @Override + public LatLngBounds[] newArray(final int size) { + return new LatLngBounds[size]; + } + }; + + /** + * Returns a hash code value for the object. + * + * @return the hash code + */ + @Override + public int hashCode() { + return (int) ((latitudeNorth + 90) + + ((latitudeSouth + 90) * 1000) + + ((longitudeEast + 180) * 1000000) + + ((longitudeWest + 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(@NonNull 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) { + final double northLat = in.readDouble(); + final double eastLon = in.readDouble(); + final double southLat = in.readDouble(); + final double westLon = in.readDouble(); + return new LatLngBounds(northLat, eastLon, southLat, westLon); + } + + /** + * Builder for composing LatLngBounds objects. + */ + public static final class Builder { + + private final List latLngList = new ArrayList<>(); + + /** + * Builds a new LatLngBounds. + *

+ * Throws an {@link InvalidLatLngBoundsException} when no LatLngBounds can be created. + *

+ * + * @return the build LatLngBounds + */ + public LatLngBounds build() { + if (latLngList.size() < 2) { + throw new InvalidLatLngBoundsException(latLngList.size()); + } + return LatLngBounds.fromLatLngs(latLngList); + } + + /** + * Adds a LatLng object to the LatLngBounds.Builder. + * + * @param latLngs the List of LatLng objects to be added + * @return this + */ + @NonNull + public Builder includes(@NonNull List latLngs) { + latLngList.addAll(latLngs); + return this; + } + + /** + * Adds a LatLng object to the LatLngBounds.Builder. + * + * @param latLng the LatLng to be added + * @return this + */ + @NonNull + public Builder include(@NonNull LatLng latLng) { + latLngList.add(latLng); + return this; + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java new file mode 100644 index 000000000..d17d0d6fe --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java @@ -0,0 +1,94 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; + +/** + * A geographical area representing a non-aligned quadrilateral + *

+ * This class does not wrap values to the world bounds + *

+ */ +public class LatLngQuad implements Parcelable { + + @Keep + private final LatLng topLeft; + @Keep + private final LatLng topRight; + @Keep + private final LatLng bottomRight; + @Keep + private final LatLng bottomLeft; + + /** + * Construct a new LatLngQuad based on its corners, + * in order top left, top right, bottom left, bottom right + */ + @Keep + public LatLngQuad(final LatLng topLeft, final LatLng topRight, final LatLng bottomRight, final LatLng bottomLeft) { + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomRight = bottomRight; + this.bottomLeft = bottomLeft; + } + + public LatLng getTopLeft() { + return this.topLeft; + } + + public LatLng getTopRight() { + return this.topRight; + } + + public LatLng getBottomRight() { + return this.bottomRight; + } + + public LatLng getBottomLeft() { + return this.bottomLeft; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public LatLngQuad createFromParcel(@NonNull final Parcel in) { + return readFromParcel(in); + } + + @Override + public LatLngQuad[] newArray(final int size) { + return new LatLngQuad[size]; + } + }; + + @Override + public int hashCode() { + int code = topLeft.hashCode(); + code = (code ^ code >>> 31) + topRight.hashCode(); + code = (code ^ code >>> 31) + bottomRight.hashCode(); + code = (code ^ code >>> 31) + bottomLeft.hashCode(); + return code; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull final Parcel out, final int arg1) { + topLeft.writeToParcel(out, arg1); + topRight.writeToParcel(out, arg1); + bottomRight.writeToParcel(out, arg1); + bottomLeft.writeToParcel(out, arg1); + } + + private static LatLngQuad readFromParcel(@NonNull final Parcel in) { + final LatLng topLeft = new LatLng(in); + final LatLng topRight = new LatLng(in); + final LatLng bottomRight = new LatLng(in); + final LatLng bottomLeft = new LatLng(in); + return new LatLngQuad(topLeft, topRight, bottomRight, bottomLeft); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java new file mode 100644 index 000000000..941e6652f --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java @@ -0,0 +1,139 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +/** + * A geographical span defined by its latitude and longitude span. + */ +public class LatLngSpan implements Parcelable { + + private double mLatitudeSpan; + private double mLongitudeSpan; + + private LatLngSpan(@NonNull Parcel in) { + mLatitudeSpan = in.readDouble(); + mLongitudeSpan = in.readDouble(); + } + + /** + * Creates a LatLgnSpan. + * + * @param latitudeSpan The span used for latitude. + * @param longitudeSpan The span used for longitude. + */ + public LatLngSpan(double latitudeSpan, double longitudeSpan) { + mLatitudeSpan = latitudeSpan; + mLongitudeSpan = longitudeSpan; + } + + /** + * Returns the latitude span. + * + * @return The latitude span. + */ + public double getLatitudeSpan() { + return mLatitudeSpan; + } + + /** + * Sets the latitude span. + * + * @param latitudeSpan The latitude span to set. + */ + public void setLatitudeSpan(double latitudeSpan) { + mLatitudeSpan = latitudeSpan; + } + + /** + * Returns to longitude span. + * + * @return The longitude span. + */ + public double getLongitudeSpan() { + return mLongitudeSpan; + } + + /** + * Sets the longitude span. + * + * @param longitudeSpan The longitude span to set. + */ + public void setLongitudeSpan(double longitudeSpan) { + 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 object) { + if (this == object) { + return true; + } + 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 CREATOR = + new Parcelable.Creator() { + @Override + public LatLngSpan createFromParcel(@NonNull Parcel in) { + return new LatLngSpan(in); + } + + @Override + public LatLngSpan[] newArray(int size) { + return new LatLngSpan[size]; + } + }; + + /** + * 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(@NonNull 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/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java new file mode 100644 index 000000000..745a7c6be --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java @@ -0,0 +1,155 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +/** + * ProjectedMeters is a projection of longitude, latitude points in Mercator meters. + *

+ * these have been projected into Mapbox GL's Mercator projection. Instead of decimal + * degrees, it uses Mercator meters (which are notably not equivalent to SI meters) + * except at the equator. + *

+ */ +public class ProjectedMeters implements Parcelable { + + /** + * Inner class responsible for recreating Parcels into objects. + */ + public static final Creator CREATOR = new Creator() { + public ProjectedMeters createFromParcel(@NonNull Parcel in) { + return new ProjectedMeters(in); + } + + public ProjectedMeters[] newArray(int size) { + return new ProjectedMeters[size]; + } + }; + + private double northing; + private double easting; + + /** + * Creates a ProjectedMeters based on projected meters in north and east direction. + * + * @param northing the northing in meters + * @param easting the easting in meters + */ + @Keep + public ProjectedMeters(double northing, double easting) { + this.northing = northing; + this.easting = easting; + } + + /** + * Creates a ProjecteMeters based on another set of projected meters. + * + * @param projectedMeters The projected meters to be based on. + */ + public ProjectedMeters(ProjectedMeters projectedMeters) { + this.northing = projectedMeters.northing; + 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(); + } + + /** + * Get projected meters in north direction. + * + * @return Projected meters in north. + */ + public double getNorthing() { + return northing; + } + + /** + * Get projected meters in east direction. + * + * @return Projected meters in east. + */ + public double getEasting() { + 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(@Nullable Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + 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; + long temp; + temp = Double.doubleToLongBits(easting); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(northing); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + /** + * Returns a string representation of the object. + * + * @return the string representation of this + */ + @NonNull + @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(@NonNull Parcel out, int flags) { + out.writeDouble(northing); + out.writeDouble(easting); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java new file mode 100644 index 000000000..a8b4421ee --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java @@ -0,0 +1,161 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +/** + * Contains the four points defining the four-sided polygon that is visible in a map's camera. + * This polygon can be a trapezoid instead of a rectangle, because a camera can have tilt. + * If the camera is directly over the center of the camera, the shape is rectangular, + * but if the camera is tilted, the shape will appear to be a trapezoid whose + * smallest side is closest to the point of view. + */ +public class VisibleRegion implements Parcelable { + + /** + * LatLng object that defines the far left corner of the camera. + */ + public final LatLng farLeft; + + /** + * LatLng object that defines the far right corner of the camera. + */ + public final LatLng farRight; + + /** + * LatLng object that defines the bottom left corner of the camera. + */ + public final LatLng nearLeft; + + /** + * LatLng object that defines the bottom right corner of the camera. + */ + public final LatLng nearRight; + + /** + * The smallest bounding box that includes the visible region defined in this class. + */ + 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()); + this.nearLeft = in.readParcelable(LatLng.class.getClassLoader()); + this.nearRight = in.readParcelable(LatLng.class.getClassLoader()); + this.latLngBounds = in.readParcelable(LatLngBounds.class.getClassLoader()); + } + + /** + * 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. + * @param nearLeft A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param nearRight A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param latLngBounds The smallest bounding box that includes the visible region defined in this class. + */ + public VisibleRegion(LatLng farLeft, LatLng farRight, LatLng nearLeft, LatLng nearRight, LatLngBounds latLngBounds) { + this.farLeft = farLeft; + this.farRight = farRight; + this.nearLeft = nearLeft; + this.nearRight = nearRight; + this.latLngBounds = latLngBounds; + } + + /** + * Compares this VisibleRegion to another object. + * If the other object is actually a pointer to this object, + * or if all four corners and the bounds of the two objects are the same, + * this method returns true. Otherwise, this method returns false. + * + * @param o The Object to compare with. + * @return true if both objects are the same object. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof VisibleRegion)) { + return false; + } + if (o == this) { + return true; + } + + VisibleRegion visibleRegion = (VisibleRegion) o; + return farLeft.equals(visibleRegion.farLeft) + && farRight.equals(visibleRegion.farRight) + && nearLeft.equals(visibleRegion.nearLeft) + && nearRight.equals(visibleRegion.nearRight) + && latLngBounds.equals(visibleRegion.latLngBounds); + } + + /** + * The string representation of the object. + * + * @return the string representation of this + */ + @NonNull + @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) + + ((farRight.hashCode() + 90) * 1000) + + ((nearLeft.hashCode() + 180) * 1000000) + + ((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(@NonNull Parcel out, int flags) { + out.writeParcelable(farLeft, flags); + out.writeParcelable(farRight, flags); + out.writeParcelable(nearLeft, flags); + out.writeParcelable(nearRight, flags); + out.writeParcelable(latLngBounds, flags); + } + + /** + * Inner class responsible for recreating Parcels into objects. + */ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public VisibleRegion createFromParcel(@NonNull Parcel in) { + return new VisibleRegion(in); + } + + public VisibleRegion[] newArray(int size) { + return new VisibleRegion[size]; + } + }; + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/package-info.java new file mode 100644 index 000000000..754af7659 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Geometry API classes. + */ +package com.mapbox.mapboxsdk.geometry; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java new file mode 100644 index 000000000..5f4f85ea7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java @@ -0,0 +1,39 @@ +package com.mapbox.mapboxsdk.http; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.Mapbox; + +public class HttpIdentifier { + + private HttpIdentifier() { + } + + /** + * Returns the application identifier, consisting out the package name, version name and version code. + * + * @return the application identifier + */ + public static String getIdentifier() { + return getIdentifier(Mapbox.getApplicationContext()); + } + + /** + * Returns the application identifier, consisting out the package name, version name and version code. + * + * @param context the context used to retrieve the package manager from + * @return the application identifier + */ + private static String getIdentifier(@NonNull Context context) { + try { + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode); + } catch (Exception exception) { + MapStrictMode.strictModeViolation(exception); + return ""; + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java new file mode 100644 index 000000000..2f44694f0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java @@ -0,0 +1,35 @@ +package com.mapbox.mapboxsdk.http; + +import android.util.Log; +import com.mapbox.mapboxsdk.log.Logger; + +import static com.mapbox.mapboxsdk.http.HttpRequest.CONNECTION_ERROR; +import static com.mapbox.mapboxsdk.http.HttpRequest.TEMPORARY_ERROR; + +public class HttpLogger { + + private static final String TAG = "Mbgl-HttpRequest"; + + public static boolean logRequestUrl; + public static boolean logEnabled = true; + + private HttpLogger(){ + } + + public static void logFailure(int type, String errorMessage, String requestUrl) { + log(type == TEMPORARY_ERROR ? Log.DEBUG : type == CONNECTION_ERROR ? Log.INFO : Log.WARN, + String.format( + "Request failed due to a %s error: %s %s", + type == TEMPORARY_ERROR ? "temporary" : type == CONNECTION_ERROR ? "connection" : "permanent", + errorMessage, + logRequestUrl ? requestUrl : "" + ) + ); + } + + public static void log(int type, String errorMessage) { + if (logEnabled) { + Logger.log(type, TAG, errorMessage); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java new file mode 100644 index 000000000..1fd4f43cd --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.http; + +/** + * Interface definition for performing http requests. + *

+ * This allows to provide alternative implementations for the http interaction of this library. + *

+ */ +public interface HttpRequest { + + int CONNECTION_ERROR = 0; + int TEMPORARY_ERROR = 1; + int PERMANENT_ERROR = 2; + + /** + * Executes the request. + * + * @param httpRequest callback to be invoked when we receive a response + * @param nativePtr the pointer associated to the request + * @param resourceUrl the resource url to download + * @param etag http header, identifier for a specific version of a resource + * @param modified http header, used to determine if a resource hasn't been modified since + * @param offlineUsage flag to indicate a resource will be used for offline, appends offline=true as a query parameter + */ + void executeRequest(HttpResponder httpRequest, long nativePtr, String resourceUrl, + String etag, String modified, boolean offlineUsage); + + /** + * Cancels the request. + */ + void cancelRequest(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java new file mode 100644 index 000000000..1faf8f5e5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java @@ -0,0 +1,53 @@ +package com.mapbox.mapboxsdk.http; + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.Mapbox; + +public class HttpRequestUrl { + + private HttpRequestUrl() { + } + + /** + * Adapts a resource request url based on the host, query size, and offline requirement. + * Mapbox resources downloaded for offline use are subject to separate Vector Tile and + * Raster Tile API pricing and are not included in the Maps SDK’s “unlimited” requests. + * See our pricing page for more information. + * + * @param host the host used as endpoint + * @param resourceUrl the resource to download + * @param querySize the query size of the resource request + * @param offline the type of resource, either offline or online + * @return the adapted resource url + */ + public static String buildResourceUrl(@NonNull String host, String resourceUrl, int querySize, boolean offline) { + if (isValidMapboxEndpoint(host)) { + if (querySize == 0) { + resourceUrl = resourceUrl + "?"; + } else { + resourceUrl = resourceUrl + "&"; + } + // Only add SKU token to requests not tagged as "offline" usage. + if (offline) { + resourceUrl = resourceUrl + "offline=true"; + } else { + resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken(); + } + } + return resourceUrl; + } + + /** + * Validates if the host used as endpoint is a valid Mapbox endpoint. + * + * @param host the host used as endpoint + * @return true if a valid Mapbox endpoint + */ + private static boolean isValidMapboxEndpoint(String host) { + return host.equals("mapbox.com") + || host.endsWith(".mapbox.com") + || host.equals("mapbox.cn") + || host.endsWith(".mapbox.cn"); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java new file mode 100644 index 000000000..a050e07c5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.http; + +/** + * Interface definition for a callback to be invoked when either a response was returned for a requested resource or + * when an error occurred when requesting the resource. + */ +public interface HttpResponder { + + /** + * Invoked when a resource has finished. + * + * @param responseCode http response code + * @param eTag http header, identifier for a specific version of a resource + * @param lastModified http header, used to determine if a resource hasn't been modified since + * @param cacheControl http header, used to determine cache strategy of a resource + * @param expires http header, used to determine when a resource is stale + * @param retryAfter http header, used to indicate when the service is expected to be unavailable to the client + * @param xRateLimitReset http header, used to determine the remaining window before the rate limit resets + * @param body http response body, in an array of bytes representation + */ + void onResponse(int responseCode, String eTag, String lastModified, String cacheControl, String expires, + String retryAfter, String xRateLimitReset, byte[] body); + + /** + * Invoked when a resource failed to be retrieved. + * + * @param type the error type, either one of {@link HttpRequest#CONNECTION_ERROR}, + * {@link HttpRequest#TEMPORARY_ERROR} or {@link HttpRequest#PERMANENT_ERROR} + * @param errorMessage the error message associated with the failure + */ + void handleFailure(int type, String errorMessage); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java new file mode 100644 index 000000000..2d9fe43ad --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java @@ -0,0 +1,75 @@ +package com.mapbox.mapboxsdk.http; + +import android.content.res.AssetManager; +import android.os.AsyncTask; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.log.Logger; + +import java.io.IOException; +import java.io.InputStream; + +class LocalRequestTask extends AsyncTask { + + private static final String TAG = "Mbgl-LocalRequestTask"; + + private OnLocalRequestResponse requestResponse; + + LocalRequestTask(OnLocalRequestResponse requestResponse) { + this.requestResponse = requestResponse; + } + + @Nullable + @Override + protected byte[] doInBackground(String... strings) { + return loadFile(Mapbox.getApplicationContext().getAssets(), + "integration/" + strings[0] + .substring(8) + .replaceAll("%20", " ") + .replaceAll("%2c", ",")); + } + + @Override + protected void onPostExecute(@Nullable byte[] bytes) { + super.onPostExecute(bytes); + if (bytes != null && requestResponse != null) { + requestResponse.onResponse(bytes); + } + } + + @Nullable + private static byte[] loadFile(AssetManager assets, @NonNull String path) { + byte[] buffer = null; + InputStream input = null; + try { + input = assets.open(path); + int size = input.available(); + buffer = new byte[size]; + input.read(buffer); + } catch (IOException exception) { + logFileError(exception); + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException exception) { + logFileError(exception); + } + } + } + return buffer; + } + + private static void logFileError(Exception exception) { + String message = "Load file failed"; + Logger.e(TAG, message, exception); + MapStrictMode.strictModeViolation(message, exception); + } + + public interface OnLocalRequestResponse { + void onResponse(byte[] bytes); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java new file mode 100644 index 000000000..e59b07dc1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java @@ -0,0 +1,90 @@ +package com.mapbox.mapboxsdk.http; + +import android.support.annotation.Keep; +import android.support.annotation.Nullable; +import com.mapbox.mapboxsdk.Mapbox; + +import java.util.concurrent.locks.ReentrantLock; + +@Keep +public class NativeHttpRequest implements HttpResponder { + + private final HttpRequest httpRequest = Mapbox.getModuleProvider().createHttpRequest(); + + // Reentrancy is not needed, but "Lock" is an abstract class. + private final ReentrantLock lock = new ReentrantLock(); + + @Keep + private long nativePtr; + + @Keep + private NativeHttpRequest(long nativePtr, String resourceUrl, String etag, String modified, boolean offlineUsage) { + this.nativePtr = nativePtr; + + if (resourceUrl.startsWith("local://")) { + // used by render test to serve files from assets + executeLocalRequest(resourceUrl); + return; + } + httpRequest.executeRequest(this, nativePtr, resourceUrl, etag, modified, offlineUsage); + } + + public void cancel() { + httpRequest.cancelRequest(); + + // TODO: We need a lock here because we can try + // to cancel at the same time the request is getting + // answered on the OkHTTP thread. We could get rid of + // this lock by using Runnable when we move Android + // implementation of mbgl::RunLoop to Looper. + lock.lock(); + nativePtr = 0; + lock.unlock(); + } + + public void onResponse(int responseCode, String etag, String lastModified, String cacheControl, String expires, + String retryAfter, String xRateLimitReset, byte[] body) { + lock.lock(); + if (nativePtr != 0) { + nativeOnResponse(responseCode, + etag, + lastModified, + cacheControl, + expires, + retryAfter, + xRateLimitReset, + body); + } + lock.unlock(); + } + + private void executeLocalRequest(String resourceUrl) { + new LocalRequestTask(new LocalRequestTask.OnLocalRequestResponse() { + @Override + public void onResponse(@Nullable byte[] bytes) { + if (bytes != null) { + lock.lock(); + if (nativePtr != 0) { + NativeHttpRequest.this.nativeOnResponse(200, null, null, null, null, null, null, bytes); + } + lock.unlock(); + } + } + }).execute(resourceUrl); + } + + public void handleFailure(int type, String errorMessage) { + lock.lock(); + if (nativePtr != 0) { + nativeOnFailure(type, errorMessage); + } + lock.unlock(); + } + + @Keep + private native void nativeOnFailure(int type, String message); + + @Keep + private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires, + String retryAfter, String xRateLimitReset, byte[] body); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/package-info.java new file mode 100644 index 000000000..09eeda2b7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/package-info.java @@ -0,0 +1,4 @@ +/** + * Do not use this package. Internal use only. + */ +package com.mapbox.mapboxsdk.http; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/AnimatorListenerHolder.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/AnimatorListenerHolder.java new file mode 100644 index 000000000..5dcf30919 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/AnimatorListenerHolder.java @@ -0,0 +1,45 @@ +package com.mapbox.mapboxsdk.location; + +class AnimatorListenerHolder { + @MapboxAnimator.Type + private final int animatorType; + private final MapboxAnimator.AnimationsValueChangeListener listener; + + AnimatorListenerHolder(@MapboxAnimator.Type int animatorType, MapboxAnimator.AnimationsValueChangeListener listener) { + this.animatorType = animatorType; + this.listener = listener; + } + + @MapboxAnimator.Type + public int getAnimatorType() { + return animatorType; + } + + public MapboxAnimator.AnimationsValueChangeListener getListener() { + return listener; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + AnimatorListenerHolder that = (AnimatorListenerHolder) o; + + if (animatorType != that.animatorType) { + return false; + } + return listener != null ? listener.equals(that.listener) : that.listener == null; + } + + @Override + public int hashCode() { + int result = animatorType; + result = 31 * result + (listener != null ? listener.hashCode() : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java new file mode 100644 index 000000000..bb7fd4972 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java @@ -0,0 +1,55 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.location.modes.CameraMode; +import com.mapbox.mapboxsdk.location.modes.RenderMode; + +/** + * Interface defining the source of compass heading data that is + * consumed by the {@link LocationComponent} when in compass related + * {@link RenderMode} or + * {@link CameraMode}s. + */ +public interface CompassEngine { + + /** + * Adds a {@link CompassListener} that can be used to + * receive heading and state changes. + * + * @param compassListener to be added + */ + void addCompassListener(@NonNull CompassListener compassListener); + + /** + * Removes a {@link CompassListener} that can be used to + * receive heading and state changes. + * + * @param compassListener to be removed + */ + void removeCompassListener(@NonNull CompassListener compassListener); + + /** + * Returns the last heading value produced and pushed via + * a compass listener. + * + * @return last heading value + */ + float getLastHeading(); + + /** + * Provides the last know accuracy status from the sensor manager. + *

+ * An integer value which is identical to the {@code SensorManager} class constants: + *

    + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_NO_CONTACT}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_UNRELIABLE}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_LOW}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_MEDIUM}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_HIGH}
  • + *
+ * + * @return last accuracy status + */ + int getLastAccuracySensorStatus(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java new file mode 100644 index 000000000..c44218a1d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java @@ -0,0 +1,33 @@ +package com.mapbox.mapboxsdk.location; + +/** + * Callbacks related to the compass + */ +public interface CompassListener { + + /** + * Callback's invoked when a new compass update occurs. You can listen into the compass updates + * using {@link CompassEngine#addCompassListener(CompassListener)} and implementing these + * callbacks. Note that this interface is also used internally to to update the UI chevron/arrow. + * + * @param userHeading the new compass heading + */ + void onCompassChanged(float userHeading); + + /** + * This gets invoked when the compass accuracy status changes from one value to another. It + * provides an integer value which is identical to the {@code SensorManager} class constants: + *
    + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_NO_CONTACT}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_UNRELIABLE}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_LOW}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_MEDIUM}
  • + *
  • {@link android.hardware.SensorManager#SENSOR_STATUS_ACCURACY_HIGH}
  • + *
+ * + * @param compassStatus the new accuracy of this sensor, one of + * {@code SensorManager.SENSOR_STATUS_*} + */ + void onCompassAccuracyChange(int compassStatus); +} + diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java new file mode 100644 index 000000000..c631b1b75 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java @@ -0,0 +1,21 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.TypeEvaluator; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.geometry.LatLng; + +class LatLngEvaluator implements TypeEvaluator { + + private final LatLng latLng = new LatLng(); + + @NonNull + @Override + public LatLng evaluate(float fraction, @NonNull LatLng startValue, @NonNull LatLng endValue) { + latLng.setLatitude(startValue.getLatitude() + + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + latLng.setLongitude(startValue.getLongitude() + + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); + return latLng; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java new file mode 100644 index 000000000..14a1b49dc --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.location; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.support.annotation.ColorInt; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.utils.BitmapUtils; + +import static com.mapbox.mapboxsdk.location.Utils.generateShadow; + +class LayerBitmapProvider { + + private final Context context; + + LayerBitmapProvider(Context context) { + this.context = context; + } + + Bitmap generateBitmap(@DrawableRes int drawableRes, @ColorInt Integer tintColor) { + Drawable drawable = BitmapUtils.getDrawableFromRes(context, drawableRes, tintColor); + return BitmapUtils.getBitmapFromDrawable(drawable); + } + + Bitmap generateShadowBitmap(@NonNull LocationComponentOptions options) { + Drawable shadowDrawable = BitmapUtils.getDrawableFromRes(context, R.drawable.mapbox_user_icon_shadow); + return generateShadow(shadowDrawable, options.elevation()); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java new file mode 100644 index 000000000..faa83ea0e --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java @@ -0,0 +1,26 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Point; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; + +class LayerFeatureProvider { + + @NonNull + Feature generateLocationFeature(@Nullable Feature locationFeature, @NonNull LocationComponentOptions options) { + if (locationFeature != null) { + return locationFeature; + } + locationFeature = Feature.fromGeometry(Point.fromLngLat(0.0, 0.0)); + locationFeature.addNumberProperty(PROPERTY_GPS_BEARING, 0f); + locationFeature.addNumberProperty(PROPERTY_COMPASS_BEARING, 0f); + locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, options.enableStaleState()); + return locationFeature; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java new file mode 100644 index 000000000..cac513c2f --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -0,0 +1,111 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.NonNull; +import com.mapbox.geojson.Feature; +import com.mapbox.mapboxsdk.style.layers.CircleLayer; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.Property; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_ALPHA; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_COLOR; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; +import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; +import static com.mapbox.mapboxsdk.style.expressions.Expression.match; +import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; +import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; +import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ROTATION_ALIGNMENT_MAP; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circlePitchAlignment; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotationAlignment; + +class LayerSourceProvider { + + private static final String EMPTY_STRING = ""; + + @NonNull + GeoJsonSource generateSource(Feature locationFeature) { + return new GeoJsonSource( + LOCATION_SOURCE, + locationFeature, + new GeoJsonOptions().withMaxZoom(16) + ); + } + + @NonNull + Layer generateLayer(@NonNull String layerId) { + SymbolLayer layer = new SymbolLayer(layerId, LOCATION_SOURCE); + layer.setProperties( + iconAllowOverlap(true), + iconIgnorePlacement(true), + iconRotationAlignment(ICON_ROTATION_ALIGNMENT_MAP), + iconRotate( + match(literal(layerId), literal(0f), + stop(FOREGROUND_LAYER, get(PROPERTY_GPS_BEARING)), + stop(BACKGROUND_LAYER, get(PROPERTY_GPS_BEARING)), + stop(SHADOW_LAYER, get(PROPERTY_GPS_BEARING)), + stop(BEARING_LAYER, get(PROPERTY_COMPASS_BEARING)) + ) + ), + iconImage( + match(literal(layerId), literal(EMPTY_STRING), + stop(FOREGROUND_LAYER, switchCase( + get(PROPERTY_LOCATION_STALE), get(PROPERTY_FOREGROUND_STALE_ICON), + get(PROPERTY_FOREGROUND_ICON))), + stop(BACKGROUND_LAYER, switchCase( + get(PROPERTY_LOCATION_STALE), get(PROPERTY_BACKGROUND_STALE_ICON), + get(PROPERTY_BACKGROUND_ICON))), + stop(SHADOW_LAYER, literal(SHADOW_ICON)), + stop(BEARING_LAYER, get(PROPERTY_BEARING_ICON)) + ) + ), + iconOffset( + match(literal(layerId), literal(new Float[] {0f, 0f}), + stop(literal(FOREGROUND_LAYER), get(PROPERTY_FOREGROUND_ICON_OFFSET)), + stop(literal(SHADOW_LAYER), get(PROPERTY_SHADOW_ICON_OFFSET)) + ) + ) + ); + return layer; + } + + @NonNull + Layer generateAccuracyLayer() { + return new CircleLayer(ACCURACY_LAYER, LOCATION_SOURCE) + .withProperties( + circleRadius(get(PROPERTY_ACCURACY_RADIUS)), + circleColor(get(PROPERTY_ACCURACY_COLOR)), + circleOpacity(get(PROPERTY_ACCURACY_ALPHA)), + circleStrokeColor(get(PROPERTY_ACCURACY_COLOR)), + circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) + ); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java new file mode 100644 index 000000000..5aad038a2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -0,0 +1,422 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.location.Location; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.util.SparseArray; +import android.view.animation.LinearInterpolator; + +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.COMPASS_UPDATE_RATE_MS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.MAX_ANIMATION_DURATION_MS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_LATLNG; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURACY; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; +import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation; + +final class LocationAnimatorCoordinator { + + private static final String TAG = "Mbgl-LocationAnimatorCoordinator"; + + @VisibleForTesting + final SparseArray animatorArray = new SparseArray<>(); + + private final Projection projection; + private Location previousLocation; + private float previousAccuracyRadius = -1; + private float previousCompassBearing = -1; + private long locationUpdateTimestamp = -1; + private float durationMultiplier; + private final MapboxAnimatorProvider animatorProvider; + private final MapboxAnimatorSetProvider animatorSetProvider; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; + + @VisibleForTesting + int maxAnimationFps = Integer.MAX_VALUE; + + @VisibleForTesting + final SparseArray listeners = new SparseArray<>(); + + LocationAnimatorCoordinator(@NonNull Projection projection, @NonNull MapboxAnimatorSetProvider animatorSetProvider, + @NonNull MapboxAnimatorProvider animatorProvider) { + this.projection = projection; + this.animatorProvider = animatorProvider; + this.animatorSetProvider = animatorSetProvider; + } + + void updateAnimatorListenerHolders(@NonNull Set listenerHolders) { + listeners.clear(); + for (AnimatorListenerHolder holder : listenerHolders) { + listeners.append(holder.getAnimatorType(), holder.getListener()); + } + } + + void feedNewLocation(@NonNull Location newLocation, @NonNull CameraPosition currentCameraPosition, + boolean isGpsNorth) { + if (previousLocation == null) { + previousLocation = newLocation; + locationUpdateTimestamp = SystemClock.elapsedRealtime() - TRANSITION_ANIMATION_DURATION_MS; + } + + LatLng previousLayerLatLng = getPreviousLayerLatLng(); + float previousLayerBearing = getPreviousLayerGpsBearing(); + LatLng previousCameraLatLng = currentCameraPosition.target; + float previousCameraBearing = (float) currentCameraPosition.bearing; + + LatLng targetLatLng = new LatLng(newLocation); + float targetLayerBearing = newLocation.getBearing(); + float targetCameraBearing = newLocation.getBearing(); + targetCameraBearing = checkGpsNorth(isGpsNorth, targetCameraBearing); + + updateLayerAnimators(previousLayerLatLng, targetLatLng, previousLayerBearing, targetLayerBearing); + updateCameraAnimators(previousCameraLatLng, previousCameraBearing, targetLatLng, targetCameraBearing); + + boolean snap = immediateAnimation(projection, previousCameraLatLng, targetLatLng) + || immediateAnimation(projection, previousLayerLatLng, targetLatLng); + + long animationDuration = 0; + if (!snap) { + long previousUpdateTimeStamp = locationUpdateTimestamp; + locationUpdateTimestamp = SystemClock.elapsedRealtime(); + + if (previousUpdateTimeStamp == 0) { + animationDuration = 0; + } else { + animationDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * durationMultiplier) + /* make animation slightly longer with durationMultiplier, defaults to 1.1f */; + } + + animationDuration = Math.min(animationDuration, MAX_ANIMATION_DURATION_MS); + } + + playAnimators(animationDuration, + ANIMATOR_LAYER_LATLNG, + ANIMATOR_LAYER_GPS_BEARING, + ANIMATOR_CAMERA_LATLNG, + ANIMATOR_CAMERA_GPS_BEARING); + + previousLocation = newLocation; + } + + void feedNewCompassBearing(float targetCompassBearing, @NonNull CameraPosition currentCameraPosition) { + if (previousCompassBearing < 0) { + previousCompassBearing = targetCompassBearing; + } + + float previousLayerBearing = getPreviousLayerCompassBearing(); + float previousCameraBearing = (float) currentCameraPosition.bearing; + + updateCompassAnimators(targetCompassBearing, previousLayerBearing, previousCameraBearing); + playAnimators( + compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0, + ANIMATOR_LAYER_COMPASS_BEARING, + ANIMATOR_CAMERA_COMPASS_BEARING); + + previousCompassBearing = targetCompassBearing; + } + + void feedNewAccuracyRadius(float targetAccuracyRadius, boolean noAnimation) { + if (previousAccuracyRadius < 0) { + previousAccuracyRadius = targetAccuracyRadius; + } + + float previousAccuracyRadius = getPreviousAccuracyRadius(); + updateAccuracyAnimators(targetAccuracyRadius, previousAccuracyRadius); + playAnimators( + noAnimation || !accuracyAnimationEnabled ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION, + ANIMATOR_LAYER_ACCURACY); + + this.previousAccuracyRadius = targetAccuracyRadius; + } + + void feedNewZoomLevel(double targetZoomLevel, @NonNull CameraPosition currentCameraPosition, long animationDuration, + @Nullable MapboxMap.CancelableCallback callback) { + updateZoomAnimator((float) targetZoomLevel, (float) currentCameraPosition.zoom, callback); + playAnimators(animationDuration, ANIMATOR_ZOOM); + } + + void feedNewTilt(double targetTilt, @NonNull CameraPosition currentCameraPosition, long animationDuration, + @Nullable MapboxMap.CancelableCallback callback) { + updateTiltAnimator((float) targetTilt, (float) currentCameraPosition.tilt, callback); + playAnimators(animationDuration, ANIMATOR_TILT); + } + + private LatLng getPreviousLayerLatLng() { + LatLng previousLatLng; + MapboxAnimator latLngAnimator = animatorArray.get(ANIMATOR_LAYER_LATLNG); + if (latLngAnimator != null) { + previousLatLng = (LatLng) latLngAnimator.getAnimatedValue(); + } else { + previousLatLng = new LatLng(previousLocation); + } + return previousLatLng; + } + + private float getPreviousLayerGpsBearing() { + MapboxFloatAnimator animator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_GPS_BEARING); + float previousBearing; + if (animator != null) { + previousBearing = (float) animator.getAnimatedValue(); + } else { + previousBearing = previousLocation.getBearing(); + } + return previousBearing; + } + + private float getPreviousLayerCompassBearing() { + MapboxFloatAnimator animator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING); + + float previousBearing; + if (animator != null) { + previousBearing = (float) animator.getAnimatedValue(); + } else { + previousBearing = previousCompassBearing; + } + return previousBearing; + } + + private float getPreviousAccuracyRadius() { + MapboxAnimator animator = animatorArray.get(ANIMATOR_LAYER_ACCURACY); + float previousRadius; + if (animator != null) { + previousRadius = (float) animator.getAnimatedValue(); + } else { + previousRadius = previousAccuracyRadius; + } + return previousRadius; + } + + private void updateLayerAnimators(LatLng previousLatLng, LatLng targetLatLng, + float previousBearing, float targetBearing) { + createNewLatLngAnimator(ANIMATOR_LAYER_LATLNG, previousLatLng, targetLatLng); + + // Because Location bearing values are normalized to [0, 360] + // we need to do the same for the previous bearing value to determine the shortest path + previousBearing = Utils.normalize(previousBearing); + float normalizedLayerBearing = Utils.shortestRotation(targetBearing, previousBearing); + createNewFloatAnimator(ANIMATOR_LAYER_GPS_BEARING, previousBearing, normalizedLayerBearing); + } + + private void updateCameraAnimators(LatLng previousCameraLatLng, float previousCameraBearing, + LatLng targetLatLng, float targetBearing) { + createNewLatLngAnimator(ANIMATOR_CAMERA_LATLNG, previousCameraLatLng, targetLatLng); + + float normalizedCameraBearing = Utils.shortestRotation(targetBearing, previousCameraBearing); + createNewFloatAnimator(ANIMATOR_CAMERA_GPS_BEARING, previousCameraBearing, normalizedCameraBearing); + } + + private void updateCompassAnimators(float targetCompassBearing, float previousLayerBearing, + float previousCameraBearing) { + float normalizedLayerBearing = Utils.shortestRotation(targetCompassBearing, previousLayerBearing); + createNewFloatAnimator(ANIMATOR_LAYER_COMPASS_BEARING, previousLayerBearing, normalizedLayerBearing); + + float normalizedCameraBearing = Utils.shortestRotation(targetCompassBearing, previousCameraBearing); + createNewFloatAnimator(ANIMATOR_CAMERA_COMPASS_BEARING, previousCameraBearing, normalizedCameraBearing); + } + + private void updateAccuracyAnimators(float targetAccuracyRadius, float previousAccuracyRadius) { + createNewFloatAnimator(ANIMATOR_LAYER_ACCURACY, previousAccuracyRadius, targetAccuracyRadius); + } + + private void updateZoomAnimator(float targetZoomLevel, float previousZoomLevel, + @Nullable MapboxMap.CancelableCallback cancelableCallback) { + createNewCameraAdapterAnimator(ANIMATOR_ZOOM, previousZoomLevel, targetZoomLevel, cancelableCallback); + } + + private void updateTiltAnimator(float targetTilt, float previousTiltLevel, + @Nullable MapboxMap.CancelableCallback cancelableCallback) { + createNewCameraAdapterAnimator(ANIMATOR_TILT, previousTiltLevel, targetTilt, cancelableCallback); + } + + private void createNewLatLngAnimator(@MapboxAnimator.Type int animatorType, LatLng previous, LatLng target) { + cancelAnimator(animatorType); + MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); + if (listener != null) { + animatorArray.put(animatorType, animatorProvider.latLngAnimator(previous, target, listener, maxAnimationFps)); + } + } + + private void createNewFloatAnimator(@MapboxAnimator.Type int animatorType, float previous, float target) { + cancelAnimator(animatorType); + MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); + if (listener != null) { + animatorArray.put(animatorType, animatorProvider.floatAnimator(previous, target, listener, maxAnimationFps)); + } + } + + private void createNewCameraAdapterAnimator(@MapboxAnimator.Type int animatorType, float previous, float target, + @Nullable MapboxMap.CancelableCallback cancelableCallback) { + cancelAnimator(animatorType); + MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); + if (listener != null) { + animatorArray.put(animatorType, animatorProvider.cameraAnimator(previous, target, listener, cancelableCallback)); + } + } + + private float checkGpsNorth(boolean isGpsNorth, float targetCameraBearing) { + if (isGpsNorth) { + targetCameraBearing = 0; + } + return targetCameraBearing; + } + + private void playAnimators(long duration, @MapboxAnimator.Type int... animatorTypes) { + List animators = new ArrayList<>(); + for (@MapboxAnimator.Type int animatorType : animatorTypes) { + Animator animator = animatorArray.get(animatorType); + if (animator != null) { + animators.add(animator); + } + } + animatorSetProvider.startAnimation(animators, new LinearInterpolator(), duration); + } + + void resetAllCameraAnimations(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { + resetCameraCompassAnimation(currentCameraPosition); + boolean snap = resetCameraLocationAnimations(currentCameraPosition, isGpsNorth); + playAnimators( + snap ? 0 : TRANSITION_ANIMATION_DURATION_MS, + ANIMATOR_CAMERA_LATLNG, + ANIMATOR_CAMERA_GPS_BEARING); + } + + private boolean resetCameraLocationAnimations(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { + resetCameraGpsBearingAnimation(currentCameraPosition, isGpsNorth); + return resetCameraLatLngAnimation(currentCameraPosition); + } + + private boolean resetCameraLatLngAnimation(@NonNull CameraPosition currentCameraPosition) { + MapboxLatLngAnimator animator = (MapboxLatLngAnimator) animatorArray.get(ANIMATOR_CAMERA_LATLNG); + if (animator == null) { + return false; + } + + LatLng currentTarget = animator.getTarget(); + LatLng previousCameraTarget = currentCameraPosition.target; + createNewLatLngAnimator(ANIMATOR_CAMERA_LATLNG, previousCameraTarget, currentTarget); + + return immediateAnimation(projection, previousCameraTarget, currentTarget); + } + + private void resetCameraGpsBearingAnimation(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { + MapboxFloatAnimator animator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_CAMERA_GPS_BEARING); + if (animator == null) { + return; + } + + float currentTargetBearing = animator.getTarget(); + currentTargetBearing = checkGpsNorth(isGpsNorth, currentTargetBearing); + float previousCameraBearing = (float) currentCameraPosition.bearing; + float normalizedCameraBearing = Utils.shortestRotation(currentTargetBearing, previousCameraBearing); + createNewFloatAnimator(ANIMATOR_CAMERA_GPS_BEARING, previousCameraBearing, normalizedCameraBearing); + } + + private void resetCameraCompassAnimation(@NonNull CameraPosition currentCameraPosition) { + MapboxFloatAnimator animator = + (MapboxFloatAnimator) animatorArray.get(ANIMATOR_CAMERA_COMPASS_BEARING); + if (animator == null) { + return; + } + + float currentTargetBearing = animator.getTarget(); + float previousCameraBearing = (float) currentCameraPosition.bearing; + float normalizedCameraBearing = Utils.shortestRotation(currentTargetBearing, previousCameraBearing); + createNewFloatAnimator(ANIMATOR_CAMERA_COMPASS_BEARING, previousCameraBearing, normalizedCameraBearing); + } + + void resetAllLayerAnimations() { + MapboxLatLngAnimator latLngAnimator = (MapboxLatLngAnimator) animatorArray.get(ANIMATOR_LAYER_LATLNG); + MapboxFloatAnimator gpsBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_GPS_BEARING); + MapboxFloatAnimator compassBearingAnimator = + (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING); + + if (latLngAnimator != null && gpsBearingAnimator != null) { + LatLng currentLatLng = (LatLng) latLngAnimator.getAnimatedValue(); + LatLng currentLatLngTarget = latLngAnimator.getTarget(); + createNewLatLngAnimator(ANIMATOR_LAYER_LATLNG, currentLatLng, currentLatLngTarget); + + float currentGpsBearing = (float) gpsBearingAnimator.getAnimatedValue(); + float currentGpsBearingTarget = gpsBearingAnimator.getTarget(); + createNewFloatAnimator(ANIMATOR_LAYER_GPS_BEARING, currentGpsBearing, currentGpsBearingTarget); + + long duration = latLngAnimator.getDuration() - latLngAnimator.getCurrentPlayTime(); + + playAnimators(duration, ANIMATOR_LAYER_LATLNG, ANIMATOR_LAYER_GPS_BEARING); + } + + if (compassBearingAnimator != null) { + float currentLayerBearing = getPreviousLayerCompassBearing(); + float currentLayerBearingTarget = compassBearingAnimator.getTarget(); + createNewFloatAnimator(ANIMATOR_LAYER_COMPASS_BEARING, currentLayerBearing, currentLayerBearingTarget); + playAnimators( + compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0, + ANIMATOR_LAYER_COMPASS_BEARING); + } + } + + void cancelZoomAnimation() { + cancelAnimator(ANIMATOR_ZOOM); + } + + void cancelTiltAnimation() { + cancelAnimator(ANIMATOR_TILT); + } + + void cancelAllAnimations() { + for (int i = 0; i < animatorArray.size(); i++) { + @MapboxAnimator.Type int animatorType = animatorArray.keyAt(i); + cancelAnimator(animatorType); + } + } + + private void cancelAnimator(@MapboxAnimator.Type int animatorType) { + MapboxAnimator animator = animatorArray.get(animatorType); + if (animator != null) { + animator.cancel(); + animator.removeAllUpdateListeners(); + animator.removeAllListeners(); + animatorArray.put(animatorType, null); + } + } + + void setTrackingAnimationDurationMultiplier(float trackingAnimationDurationMultiplier) { + this.durationMultiplier = trackingAnimationDurationMultiplier; + } + + void setCompassAnimationEnabled(boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + } + + void setAccuracyAnimationEnabled(boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; + } + + void setMaxAnimationFps(int maxAnimationFps) { + if (maxAnimationFps <= 0) { + Logger.e(TAG, "Max animation FPS cannot be less or equal to 0."); + return; + } + this.maxAnimationFps = maxAnimationFps; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java new file mode 100644 index 000000000..79d2e02bf --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -0,0 +1,437 @@ +package com.mapbox.mapboxsdk.location; + +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.annotation.VisibleForTesting; +import android.view.MotionEvent; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdate; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.CameraMode; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Transform; + +import java.util.HashSet; +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; + +final class LocationCameraController { + + @CameraMode.Mode + private int cameraMode; + + private final MapboxMap mapboxMap; + private final Transform transform; + private final OnCameraTrackingChangedListener internalCameraTrackingChangedListener; + private LocationComponentOptions options; + private boolean adjustFocalPoint; + + private final MoveGestureDetector moveGestureDetector; + private final OnCameraMoveInvalidateListener onCameraMoveInvalidateListener; + + private final AndroidGesturesManager initialGesturesManager; + private final AndroidGesturesManager internalGesturesManager; + + private boolean isTransitioning; + + LocationCameraController( + Context context, + MapboxMap mapboxMap, + Transform transform, + OnCameraTrackingChangedListener internalCameraTrackingChangedListener, + @NonNull LocationComponentOptions options, + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener) { + this.mapboxMap = mapboxMap; + this.transform = transform; + + initialGesturesManager = mapboxMap.getGesturesManager(); + internalGesturesManager = new LocationGesturesManager(context); + moveGestureDetector = internalGesturesManager.getMoveGestureDetector(); + mapboxMap.addOnRotateListener(onRotateListener); + mapboxMap.addOnFlingListener(onFlingListener); + mapboxMap.addOnMoveListener(onMoveListener); + + this.internalCameraTrackingChangedListener = internalCameraTrackingChangedListener; + this.onCameraMoveInvalidateListener = onCameraMoveInvalidateListener; + initializeOptions(options); + } + + // Package private for testing purposes + LocationCameraController(MapboxMap mapboxMap, + Transform transform, + MoveGestureDetector moveGestureDetector, + OnCameraTrackingChangedListener internalCameraTrackingChangedListener, + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener, + AndroidGesturesManager initialGesturesManager, + AndroidGesturesManager internalGesturesManager) { + this.mapboxMap = mapboxMap; + this.transform = transform; + this.moveGestureDetector = moveGestureDetector; + this.internalCameraTrackingChangedListener = internalCameraTrackingChangedListener; + this.onCameraMoveInvalidateListener = onCameraMoveInvalidateListener; + this.internalGesturesManager = internalGesturesManager; + this.initialGesturesManager = initialGesturesManager; + } + + void initializeOptions(LocationComponentOptions options) { + this.options = options; + if (options.trackingGesturesManagement()) { + if (mapboxMap.getGesturesManager() != internalGesturesManager) { + mapboxMap.setGesturesManager(internalGesturesManager, true, true); + } + adjustGesturesThresholds(); + } else if (mapboxMap.getGesturesManager() != initialGesturesManager) { + mapboxMap.setGesturesManager(initialGesturesManager, true, true); + } + } + + void setCameraMode(@CameraMode.Mode int cameraMode) { + setCameraMode(cameraMode, null, TRANSITION_ANIMATION_DURATION_MS, null, null, null, null); + } + + void setCameraMode(@CameraMode.Mode final int cameraMode, @Nullable Location lastLocation, + long transitionDuration, + @Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt, + @Nullable OnLocationCameraTransitionListener internalTransitionListener) { + if (this.cameraMode == cameraMode) { + return; + } + + final boolean wasTracking = isLocationTracking(); + this.cameraMode = cameraMode; + + if (cameraMode != CameraMode.NONE) { + mapboxMap.cancelTransitions(); + } + + adjustGesturesThresholds(); + notifyCameraTrackingChangeListener(wasTracking); + transitionToCurrentLocation( + wasTracking, lastLocation, transitionDuration, zoom, bearing, tilt, internalTransitionListener); + } + + /** + * Initiates a camera animation to the current location if location tracking was engaged. + * Notifies an internal listener when the transition's finished to invalidate animators and notify external listeners. + */ + private void transitionToCurrentLocation(boolean wasTracking, Location lastLocation, + long transitionDuration, + Double zoom, Double bearing, Double tilt, + final OnLocationCameraTransitionListener internalTransitionListener) { + if (!wasTracking && isLocationTracking() && lastLocation != null) { + isTransitioning = true; + LatLng target = new LatLng(lastLocation); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(target); + if (zoom != null) { + builder.zoom(zoom); + } + if (tilt != null) { + builder.tilt(tilt); + } + if (bearing != null) { + builder.bearing(bearing); + } else { + if (isLocationBearingTracking()) { + builder.bearing(cameraMode == CameraMode.TRACKING_GPS_NORTH ? 0 : lastLocation.getBearing()); + } + } + + CameraUpdate update = CameraUpdateFactory.newCameraPosition(builder.build()); + MapboxMap.CancelableCallback callback = new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + isTransitioning = false; + if (internalTransitionListener != null) { + internalTransitionListener.onLocationCameraTransitionCanceled(cameraMode); + } + } + + @Override + public void onFinish() { + isTransitioning = false; + if (internalTransitionListener != null) { + internalTransitionListener.onLocationCameraTransitionFinished(cameraMode); + } + } + }; + + CameraPosition currentPosition = mapboxMap.getCameraPosition(); + if (Utils.immediateAnimation(mapboxMap.getProjection(), currentPosition.target, target)) { + transform.moveCamera( + mapboxMap, + update, + callback); + } else { + transform.animateCamera( + mapboxMap, + update, + (int) transitionDuration, + callback); + } + } else { + if (internalTransitionListener != null) { + internalTransitionListener.onLocationCameraTransitionFinished(cameraMode); + } + } + } + + int getCameraMode() { + return cameraMode; + } + + private void setBearing(float bearing) { + if (isTransitioning) { + return; + } + + transform.moveCamera(mapboxMap, CameraUpdateFactory.bearingTo(bearing), null); + onCameraMoveInvalidateListener.onInvalidateCameraMove(); + } + + private void setLatLng(@NonNull LatLng latLng) { + if (isTransitioning) { + return; + } + + transform.moveCamera(mapboxMap, CameraUpdateFactory.newLatLng(latLng), null); + onCameraMoveInvalidateListener.onInvalidateCameraMove(); + + if (adjustFocalPoint) { + PointF focalPoint = mapboxMap.getProjection().toScreenLocation(latLng); + mapboxMap.getUiSettings().setFocalPoint(focalPoint); + adjustFocalPoint = false; + } + } + + private void setZoom(float zoom) { + if (isTransitioning) { + return; + } + + transform.moveCamera(mapboxMap, CameraUpdateFactory.zoomTo(zoom), null); + onCameraMoveInvalidateListener.onInvalidateCameraMove(); + } + + private void setTilt(float tilt) { + if (isTransitioning) { + return; + } + + transform.moveCamera(mapboxMap, CameraUpdateFactory.tiltTo(tilt), null); + onCameraMoveInvalidateListener.onInvalidateCameraMove(); + } + + private final MapboxAnimator.AnimationsValueChangeListener latLngValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(LatLng value) { + setLatLng(value); + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener gpsBearingValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + boolean trackingNorth = cameraMode == CameraMode.TRACKING_GPS_NORTH + && mapboxMap.getCameraPosition().bearing == 0; + + if (!trackingNorth) { + setBearing(value); + } + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener compassBearingValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + if (cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.NONE_COMPASS) { + setBearing(value); + } + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener zoomValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + setZoom(value); + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener tiltValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + setTilt(value); + } + }; + + Set getAnimationListeners() { + Set holders = new HashSet<>(); + if (isLocationTracking()) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_CAMERA_LATLNG, latLngValueListener)); + } + + if (isLocationBearingTracking()) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_CAMERA_GPS_BEARING, gpsBearingValueListener)); + } + + if (isConsumingCompass()) { + holders.add(new AnimatorListenerHolder( + MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING, + compassBearingValueListener)); + } + + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_ZOOM, zoomValueListener)); + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_TILT, tiltValueListener)); + return holders; + } + + boolean isTransitioning() { + return isTransitioning; + } + + private void adjustGesturesThresholds() { + if (options.trackingGesturesManagement()) { + if (isLocationTracking()) { + adjustFocalPoint = true; + moveGestureDetector.setMoveThreshold(options.trackingInitialMoveThreshold()); + } else { + moveGestureDetector.setMoveThreshold(0f); + } + } + } + + boolean isConsumingCompass() { + return cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.NONE_COMPASS; + } + + private boolean isLocationTracking() { + return cameraMode == CameraMode.TRACKING + || cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.TRACKING_GPS + || cameraMode == CameraMode.TRACKING_GPS_NORTH; + } + + private boolean isBearingTracking() { + return cameraMode == CameraMode.NONE_COMPASS + || cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.NONE_GPS + || cameraMode == CameraMode.TRACKING_GPS + || cameraMode == CameraMode.TRACKING_GPS_NORTH; + } + + private boolean isLocationBearingTracking() { + return cameraMode == CameraMode.TRACKING_GPS + || cameraMode == CameraMode.TRACKING_GPS_NORTH + || cameraMode == CameraMode.NONE_GPS; + } + + private void notifyCameraTrackingChangeListener(boolean wasTracking) { + internalCameraTrackingChangedListener.onCameraTrackingChanged(cameraMode); + if (wasTracking && !isLocationTracking()) { + mapboxMap.getUiSettings().setFocalPoint(null); + internalCameraTrackingChangedListener.onCameraTrackingDismissed(); + } + } + + @NonNull + @VisibleForTesting + MapboxMap.OnMoveListener onMoveListener = new MapboxMap.OnMoveListener() { + private boolean interrupt; + + @Override + public void onMoveBegin(@NonNull MoveGestureDetector detector) { + if (options.trackingGesturesManagement() + && detector.getPointersCount() > 1 + && detector.getMoveThreshold() != options.trackingMultiFingerMoveThreshold() + && isLocationTracking()) { + detector.setMoveThreshold(options.trackingMultiFingerMoveThreshold()); + interrupt = true; + } else { + setCameraMode(CameraMode.NONE); + } + } + + @Override + public void onMove(@NonNull MoveGestureDetector detector) { + if (interrupt) { + detector.interrupt(); + return; + } + + if (isLocationTracking() || isBearingTracking()) { + setCameraMode(CameraMode.NONE); + detector.interrupt(); + } + } + + @Override + public void onMoveEnd(@NonNull MoveGestureDetector detector) { + if (options.trackingGesturesManagement() && !interrupt && isLocationTracking()) { + detector.setMoveThreshold(options.trackingInitialMoveThreshold()); + } + interrupt = false; + } + }; + + @NonNull + private MapboxMap.OnRotateListener onRotateListener = new MapboxMap.OnRotateListener() { + @Override + public void onRotateBegin(@NonNull RotateGestureDetector detector) { + if (isBearingTracking()) { + setCameraMode(CameraMode.NONE); + } + } + + @Override + public void onRotate(@NonNull RotateGestureDetector detector) { + // no implementation + } + + @Override + public void onRotateEnd(@NonNull RotateGestureDetector detector) { + // no implementation + } + }; + + @NonNull + private MapboxMap.OnFlingListener onFlingListener = new MapboxMap.OnFlingListener() { + @Override + public void onFling() { + setCameraMode(CameraMode.NONE); + } + }; + + private class LocationGesturesManager extends AndroidGesturesManager { + + LocationGesturesManager(Context context) { + super(context); + } + + @Override + public boolean onTouchEvent(@Nullable MotionEvent motionEvent) { + if (motionEvent != null) { + int action = motionEvent.getActionMasked(); + if (action == MotionEvent.ACTION_UP) { + adjustGesturesThresholds(); + } + } + return super.onTouchEvent(motionEvent); + } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java new file mode 100644 index 000000000..46de3673e --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -0,0 +1,1586 @@ +package com.mapbox.mapboxsdk.location; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.SensorManager; +import android.location.Location; +import android.os.Looper; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresPermission; +import android.support.annotation.StyleRes; +import android.support.annotation.VisibleForTesting; +import android.view.WindowManager; + +import com.mapbox.android.core.location.LocationEngine; +import com.mapbox.android.core.location.LocationEngineCallback; +import com.mapbox.android.core.location.LocationEngineProvider; +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.android.core.location.LocationEngineResult; +import com.mapbox.android.core.permissions.PermissionsManager; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdate; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.CameraMode; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener; +import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener; +import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.maps.Transform; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_FASTEST_INTERVAL_MILLIS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_INTERVAL_MILLIS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; + +/** + * The Location Component provides location awareness to your mobile application. Enabling this + * component provides a contextual experience to your users by showing an icon representing the users + * current location. A few different modes are offered to provide the right context to your users at + * the correct time. {@link RenderMode#NORMAL} simply shows the users location on the map + * represented as a dot. {@link RenderMode#COMPASS} mode allows you to display an arrow icon + * (by default) that points in the direction the device is pointing in. + * {@link RenderMode#GPS} can be used in conjunction with our Navigation SDK to + * display a larger icon (customized with {@link LocationComponentOptions#gpsDrawable()}) we call the user puck. + *

+ * This component also offers the ability to set a map camera behavior for tracking the user + * location. These different {@link CameraMode}s will track, stop tracking the location based on the + * mode set with {@link LocationComponent#setCameraMode(int)}. + *

+ * + * To get the component object use {@link MapboxMap#getLocationComponent()} and activate it with + * {@link #activateLocationComponent(Context, Style)} or one of the overloads. + * Then, manage its visibility with {@link #setLocationComponentEnabled(boolean)}. + * The component will not process location updates right after activation, but only after being enabled. + * + *

+ * Using this component requires you to request permission beforehand manually or using + * {@link PermissionsManager}. Either + * {@code ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permissions can be requested for + * this component to work as expected. + *

+ * This component offers a default, built-in {@link LocationEngine} with some of the activation methods. + * This engine will be obtained by {@link LocationEngineProvider#getBestLocationEngine(Context, boolean)} which defaults + * to the {@link com.mapbox.android.core.location.MapboxFusedLocationEngineImpl}. If you'd like to utilize Google + * Play Services + * for more precise location updates, simply add the Google Play Location Services dependency in your build script. + * This will make the default engine the {@link com.mapbox.android.core.location.GoogleLocationEngineImpl} instead. + * After a custom engine is passed to the component, or the built-in is initialized, + * the location updates are going to be requested with the {@link LocationEngineRequest}, either a default one, + * or the one passed during the activation. + * When using any engine, requesting/removing the location updates is going to be managed internally. + *

+ * You can also push location updates to the component without any internal engine management. + * To achieve that, use {@link #activateLocationComponent(Context, Style, boolean)} with false. + * No engine is going to be initialized and you can push location updates with {@link #forceLocationUpdate(Location)}. + *

+ * For location puck animation purposes, like navigation, + * we recommend limiting the maximum zoom level of the map for the best user experience. + *

+ * Location Component doesn't support state saving out-of-the-box. + */ +public final class LocationComponent { + private static final String TAG = "Mbgl-LocationComponent"; + + @NonNull + private final MapboxMap mapboxMap; + @NonNull + private final Transform transform; + private Style style; + private LocationComponentOptions options; + @NonNull + private InternalLocationEngineProvider internalLocationEngineProvider = new InternalLocationEngineProvider(); + @Nullable + private LocationEngine locationEngine; + @NonNull + private LocationEngineRequest locationEngineRequest = + new LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS) + .setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .build(); + private LocationEngineCallback currentLocationEngineListener + = new CurrentLocationEngineCallback(this); + private LocationEngineCallback lastLocationEngineListener + = new LastLocationEngineCallback(this); + + @Nullable + private CompassEngine compassEngine; + + private LocationLayerController locationLayerController; + private LocationCameraController locationCameraController; + + private LocationAnimatorCoordinator locationAnimatorCoordinator; + + /** + * Holds last location which is being returned in the {@link #getLastKnownLocation()} + * when there is no {@link #locationEngine} set or when the last location returned by the engine is null. + */ + @Nullable + private Location lastLocation; + private CameraPosition lastCameraPosition; + + /** + * Indicates whether the component has been initialized. + */ + private boolean isComponentInitialized; + + /** + * Indicates that the component is enabled and should be displaying location if Mapbox components are available and + * the lifecycle is in a started state. + */ + private boolean isEnabled; + + /** + * Indicated that component's lifecycle {@link #onStart()} method has been called. + * This allows Mapbox components enter started state and display data, and adds state safety for methods like + * {@link #setLocationComponentEnabled(boolean)} + */ + private boolean isComponentStarted; + + /** + * Indicates if Mapbox components are ready to be interacted with. This can differ from {@link #isComponentStarted} + * if the Mapbox style is being reloaded. + */ + private boolean isLayerReady; + + /** + * Indicates whether we are listening for compass updates. + */ + private boolean isListeningToCompass; + + private StaleStateManager staleStateManager; + private final CopyOnWriteArrayList onLocationStaleListeners + = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onLocationClickListeners + = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onLocationLongClickListeners + = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onCameraTrackingChangedListeners + = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onRenderModeChangedListeners + = new CopyOnWriteArrayList<>(); + + // Workaround for too frequent updates, see https://github.com/mapbox/mapbox-gl-native/issues/13587 + private long fastestInterval; + private long lastUpdateTime; + + /** + * Internal use. + *

+ * To get the component object use {@link MapboxMap#getLocationComponent()}. + */ + public LocationComponent(@NonNull MapboxMap mapboxMap, + @NonNull Transform transform, + @NonNull List developerAnimationListeners) { + this.mapboxMap = mapboxMap; + this.transform = transform; + developerAnimationListeners.add(developerAnimationListener); + } + + // used for creating a spy + LocationComponent() { + //noinspection ConstantConditions + mapboxMap = null; + transform = null; + } + + @VisibleForTesting + LocationComponent(@NonNull MapboxMap mapboxMap, + @NonNull Transform transform, + @NonNull List developerAnimationListeners, + @NonNull LocationEngineCallback currentListener, + @NonNull LocationEngineCallback lastListener, + @NonNull LocationLayerController locationLayerController, + @NonNull LocationCameraController locationCameraController, + @NonNull LocationAnimatorCoordinator locationAnimatorCoordinator, + @NonNull StaleStateManager staleStateManager, + @NonNull CompassEngine compassEngine, + @NonNull InternalLocationEngineProvider internalLocationEngineProvider) { + this.mapboxMap = mapboxMap; + this.transform = transform; + developerAnimationListeners.add(developerAnimationListener); + this.currentLocationEngineListener = currentListener; + this.lastLocationEngineListener = lastListener; + this.locationLayerController = locationLayerController; + this.locationCameraController = locationCameraController; + this.locationAnimatorCoordinator = locationAnimatorCoordinator; + this.staleStateManager = staleStateManager; + this.compassEngine = compassEngine; + this.internalLocationEngineProvider = internalLocationEngineProvider; + isComponentInitialized = true; + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + *

+ * Note: This method will initialize and use an internal {@link LocationEngine} when enabled. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style) { + activateLocationComponent(context, style, + LocationComponentOptions.createFromAttributes(context, R.style.mapbox_LocationComponent)); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if + * there should be no location engine initialized + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + boolean useDefaultLocationEngine) { + if (useDefaultLocationEngine) { + activateLocationComponent(context, style, R.style.mapbox_LocationComponent); + } else { + activateLocationComponent(context, style, null, R.style.mapbox_LocationComponent); + } + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if + * there should be no location engine initialized + * @param locationEngineRequest the location request + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + boolean useDefaultLocationEngine, + @NonNull LocationEngineRequest locationEngineRequest) { + setLocationEngineRequest(locationEngineRequest); + if (useDefaultLocationEngine) { + activateLocationComponent(context, style, R.style.mapbox_LocationComponent); + } else { + activateLocationComponent(context, style, null, R.style.mapbox_LocationComponent); + } + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if + * there should be no location engine initialized + * @param locationEngineRequest the location request + * @param options the options + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + boolean useDefaultLocationEngine, + @NonNull LocationEngineRequest locationEngineRequest, + @NonNull LocationComponentOptions options) { + setLocationEngineRequest(locationEngineRequest); + if (useDefaultLocationEngine) { + activateLocationComponent(context, style, options); + } else { + activateLocationComponent(context, style, null, options); + } + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + *

+ * Note: This method will initialize and use an internal {@link LocationEngine} when enabled. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param styleRes the LocationComponent style res + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) { + activateLocationComponent(context, style, LocationComponentOptions.createFromAttributes(context, styleRes)); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + *

+ * Note: This method will initialize and use an internal {@link LocationEngine} when enabled. + *

+ * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param options the options + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @NonNull LocationComponentOptions options) { + initialize(context, style, options); + initializeLocationEngine(context); + applyStyle(options); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param locationEngine the engine, or null if you'd like to only force location updates + * @param styleRes the LocationComponent style res + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, @StyleRes int styleRes) { + activateLocationComponent(context, style, locationEngine, + LocationComponentOptions.createFromAttributes(context, styleRes)); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param locationEngine the engine, or null if you'd like to only force location updates + * @param locationEngineRequest the location request + * @param styleRes the LocationComponent style res + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, + @NonNull LocationEngineRequest locationEngineRequest, @StyleRes int styleRes) { + activateLocationComponent(context, style, locationEngine, locationEngineRequest, + LocationComponentOptions.createFromAttributes(context, styleRes)); + } + + /** + * This method will show the location icon and enable the camera tracking the location. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param locationEngine the engine + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine) { + activateLocationComponent(context, style, locationEngine, R.style.mapbox_LocationComponent); + } + + /** + * This method will show the location icon and enable the camera tracking the location. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param locationEngine the engine + * @param locationEngineRequest the location request + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, + @NonNull LocationEngineRequest locationEngineRequest) { + activateLocationComponent(context, style, locationEngine, locationEngineRequest, R.style.mapbox_LocationComponent); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param locationEngine the engine, or null if you'd like to only force location updates + * @param style the proxy object for current map style. More info at {@link Style} + * @param options the options + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, + @NonNull LocationComponentOptions options) { + initialize(context, style, options); + setLocationEngine(locationEngine); + applyStyle(options); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param context the context + * @param style the proxy object for current map style. More info at {@link Style} + * @param locationEngine the engine, or null if you'd like to only force location updates + * @param locationEngineRequest the location request + * @param options the options + * @deprecated use {@link LocationComponentActivationOptions.Builder} instead + */ + @Deprecated + public void activateLocationComponent(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, + @NonNull LocationEngineRequest locationEngineRequest, + @NonNull LocationComponentOptions options) { + initialize(context, style, options); + setLocationEngineRequest(locationEngineRequest); + setLocationEngine(locationEngine); + applyStyle(options); + } + + /** + * This method initializes the component and needs to be called before any other operations are performed. + * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}. + * + * @param activationOptions a fully built {@link LocationComponentActivationOptions} object + */ + public void activateLocationComponent(@NonNull LocationComponentActivationOptions activationOptions) { + LocationComponentOptions options = activationOptions.locationComponentOptions(); + if (options == null) { + int styleRes = activationOptions.styleRes(); + if (styleRes == 0) { + styleRes = R.style.mapbox_LocationComponent; + } + options = LocationComponentOptions.createFromAttributes(activationOptions.context(), styleRes); + } + + // Initialize the LocationComponent with Context, the map's `Style`, and either custom LocationComponentOptions + // or backup options created from default/custom attributes + initialize(activationOptions.context(), activationOptions.style(), options); + + // Apply the LocationComponent styling + // TODO avoid doubling style initialization + applyStyle(options); + + // Set the LocationEngine request if one was given to LocationComponentActivationOptions + LocationEngineRequest locationEngineRequest = activationOptions.locationEngineRequest(); + if (locationEngineRequest != null) { + setLocationEngineRequest(locationEngineRequest); + } + + // Set the LocationEngine if one was given to LocationComponentActivationOptions + LocationEngine locationEngine = activationOptions.locationEngine(); + if (locationEngine != null) { + setLocationEngine(locationEngine); + } else { + if (activationOptions.useDefaultLocationEngine()) { + initializeLocationEngine(activationOptions.context()); + } else { + setLocationEngine(null); + } + } + } + + /** + * Manage component's visibility after activation. + * + * @param isEnabled true if the plugin should be visible and listen for location updates, false otherwise. + */ + @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) + public void setLocationComponentEnabled(boolean isEnabled) { + checkActivationState(); + if (isEnabled) { + enableLocationComponent(); + } else { + disableLocationComponent(); + } + } + + /** + * Returns whether the plugin is enabled, meaning that location can be displayed and camera modes can be used. + * + * @return true if the plugin is enabled, false otherwise + */ + public boolean isLocationComponentEnabled() { + checkActivationState(); + return isEnabled; + } + + /** + * Sets the camera mode, which determines how the map camera will track the rendered location. + *

+ * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or + * {@link #tiltWhileTracking(double)}. + * Use {@link OnLocationCameraTransitionListener} to listen for the transition state. + *

+ *

    + *
  • {@link CameraMode#NONE}: No camera tracking
  • + *
  • {@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing
  • + *
  • {@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing
  • + *
  • {@link CameraMode#TRACKING}: Camera tracks the user location
  • + *
  • {@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass
  • + *
  • {@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing
  • + *
  • {@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north
  • + *
+ * + * @param cameraMode one of the modes found in {@link CameraMode} + */ + public void setCameraMode(@CameraMode.Mode int cameraMode) { + setCameraMode(cameraMode, null); + } + + /** + * Sets the camera mode, which determines how the map camera will track the rendered location. + *

+ * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or + * {@link #tiltWhileTracking(double)}. + * Use {@link OnLocationCameraTransitionListener} to listen for the transition state. + *

+ *

    + *
  • {@link CameraMode#NONE}: No camera tracking
  • + *
  • {@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing
  • + *
  • {@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing
  • + *
  • {@link CameraMode#TRACKING}: Camera tracks the user location
  • + *
  • {@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass
  • + *
  • {@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing
  • + *
  • {@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north
  • + *
+ * + * @param cameraMode one of the modes found in {@link CameraMode} + * @param transitionListener callback that's going to be invoked when the transition animation finishes + */ + public void setCameraMode(@CameraMode.Mode int cameraMode, + @Nullable OnLocationCameraTransitionListener transitionListener) { + setCameraMode(cameraMode, TRANSITION_ANIMATION_DURATION_MS, null, null, null, transitionListener); + } + + /** + * Sets the camera mode, which determines how the map camera will track the rendered location. + *

+ * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or + * {@link #tiltWhileTracking(double)}. + * Use {@link OnLocationCameraTransitionListener} to listen for the transition state. + *

+ * Set values of zoom, bearing and tilt that the camera will transition to. If null is passed to any of those, + * current value will be used for that parameter instead. + * If the camera is already tracking, provided values are ignored. + *

+ *

    + *
  • {@link CameraMode#NONE}: No camera tracking
  • + *
  • {@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing
  • + *
  • {@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing
  • + *
  • {@link CameraMode#TRACKING}: Camera tracks the user location
  • + *
  • {@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass
  • + *
  • {@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing
  • + *
  • {@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north
  • + *
+ * + * @param cameraMode one of the modes found in {@link CameraMode} + * @param transitionDuration duration of the transition in milliseconds + * @param zoom target zoom, set to null to use current camera position + * @param bearing target bearing, set to null to use current camera position + * @param tilt target tilt, set to null to use current camera position + * @param transitionListener callback that's going to be invoked when the transition animation finishes + */ + public void setCameraMode(@CameraMode.Mode int cameraMode, + long transitionDuration, + @Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt, + @Nullable OnLocationCameraTransitionListener transitionListener) { + checkActivationState(); + locationCameraController.setCameraMode( + cameraMode, lastLocation, transitionDuration, zoom, bearing, tilt, + new CameraTransitionListener(transitionListener)); + updateCompassListenerState(true); + } + + /** + * Used to reset camera animators and notify listeners when the transition finishes. + */ + private class CameraTransitionListener implements OnLocationCameraTransitionListener { + + private final OnLocationCameraTransitionListener externalListener; + + private CameraTransitionListener(OnLocationCameraTransitionListener externalListener) { + this.externalListener = externalListener; + } + + @Override + public void onLocationCameraTransitionFinished(int cameraMode) { + if (externalListener != null) { + externalListener.onLocationCameraTransitionFinished(cameraMode); + } + reset(cameraMode); + } + + @Override + public void onLocationCameraTransitionCanceled(int cameraMode) { + if (externalListener != null) { + externalListener.onLocationCameraTransitionCanceled(cameraMode); + } + reset(cameraMode); + } + + private void reset(@CameraMode.Mode int cameraMode) { + locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(), + cameraMode == CameraMode.TRACKING_GPS_NORTH); + } + } + + /** + * Provides the current camera mode being used to track the location or compass updates. + * + * @return the current camera mode + */ + @CameraMode.Mode + public int getCameraMode() { + checkActivationState(); + return locationCameraController.getCameraMode(); + } + + /** + * Sets the render mode, which determines how the location updates will be rendered on the map. + *

+ *

    + *
  • {@link RenderMode#NORMAL}: Shows user location, bearing ignored
  • + *
  • {@link RenderMode#COMPASS}: Shows user location with bearing considered from compass
  • + *
  • {@link RenderMode#GPS}: Shows user location with bearing considered from location
  • + *
+ * + * @param renderMode one of the modes found in {@link RenderMode} + */ + public void setRenderMode(@RenderMode.Mode int renderMode) { + checkActivationState(); + locationLayerController.setRenderMode(renderMode); + updateLayerOffsets(true); + updateCompassListenerState(true); + } + + /** + * Provides the current render mode being used to show + * the location and/or compass updates on the map. + * + * @return the current render mode + */ + @RenderMode.Mode + public int getRenderMode() { + checkActivationState(); + return locationLayerController.getRenderMode(); + } + + /** + * Returns the current location options being used. + * + * @return the current {@link LocationComponentOptions} + */ + public LocationComponentOptions getLocationComponentOptions() { + checkActivationState(); + return options; + } + + /** + * Apply a new component style with a style resource. + * + * @param styleRes a XML style overriding some or all the options + */ + public void applyStyle(@NonNull Context context, @StyleRes int styleRes) { + checkActivationState(); + applyStyle(LocationComponentOptions.createFromAttributes(context, styleRes)); + } + + /** + * Apply a new component style with location component options. + * + * @param options to update the current style + */ + public void applyStyle(@NonNull final LocationComponentOptions options) { + checkActivationState(); + LocationComponent.this.options = options; + if (mapboxMap.getStyle() != null) { + locationLayerController.applyStyle(options); + locationCameraController.initializeOptions(options); + staleStateManager.setEnabled(options.enableStaleState()); + staleStateManager.setDelayTime(options.staleStateTimeout()); + locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); + locationAnimatorCoordinator.setCompassAnimationEnabled(options.compassAnimationEnabled()); + locationAnimatorCoordinator.setAccuracyAnimationEnabled(options.accuracyAnimationEnabled()); + updateMapWithOptions(options); + } + } + + /** + * Zooms to the desired zoom level. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param zoomLevel The desired zoom level. + * @param animationDuration The zoom animation duration. + * @param callback The callback with finish/cancel information + */ + public void zoomWhileTracking(double zoomLevel, long animationDuration, + @Nullable MapboxMap.CancelableCallback callback) { + checkActivationState(); + if (!isLayerReady) { + return; + } else if (getCameraMode() == CameraMode.NONE) { + Logger.e(TAG, String.format("%s%s", + "LocationComponent#zoomWhileTracking method can only be used", + " when a camera mode other than CameraMode#NONE is engaged.")); + return; + } + locationAnimatorCoordinator.feedNewZoomLevel(zoomLevel, mapboxMap.getCameraPosition(), animationDuration, callback); + } + + /** + * Zooms to the desired zoom level. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param zoomLevel The desired zoom level. + * @param animationDuration The zoom animation duration. + */ + public void zoomWhileTracking(double zoomLevel, long animationDuration) { + checkActivationState(); + zoomWhileTracking(zoomLevel, animationDuration, null); + } + + /** + * Zooms to the desired zoom level. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param zoomLevel The desired zoom level. + */ + public void zoomWhileTracking(double zoomLevel) { + checkActivationState(); + zoomWhileTracking(zoomLevel, DEFAULT_TRACKING_ZOOM_ANIM_DURATION, null); + } + + /** + * Cancels animation started by {@link #zoomWhileTracking(double, long, MapboxMap.CancelableCallback)}. + */ + public void cancelZoomWhileTrackingAnimation() { + checkActivationState(); + locationAnimatorCoordinator.cancelZoomAnimation(); + } + + /** + * Tilts the camera. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param tilt The desired camera tilt. + * @param animationDuration The tilt animation duration. + * @param callback The callback with finish/cancel information + */ + public void tiltWhileTracking(double tilt, long animationDuration, + @Nullable MapboxMap.CancelableCallback callback) { + checkActivationState(); + if (!isLayerReady) { + return; + } else if (getCameraMode() == CameraMode.NONE) { + Logger.e(TAG, String.format("%s%s", + "LocationComponent#tiltWhileTracking method can only be used", + " when a camera mode other than CameraMode#NONE is engaged.")); + return; + } + locationAnimatorCoordinator.feedNewTilt(tilt, mapboxMap.getCameraPosition(), animationDuration, callback); + } + + /** + * Tilts the camera. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param tilt The desired camera tilt. + * @param animationDuration The tilt animation duration. + */ + public void tiltWhileTracking(double tilt, long animationDuration) { + checkActivationState(); + tiltWhileTracking(tilt, animationDuration, null); + } + + /** + * Tilts the camera. + * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. + * If you are not using any of {@link CameraMode} modes, + * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, + * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + * + * @param tilt The desired camera tilt. + */ + public void tiltWhileTracking(double tilt) { + checkActivationState(); + tiltWhileTracking(tilt, DEFAULT_TRACKING_TILT_ANIM_DURATION, null); + } + + /** + * Cancels animation started by {@link #tiltWhileTracking(double, long, MapboxMap.CancelableCallback)}. + */ + public void cancelTiltWhileTrackingAnimation() { + checkActivationState(); + locationAnimatorCoordinator.cancelTiltAnimation(); + } + + /** + * Use to either force a location update or to manually control when the user location gets + * updated. + * + * @param location where the location icon is placed on the map + */ + public void forceLocationUpdate(@Nullable Location location) { + checkActivationState(); + updateLocation(location, false); + } + + /** + * Set max FPS at which location animators can output updates. The throttling will only impact the location puck + * and camera tracking smooth animations. + *

+ * Setting this will not impact any other animations schedule with {@link MapboxMap}, gesture animations or + * {@link #zoomWhileTracking(double)}/{@link #tiltWhileTracking(double)}. + *

+ * Use this setting to limit animation rate of the location puck on higher zoom levels to decrease the stress on + * the device's CPU which can directly improve battery life, without sacrificing UX. + *

+ * Example usage: + *

+   * {@code
+   * mapboxMap.addOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() {
+   *   {@literal @}Override
+   *   public void onCameraIdle() {
+   *     double zoom = mapboxMap.getCameraPosition().zoom;
+   *     int maxAnimationFps;
+   *     if (zoom < 5) {
+   *       maxAnimationFps = 3;
+   *     } else if (zoom < 10) {
+   *       maxAnimationFps = 5;
+   *     } else if (zoom < 15) {
+   *       maxAnimationFps = 7;
+   *     } else if (zoom < 18) {
+   *       maxAnimationFps = 15;
+   *     } else {
+   *       maxAnimationFps = Integer.MAX_VALUE;
+   *     }
+   *     locationComponent.setMaxAnimationFps(maxAnimationFps);
+   *   }
+   * });
+   * }
+   * 
+ *

+ * If you're looking for a way to throttle the FPS of the whole map, including other animations and gestures, see + * {@link MapView#setMaximumFps(int)}. + * + * @param maxAnimationFps max location animation FPS + */ + public void setMaxAnimationFps(int maxAnimationFps) { + checkActivationState(); + locationAnimatorCoordinator.setMaxAnimationFps(maxAnimationFps); + } + + /** + * Set the location engine to update the current user location. + *

+ * If {@code null} is passed in, all updates will have to occur through the + * {@link LocationComponent#forceLocationUpdate(Location)} method. + * + * @param locationEngine a {@link LocationEngine} this component should use to handle updates + */ + @SuppressLint("MissingPermission") + public void setLocationEngine(@Nullable LocationEngine locationEngine) { + checkActivationState(); + if (this.locationEngine != null) { + // If internal location engines being used, extra steps need to be taken to deconstruct the instance. + this.locationEngine.removeLocationUpdates(currentLocationEngineListener); + this.locationEngine = null; + } + + if (locationEngine != null) { + fastestInterval = locationEngineRequest.getFastestInterval(); + this.locationEngine = locationEngine; + if (isLayerReady && isEnabled) { + setLastLocation(); + locationEngine.requestLocationUpdates( + locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper()); + } + } else { + fastestInterval = 0; + } + } + + /** + * Set the location request that's going to be used when requesting location updates. + * + * @param locationEngineRequest the location request + */ + public void setLocationEngineRequest(@NonNull LocationEngineRequest locationEngineRequest) { + checkActivationState(); + this.locationEngineRequest = locationEngineRequest; + + // reset internal LocationEngine ref to re-request location updates if needed + setLocationEngine(locationEngine); + } + + /** + * Get the location request that's going to be used when requesting location updates. + */ + @NonNull + public LocationEngineRequest getLocationEngineRequest() { + checkActivationState(); + return locationEngineRequest; + } + + /** + * Returns the current {@link LocationEngine} being used for updating the user location. + * + * @return the {@link LocationEngine} being used to update the user location + */ + @Nullable + public LocationEngine getLocationEngine() { + checkActivationState(); + return locationEngine; + } + + /** + * Sets the compass engine used to provide compass heading values. + * + * @param compassEngine to be used + */ + public void setCompassEngine(@Nullable CompassEngine compassEngine) { + checkActivationState(); + if (this.compassEngine != null) { + updateCompassListenerState(false); + } + this.compassEngine = compassEngine; + updateCompassListenerState(true); + } + + /** + * Returns the compass engine used to provide compass heading values. + * + * @return compass engine currently being used + */ + @Nullable + public CompassEngine getCompassEngine() { + checkActivationState(); + return compassEngine; + } + + /** + * Get the last know location of the location component. + * + * @return the last known location + */ + @Nullable + public Location getLastKnownLocation() { + checkActivationState(); + return lastLocation; + } + + /** + * Adds a listener that gets invoked when the user clicks the displayed location. + *

+ * If there are registered location click listeners and the location is clicked, + * only {@link OnLocationClickListener#onLocationComponentClick()} is going to be delivered, + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener#onMapClick(LatLng)} is going to be consumed + * and not pushed to the listeners registered after the component's activation. + * + * @param listener The location click listener that is invoked when the + * location is clicked + */ + public void addOnLocationClickListener(@NonNull OnLocationClickListener listener) { + onLocationClickListeners.add(listener); + } + + /** + * Removes the passed listener from the current list of location click listeners. + * + * @param listener to be removed + */ + public void removeOnLocationClickListener(@NonNull OnLocationClickListener listener) { + onLocationClickListeners.remove(listener); + } + + /** + * Adds a listener that gets invoked when the user long clicks the displayed location. + *

+ * If there are registered location long click listeners and the location is long clicked, + * only {@link OnLocationLongClickListener#onLocationComponentLongClick()} is going to be delivered, + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnMapLongClickListener#onMapLongClick(LatLng)} is going to be consumed + * and not pushed to the listeners registered after the component's activation. + * + * @param listener The location click listener that is invoked when the + * location is clicked + */ + public void addOnLocationLongClickListener(@NonNull OnLocationLongClickListener listener) { + onLocationLongClickListeners.add(listener); + } + + /** + * Removes the passed listener from the current list of location long click listeners. + * + * @param listener to be removed + */ + public void removeOnLocationLongClickListener(@NonNull OnLocationLongClickListener listener) { + onLocationLongClickListeners.remove(listener); + } + + /** + * Adds a listener that gets invoked when camera tracking state changes. + * + * @param listener Listener that gets invoked when camera tracking state changes. + */ + public void addOnCameraTrackingChangedListener(@NonNull OnCameraTrackingChangedListener listener) { + onCameraTrackingChangedListeners.add(listener); + } + + /** + * Removes a listener that gets invoked when camera tracking state changes. + * + * @param listener Listener that gets invoked when camera tracking state changes. + */ + public void removeOnCameraTrackingChangedListener(@NonNull OnCameraTrackingChangedListener listener) { + onCameraTrackingChangedListeners.remove(listener); + } + + /** + * Adds a listener that gets invoked when render mode changes. + * + * @param listener Listener that gets invoked when render mode changes. + */ + public void addOnRenderModeChangedListener(@NonNull OnRenderModeChangedListener listener) { + onRenderModeChangedListeners.add(listener); + } + + /** + * Removes a listener that gets invoked when render mode changes. + * + * @param listener Listener that gets invoked when render mode changes. + */ + public void removeRenderModeChangedListener(@NonNull OnRenderModeChangedListener listener) { + onRenderModeChangedListeners.remove(listener); + } + + /** + * Adds the passed listener that gets invoked when user updates have stopped long enough for the last update + * to be considered stale. + *

+ * This timeout is set by {@link LocationComponentOptions#staleStateTimeout()}. + * + * @param listener invoked when last update is considered stale + */ + public void addOnLocationStaleListener(@NonNull OnLocationStaleListener listener) { + onLocationStaleListeners.add(listener); + } + + /** + * Removes the passed listener from the current list of stale listeners. + * + * @param listener to be removed from the list + */ + public void removeOnLocationStaleListener(@NonNull OnLocationStaleListener listener) { + onLocationStaleListeners.remove(listener); + } + + /** + * Internal use. + */ + public void onStart() { + isComponentStarted = true; + onLocationLayerStart(); + } + + /** + * Internal use. + */ + public void onStop() { + onLocationLayerStop(); + isComponentStarted = false; + } + + /** + * Internal use. + */ + public void onDestroy() { + } + + /** + * Internal use. + */ + public void onStartLoadingMap() { + onLocationLayerStop(); + } + + /** + * Internal use. + */ + public void onFinishLoadingStyle() { + if (isComponentInitialized) { + style = mapboxMap.getStyle(); + locationLayerController.initializeComponents(style, options); + locationCameraController.initializeOptions(options); + onLocationLayerStart(); + } + } + + @SuppressLint("MissingPermission") + private void onLocationLayerStart() { + if (!isComponentInitialized || !isComponentStarted || mapboxMap.getStyle() == null) { + return; + } + + if (!isLayerReady) { + isLayerReady = true; + mapboxMap.addOnCameraMoveListener(onCameraMoveListener); + mapboxMap.addOnCameraIdleListener(onCameraIdleListener); + if (options.enableStaleState()) { + staleStateManager.onStart(); + } + } + + if (isEnabled) { + if (locationEngine != null) { + try { + locationEngine.requestLocationUpdates( + locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper()); + } catch (SecurityException se) { + Logger.e(TAG, "Unable to request location updates", se); + } + } + setCameraMode(locationCameraController.getCameraMode()); + setLastLocation(); + updateCompassListenerState(true); + setLastCompassHeading(); + } + } + + private void onLocationLayerStop() { + if (!isComponentInitialized || !isLayerReady || !isComponentStarted) { + return; + } + + isLayerReady = false; + staleStateManager.onStop(); + if (compassEngine != null) { + updateCompassListenerState(false); + } + locationAnimatorCoordinator.cancelAllAnimations(); + if (locationEngine != null) { + locationEngine.removeLocationUpdates(currentLocationEngineListener); + } + mapboxMap.removeOnCameraMoveListener(onCameraMoveListener); + mapboxMap.removeOnCameraIdleListener(onCameraIdleListener); + } + + private void initialize(@NonNull final Context context, @NonNull Style style, + @NonNull final LocationComponentOptions options) { + if (isComponentInitialized) { + return; + } + isComponentInitialized = true; + + if (!style.isFullyLoaded()) { + throw new IllegalStateException("Style is invalid, provide the most recently loaded one."); + } + + this.style = style; + this.options = options; + + mapboxMap.addOnMapClickListener(onMapClickListener); + mapboxMap.addOnMapLongClickListener(onMapLongClickListener); + + LayerSourceProvider sourceProvider = new LayerSourceProvider(); + LayerFeatureProvider featureProvider = new LayerFeatureProvider(); + LayerBitmapProvider bitmapProvider = new LayerBitmapProvider(context); + locationLayerController = new LocationLayerController(mapboxMap, style, sourceProvider, featureProvider, + bitmapProvider, options, renderModeChangedListener); + locationCameraController = new LocationCameraController( + context, mapboxMap, transform, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener); + + locationAnimatorCoordinator = new LocationAnimatorCoordinator( + mapboxMap.getProjection(), + MapboxAnimatorSetProvider.getInstance(), + MapboxAnimatorProvider.getInstance() + ); + locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options + .trackingAnimationDurationMultiplier()); + + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + if (windowManager != null && sensorManager != null) { + compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); + } + staleStateManager = new StaleStateManager(onLocationStaleListener, options); + + updateMapWithOptions(options); + + setRenderMode(RenderMode.NORMAL); + setCameraMode(CameraMode.NONE); + + onLocationLayerStart(); + } + + private void initializeLocationEngine(@NonNull Context context) { + if (this.locationEngine != null) { + this.locationEngine.removeLocationUpdates(currentLocationEngineListener); + } + setLocationEngine(internalLocationEngineProvider.getBestLocationEngine(context, false)); + } + + private void updateCompassListenerState(boolean canListen) { + if (compassEngine != null) { + if (!canListen) { + // We shouldn't listen, simply unregistering + removeCompassListener(compassEngine); + return; + } + + if (!isComponentInitialized || !isComponentStarted || !isEnabled) { + return; + } + + if (locationCameraController.isConsumingCompass() || locationLayerController.isConsumingCompass()) { + // If we have a consumer, and not yet listening, then start listening + if (!isListeningToCompass) { + isListeningToCompass = true; + compassEngine.addCompassListener(compassListener); + } + } else { + // If we have no consumers, stop listening + removeCompassListener(compassEngine); + } + } + } + + private void removeCompassListener(@NonNull CompassEngine engine) { + if (isListeningToCompass) { + isListeningToCompass = false; + engine.removeCompassListener(compassListener); + } + } + + private void enableLocationComponent() { + isEnabled = true; + onLocationLayerStart(); + } + + private void disableLocationComponent() { + isEnabled = false; + locationLayerController.hide(); + onLocationLayerStop(); + } + + private void updateMapWithOptions(@NonNull LocationComponentOptions options) { + int[] padding = options.padding(); + if (padding != null) { + mapboxMap.setPadding( + padding[0], padding[1], padding[2], padding[3] + ); + } + } + + /** + * Updates the user location icon. + * + * @param location the latest user location + */ + private void updateLocation(@Nullable final Location location, boolean fromLastLocation) { + if (location == null) { + return; + } else if (!isLayerReady) { + lastLocation = location; + return; + } else { + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime - lastUpdateTime < fastestInterval) { + return; + } else { + lastUpdateTime = currentTime; + } + } + + showLocationLayerIfHidden(); + + if (!fromLastLocation) { + staleStateManager.updateLatestLocationTime(); + } + CameraPosition currentCameraPosition = mapboxMap.getCameraPosition(); + boolean isGpsNorth = getCameraMode() == CameraMode.TRACKING_GPS_NORTH; + locationAnimatorCoordinator.feedNewLocation(location, currentCameraPosition, isGpsNorth); + updateAccuracyRadius(location, false); + lastLocation = location; + } + + private void showLocationLayerIfHidden() { + boolean isLocationLayerHidden = locationLayerController.isHidden(); + if (isEnabled && isComponentStarted && isLocationLayerHidden) { + locationLayerController.show(); + } + } + + private void updateCompassHeading(float heading) { + locationAnimatorCoordinator.feedNewCompassBearing(heading, mapboxMap.getCameraPosition()); + } + + /** + * If the locationEngine contains a last location value, we use it for the initial location layer + * position. + */ + @SuppressLint("MissingPermission") + private void setLastLocation() { + if (locationEngine != null) { + locationEngine.getLastLocation(lastLocationEngineListener); + } else { + updateLocation(getLastKnownLocation(), true); + } + } + + private void setLastCompassHeading() { + updateCompassHeading(compassEngine != null ? compassEngine.getLastHeading() : 0); + } + + @SuppressLint("MissingPermission") + private void updateLayerOffsets(boolean forceUpdate) { + CameraPosition position = mapboxMap.getCameraPosition(); + if (lastCameraPosition == null || forceUpdate) { + lastCameraPosition = position; + locationLayerController.updateForegroundBearing((float) position.bearing); + locationLayerController.updateForegroundOffset(position.tilt); + updateAccuracyRadius(getLastKnownLocation(), true); + return; + } + + if (position.bearing != lastCameraPosition.bearing) { + locationLayerController.updateForegroundBearing((float) position.bearing); + } + if (position.tilt != lastCameraPosition.tilt) { + locationLayerController.updateForegroundOffset(position.tilt); + } + if (position.zoom != lastCameraPosition.zoom) { + updateAccuracyRadius(getLastKnownLocation(), true); + } + lastCameraPosition = position; + } + + private void updateAccuracyRadius(Location location, boolean noAnimation) { + locationAnimatorCoordinator.feedNewAccuracyRadius(Utils.calculateZoomLevelRadius(mapboxMap, location), noAnimation); + } + + private void updateAnimatorListenerHolders() { + Set animationsValueChangeListeners = new HashSet<>(); + animationsValueChangeListeners.addAll(locationLayerController.getAnimationListeners()); + animationsValueChangeListeners.addAll(locationCameraController.getAnimationListeners()); + locationAnimatorCoordinator.updateAnimatorListenerHolders(animationsValueChangeListeners); + locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(), + locationCameraController.getCameraMode() == CameraMode.TRACKING_GPS_NORTH); + locationAnimatorCoordinator.resetAllLayerAnimations(); + } + + @NonNull + private OnCameraMoveListener onCameraMoveListener = new OnCameraMoveListener() { + @Override + public void onCameraMove() { + updateLayerOffsets(false); + } + }; + + @NonNull + private OnCameraIdleListener onCameraIdleListener = new OnCameraIdleListener() { + @Override + public void onCameraIdle() { + updateLayerOffsets(false); + } + }; + + @NonNull + private OnMapClickListener onMapClickListener = new OnMapClickListener() { + @Override + public boolean onMapClick(@NonNull LatLng point) { + if (!onLocationClickListeners.isEmpty() && locationLayerController.onMapClick(point)) { + for (OnLocationClickListener listener : onLocationClickListeners) { + listener.onLocationComponentClick(); + } + return true; + } + return false; + } + }; + + @NonNull + private MapboxMap.OnMapLongClickListener onMapLongClickListener = new MapboxMap.OnMapLongClickListener() { + @Override + public boolean onMapLongClick(@NonNull LatLng point) { + if (!onLocationLongClickListeners.isEmpty() && locationLayerController.onMapClick(point)) { + for (OnLocationLongClickListener listener : onLocationLongClickListeners) { + listener.onLocationComponentLongClick(); + } + return true; + } + return false; + } + }; + + @NonNull + private OnLocationStaleListener onLocationStaleListener = new OnLocationStaleListener() { + @Override + public void onStaleStateChange(boolean isStale) { + locationLayerController.setLocationsStale(isStale); + + for (OnLocationStaleListener listener : onLocationStaleListeners) { + listener.onStaleStateChange(isStale); + } + } + }; + + @NonNull + private OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = new OnCameraMoveInvalidateListener() { + @Override + public void onInvalidateCameraMove() { + onCameraMoveListener.onCameraMove(); + } + }; + + @NonNull + private CompassListener compassListener = new CompassListener() { + @Override + public void onCompassChanged(float userHeading) { + updateCompassHeading(userHeading); + } + + @Override + public void onCompassAccuracyChange(int compassStatus) { + // Currently don't handle this inside SDK + } + }; + + @VisibleForTesting + static final class CurrentLocationEngineCallback implements LocationEngineCallback { + private final WeakReference componentWeakReference; + + CurrentLocationEngineCallback(LocationComponent component) { + this.componentWeakReference = new WeakReference<>(component); + } + + @Override + public void onSuccess(LocationEngineResult result) { + LocationComponent component = componentWeakReference.get(); + if (component != null) { + component.updateLocation(result.getLastLocation(), false); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Logger.e(TAG, "Failed to obtain location update", exception); + } + } + + @VisibleForTesting + static final class LastLocationEngineCallback implements LocationEngineCallback { + private final WeakReference componentWeakReference; + + LastLocationEngineCallback(LocationComponent component) { + this.componentWeakReference = new WeakReference<>(component); + } + + @Override + public void onSuccess(LocationEngineResult result) { + LocationComponent component = componentWeakReference.get(); + if (component != null) { + component.updateLocation(result.getLastLocation(), true); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Logger.e(TAG, "Failed to obtain last location update", exception); + } + } + + @NonNull + @VisibleForTesting + OnCameraTrackingChangedListener cameraTrackingChangedListener = new OnCameraTrackingChangedListener() { + @Override + public void onCameraTrackingDismissed() { + for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) { + listener.onCameraTrackingDismissed(); + } + } + + @Override + public void onCameraTrackingChanged(int currentMode) { + locationAnimatorCoordinator.cancelZoomAnimation(); + locationAnimatorCoordinator.cancelTiltAnimation(); + updateAnimatorListenerHolders(); + for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) { + listener.onCameraTrackingChanged(currentMode); + } + } + }; + + @NonNull + @VisibleForTesting + OnRenderModeChangedListener renderModeChangedListener = new OnRenderModeChangedListener() { + @Override + public void onRenderModeChanged(int currentMode) { + updateAnimatorListenerHolders(); + for (OnRenderModeChangedListener listener : onRenderModeChangedListeners) { + listener.onRenderModeChanged(currentMode); + } + } + }; + + @NonNull + private final MapboxMap.OnDeveloperAnimationListener developerAnimationListener = + new MapboxMap.OnDeveloperAnimationListener() { + @Override + public void onDeveloperAnimationStarted() { + if (isComponentInitialized && isEnabled) { + setCameraMode(CameraMode.NONE); + } + } + }; + + static class InternalLocationEngineProvider { + LocationEngine getBestLocationEngine(@NonNull Context context, boolean background) { + return LocationEngineProvider.getBestLocationEngine(context, background); + } + } + + private void checkActivationState() { + if (!isComponentInitialized) { + throw new LocationComponentNotInitializedException(); + } + } + + /** + * Returns whether the location component is activated. + * + * @return true if the component is activated, false otherwise + */ + public boolean isLocationComponentActivated() { + return isComponentInitialized; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java new file mode 100644 index 000000000..04987621e --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -0,0 +1,244 @@ +package com.mapbox.mapboxsdk.location; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.android.core.location.LocationEngine; +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.mapboxsdk.maps.Style; + +/** + * A class which holds the various options for activating the Maps SDK's {@link LocationComponent} to eventually + * show the device location on the map. + */ +public class LocationComponentActivationOptions { + + private final Context context; + private final Style style; + private final LocationEngine locationEngine; + private final LocationEngineRequest locationEngineRequest; + private final LocationComponentOptions locationComponentOptions; + private final int styleRes; + private final boolean useDefaultLocationEngine; + + private LocationComponentActivationOptions(@NonNull Context context, @NonNull Style style, + @Nullable LocationEngine locationEngine, + @Nullable LocationEngineRequest locationEngineRequest, + @Nullable LocationComponentOptions locationComponentOptions, + int styleRes, + boolean useDefaultLocationEngine) { + this.context = context; + this.style = style; + this.locationEngine = locationEngine; + this.locationEngineRequest = locationEngineRequest; + this.locationComponentOptions = locationComponentOptions; + this.styleRes = styleRes; + this.useDefaultLocationEngine = useDefaultLocationEngine; + } + + /** + * Convenience method to retrieve a {@link LocationComponentActivationOptions} object which is ready to build with + * + * @return a builder object + */ + @NonNull + public static Builder builder(@NonNull Context context, @NonNull Style fullyLoadedMapStyle) { + return new LocationComponentActivationOptions.Builder(context, fullyLoadedMapStyle); + } + + /** + * The application's current context + * + * @return the application's current context + */ + @NonNull + public Context context() { + return context; + } + + /** + * The proxy object for current map style. More info at {@link Style} + * + * @return the map's fully loaded Style object + */ + @NonNull + public Style style() { + return style; + } + + /** + * The {@link LocationEngine} which the {@link LocationComponent} should use + * + * @return the engine + */ + @Nullable + public LocationEngine locationEngine() { + return locationEngine; + } + + /** + * The location request which the {@link LocationComponent} should use + * + * @return the LocationEngineRequest object + */ + @Nullable + public LocationEngineRequest locationEngineRequest() { + return locationEngineRequest; + } + + /** + * A built {@link LocationComponentOptions} object, which holds the various {@link LocationComponent} styling options + * + * @return the options for styling the actual LocationComponent + */ + @Nullable + public LocationComponentOptions locationComponentOptions() { + return locationComponentOptions; + } + + /** + * The LocationComponent style resource (e.g. R.style.style_name) + * + * @return the style resource. + */ + public int styleRes() { + return styleRes; + } + + /** + * True if you want to initialize and use the built-in location engine or false if there should be no + * location engine initialized + * + * @return whether the default LocationEngine is used + */ + public boolean useDefaultLocationEngine() { + return useDefaultLocationEngine; + } + + /** + * Builder class for constructing a new instance of {@link LocationComponentActivationOptions}. + */ + public static class Builder { + private final Context context; + private final Style style; + private LocationEngine locationEngine; + private LocationEngineRequest locationEngineRequest; + private LocationComponentOptions locationComponentOptions; + private int styleRes; + + /** + * Set to true as the default in case a true/false value isn't declared via the builder's + * {@link LocationComponentActivationOptions#useDefaultLocationEngine()} method. + *

+ * Please be aware that this activation boolean is ignored when a non-null + * {@link LocationEngine} is set via the builder's `locationEngine()` method. + */ + private boolean useDefaultLocationEngine = true; + + /** + * Constructor for the {@link LocationComponentActivationOptions} builder class. + * While other activation options are optional, the activation process always requires + * context and a fully-loaded map {@link Style} object, which is why the two are in this + * constructor. + */ + public Builder(@NonNull Context context, @NonNull Style style) { + this.context = context; + this.style = style; + } + + /** + * Deliver your own {@link LocationEngine} to the LocationComponent. + *

+ * The true/false + * {@link LocationComponentActivationOptions.Builder#useDefaultLocationEngine()} + * activation option is ignored when a non-null {@link LocationEngine} is set via + * this `locationEngine()` method. + * + * @param locationEngine a {@link LocationEngine} object + * @return the {@link Builder} object being constructed + */ + @NonNull + public Builder locationEngine(@Nullable LocationEngine locationEngine) { + this.locationEngine = locationEngine; + return this; + } + + /** + * @param locationEngineRequest the location request which the + * {@link LocationComponent} should use + * @return the {@link Builder} object being constructed + */ + public Builder locationEngineRequest(LocationEngineRequest locationEngineRequest) { + this.locationEngineRequest = locationEngineRequest; + return this; + } + + /** + * @param locationComponentOptions a built {@link LocationComponentOptions} object, + * which holds the various {@link LocationComponent} + * styling options + * @return the {@link Builder} object being constructed + */ + public Builder locationComponentOptions(LocationComponentOptions locationComponentOptions) { + this.locationComponentOptions = locationComponentOptions; + return this; + } + + /** + * @param styleRes the LocationComponent style resource (e.g. R.style.style_name) + * @return the {@link Builder} object being constructed + */ + public Builder styleRes(int styleRes) { + this.styleRes = styleRes; + return this; + } + + /** + * @param useDefaultLocationEngine true if you want to initialize and use the + * built-in location engine or false if there + * should be no location engine initialized + * This is ignored when null is set as the parameter + * for {@link LocationComponentActivationOptions#builder + * (Context, Style)#locationEngine()}. + * @return the {@link Builder} object being constructed + */ + public Builder useDefaultLocationEngine(boolean useDefaultLocationEngine) { + this.useDefaultLocationEngine = useDefaultLocationEngine; + return this; + } + + /** + * Method which actually builds the {@link LocationComponentActivationOptions} object while + * taking the various options into account. + * + * @return a built {@link LocationComponentActivationOptions} object + */ + public LocationComponentActivationOptions build() { + if (styleRes != 0 && locationComponentOptions != null) { + throw new IllegalArgumentException( + "You've provided both a style resource and a LocationComponentOptions object to the " + + "LocationComponentActivationOptions builder. You can't use both and " + + "you must choose one of the two to style the LocationComponent."); + } + if (context == null) { + throw new NullPointerException( + "Context in LocationComponentActivationOptions is null."); + } + if (style == null) { + throw new NullPointerException( + "Style in LocationComponentActivationOptions is null. Make sure the " + + "Style object isn't null. Wait for the map to fully load before passing " + + "the Style object to LocationComponentActivationOptions."); + } + if (!style.isFullyLoaded()) { + throw new IllegalArgumentException( + "Style in LocationComponentActivationOptions isn't fully loaded. Wait for the " + + "map to fully load before passing the Style object to " + + "LocationComponentActivationOptions."); + } + return new LocationComponentActivationOptions(context, style, locationEngine, + locationEngineRequest, locationComponentOptions, styleRes, useDefaultLocationEngine); + } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java new file mode 100644 index 000000000..ce3823303 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -0,0 +1,268 @@ +package com.mapbox.mapboxsdk.location; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.Surface; +import android.view.WindowManager; + +import com.mapbox.mapboxsdk.log.Logger; + +import java.util.ArrayList; +import java.util.List; + +/** + * This manager class handles compass events such as starting the tracking of device bearing, or + * when a new compass update occurs. + */ +class LocationComponentCompassEngine implements CompassEngine, SensorEventListener { + + private static final String TAG = "Mbgl-LocationComponentCompassEngine"; + + // The rate sensor events will be delivered at. As the Android documentation states, this is only + // a hint to the system and the events might actually be received faster or slower then this + // specified rate. Since the minimum Android API levels about 9, we are able to set this value + // ourselves rather than using one of the provided constants which deliver updates too quickly for + // our use case. The default is set to 100ms + static final int SENSOR_DELAY_MICROS = 100 * 1000; + // Filtering coefficient 0 < ALPHA < 1 + private static final float ALPHA = 0.45f; + + @NonNull + private final WindowManager windowManager; + @NonNull + private final SensorManager sensorManager; + private final List compassListeners = new ArrayList<>(); + + // Not all devices have a compassSensor + @Nullable + private Sensor compassSensor; + @Nullable + private Sensor gravitySensor; + @Nullable + private Sensor magneticFieldSensor; + + @NonNull + private float[] truncatedRotationVectorValue = new float[4]; + @NonNull + private float[] rotationMatrix = new float[9]; + private float[] rotationVectorValue; + private float lastHeading; + private int lastAccuracySensorStatus; + + private long compassUpdateNextTimestamp; + @Nullable + private float[] gravityValues = new float[3]; + @Nullable + private float[] magneticValues = new float[3]; + + /** + * Construct a new instance of the this class. A internal compass listeners needed to separate it + * from the cleared list of public listeners. + */ + LocationComponentCompassEngine(@NonNull WindowManager windowManager, @NonNull SensorManager sensorManager) { + this.windowManager = windowManager; + this.sensorManager = sensorManager; + compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); + if (compassSensor == null) { + if (isGyroscopeAvailable()) { + Logger.d(TAG, "Rotation vector sensor not supported on device, " + + "falling back to orientation."); + compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); + } else { + Logger.d(TAG, "Rotation vector sensor not supported on device, " + + "falling back to accelerometer and magnetic field."); + gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + magneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + } + } + } + + @Override + public void addCompassListener(@NonNull CompassListener compassListener) { + if (compassListeners.isEmpty()) { + registerSensorListeners(); + } + compassListeners.add(compassListener); + } + + @Override + public void removeCompassListener(@NonNull CompassListener compassListener) { + compassListeners.remove(compassListener); + if (compassListeners.isEmpty()) { + unregisterSensorListeners(); + } + } + + @Override + public int getLastAccuracySensorStatus() { + return lastAccuracySensorStatus; + } + + @Override + public float getLastHeading() { + return lastHeading; + } + + @Override + public void onSensorChanged(@NonNull SensorEvent event) { + // check when the last time the compass was updated, return if too soon. + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime < compassUpdateNextTimestamp) { + return; + } + if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { + Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); + return; + } + if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { + rotationVectorValue = getRotationVectorFromSensorEvent(event); + updateOrientation(); + } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { + notifyCompassChangeListeners((event.values[0] + 360) % 360); + } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { + gravityValues = lowPassFilter(getRotationVectorFromSensorEvent(event), gravityValues); + updateOrientation(); + } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { + magneticValues = lowPassFilter(getRotationVectorFromSensorEvent(event), magneticValues); + updateOrientation(); + } + + // Update the compassUpdateNextTimestamp + compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + if (lastAccuracySensorStatus != accuracy) { + for (CompassListener compassListener : compassListeners) { + compassListener.onCompassAccuracyChange(accuracy); + } + lastAccuracySensorStatus = accuracy; + } + } + + private boolean isGyroscopeAvailable() { + return sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null; + } + + @SuppressWarnings("SuspiciousNameCombination") + private void updateOrientation() { + if (rotationVectorValue != null) { + SensorManager.getRotationMatrixFromVector(rotationMatrix, rotationVectorValue); + } else { + // Get rotation matrix given the gravity and geomagnetic matrices + SensorManager.getRotationMatrix(rotationMatrix, null, gravityValues, magneticValues); + } + + final int worldAxisForDeviceAxisX; + final int worldAxisForDeviceAxisY; + + // Remap the axes as if the device screen was the instrument panel, + // and adjust the rotation matrix for the device orientation. + switch (windowManager.getDefaultDisplay().getRotation()) { + case Surface.ROTATION_90: + worldAxisForDeviceAxisX = SensorManager.AXIS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_X; + break; + case Surface.ROTATION_180: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Z; + break; + case Surface.ROTATION_270: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_X; + break; + case Surface.ROTATION_0: + default: + worldAxisForDeviceAxisX = SensorManager.AXIS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_Z; + break; + } + + float[] adjustedRotationMatrix = new float[9]; + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, + worldAxisForDeviceAxisY, adjustedRotationMatrix); + + // Transform rotation matrix into azimuth/pitch/roll + float[] orientation = new float[3]; + SensorManager.getOrientation(adjustedRotationMatrix, orientation); + + // The x-axis is all we care about here. + notifyCompassChangeListeners((float) Math.toDegrees(orientation[0])); + } + + private void notifyCompassChangeListeners(float heading) { + for (CompassListener compassListener : compassListeners) { + compassListener.onCompassChanged(heading); + } + lastHeading = heading; + } + + private void registerSensorListeners() { + if (isCompassSensorAvailable()) { + // Does nothing if the sensors already registered. + sensorManager.registerListener(this, compassSensor, SENSOR_DELAY_MICROS); + } else { + sensorManager.registerListener(this, gravitySensor, SENSOR_DELAY_MICROS); + sensorManager.registerListener(this, magneticFieldSensor, SENSOR_DELAY_MICROS); + } + } + + private void unregisterSensorListeners() { + if (isCompassSensorAvailable()) { + sensorManager.unregisterListener(this, compassSensor); + } else { + sensorManager.unregisterListener(this, gravitySensor); + sensorManager.unregisterListener(this, magneticFieldSensor); + } + } + + private boolean isCompassSensorAvailable() { + return compassSensor != null; + } + + /** + * Helper function, that filters newValues, considering previous values + * + * @param newValues array of float, that contains new data + * @param smoothedValues array of float, that contains previous state + * @return float filtered array of float + */ + @NonNull + private float[] lowPassFilter(@NonNull float[] newValues, @Nullable float[] smoothedValues) { + if (smoothedValues == null) { + return newValues; + } + for (int i = 0; i < newValues.length; i++) { + smoothedValues[i] = smoothedValues[i] + ALPHA * (newValues[i] - smoothedValues[i]); + } + return smoothedValues; + } + + /** + * 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 + private 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; + } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java new file mode 100644 index 000000000..f2158584c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -0,0 +1,94 @@ +package com.mapbox.mapboxsdk.location; + +/** + * Contains all the constants being used for the {@link LocationComponent}. + */ +public final class LocationComponentConstants { + + // Controls the compass update rate in milliseconds + static final long COMPASS_UPDATE_RATE_MS = 500; + + // Sets the transition animation duration when switching camera modes. + static final long TRANSITION_ANIMATION_DURATION_MS = 750; + + // Sets the max allowed time for the location icon animation from one LatLng to another. + static final long MAX_ANIMATION_DURATION_MS = 2000; + + // Sets the duration of change of accuracy radius when a different value is provided. + static final long ACCURACY_RADIUS_ANIMATION_DURATION = 250; + + // Default animation duration for zooming while tracking. + static final long DEFAULT_TRACKING_ZOOM_ANIM_DURATION = 750; + + // Default animation duration for tilting while tracking. + static final long DEFAULT_TRACKING_TILT_ANIM_DURATION = 1250; + + // Threshold value to perform immediate camera/layer position update. + static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 50_000; + + // Default interval between location updates + static final long DEFAULT_INTERVAL_MILLIS = 1000; + + // Default fastest acceptable interval between location updates + static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000; + + // Sources + + /** + * Source ID of the location's GeoJsonSource. + */ + public static final String LOCATION_SOURCE = "mapbox-location-source"; + + static final String PROPERTY_GPS_BEARING = "mapbox-property-gps-bearing"; + static final String PROPERTY_COMPASS_BEARING = "mapbox-property-compass-bearing"; + static final String PROPERTY_LOCATION_STALE = "mapbox-property-location-stale"; + static final String PROPERTY_ACCURACY_RADIUS = "mapbox-property-accuracy-radius"; + static final String PROPERTY_ACCURACY_COLOR = "mapbox-property-accuracy-color"; + static final String PROPERTY_ACCURACY_ALPHA = "mapbox-property-accuracy-alpha"; + static final String PROPERTY_FOREGROUND_ICON_OFFSET = "mapbox-property-foreground-icon-offset"; + static final String PROPERTY_SHADOW_ICON_OFFSET = "mapbox-property-shadow-icon-offset"; + static final String PROPERTY_FOREGROUND_ICON = "mapbox-property-foreground-icon"; + static final String PROPERTY_BACKGROUND_ICON = "mapbox-property-background-icon"; + static final String PROPERTY_FOREGROUND_STALE_ICON = "mapbox-property-foreground-stale-icon"; + static final String PROPERTY_BACKGROUND_STALE_ICON = "mapbox-property-background-stale-icon"; + static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon"; + + // Layers + + /** + * Layer ID of the location shadow. + */ + public static final String SHADOW_LAYER = "mapbox-location-shadow-layer"; + + /** + * Layer ID of the location foreground icon. + */ + public static final String FOREGROUND_LAYER = "mapbox-location-foreground-layer"; + + /** + * Layer ID of the location background icon. + */ + public static final String BACKGROUND_LAYER = "mapbox-location-background-layer"; + + /** + * Layer ID of the location accuracy. + */ + public static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer"; + + /** + * Layer ID of the location bearing icon. + */ + public static final String BEARING_LAYER = "mapbox-location-bearing-layer"; + + // Icons + static final String FOREGROUND_ICON = "mapbox-location-icon"; + static final String BACKGROUND_ICON = "mapbox-location-stroke-icon"; + static final String FOREGROUND_STALE_ICON = "mapbox-location-stale-icon"; + static final String BACKGROUND_STALE_ICON = "mapbox-location-background-stale-icon"; + static final String SHADOW_ICON = "mapbox-location-shadow-icon"; + static final String BEARING_ICON = "mapbox-location-bearing-icon"; + + private LocationComponentConstants() { + // Class should not be initialized + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentNotInitializedException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentNotInitializedException.java new file mode 100644 index 000000000..82a73b973 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentNotInitializedException.java @@ -0,0 +1,8 @@ +package com.mapbox.mapboxsdk.location; + +final class LocationComponentNotInitializedException extends RuntimeException { + LocationComponentNotInitializedException() { + super("The LocationComponent has to be activated with one of the LocationComponent#activateLocationComponent" + + " overloads before any other methods are invoked."); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java new file mode 100644 index 000000000..48c89622c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -0,0 +1,1778 @@ +package com.mapbox.mapboxsdk.location; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.ColorInt; +import android.support.annotation.Dimension; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.StyleRes; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.style.layers.Layer; + +import java.util.Arrays; + +/** + * This class exposes options for the Location Component. The options can be set by defining a + * style in your apps style.xml file and passing in directly into the {@link LocationComponent} + * class. Alternatively, if properties need to be changed at runtime depending on a specific state, + * you can build an instance of this class, setting the values you desire, and then passing it into + * either the {@link LocationComponent} activation method (if it isn't initialized yet) or + * {@link LocationComponent#applyStyle(LocationComponentOptions)}. + *

+ * When the {@link #createFromAttributes(Context, int)} methods called, any attributes not found + * inside the style will revert back to using their default set values. Likewise, when building a + * new {@link LocationComponentOptions} class using the builder, any options neglecting to be set will + * reset to their default values. + *

+ * If you would like to keep your custom style changes while modifying a single attribute, you can + * get the currently used options object using {@link LocationComponent#getLocationComponentOptions()} + * and it's {@code toBuilder} method to modify a single entry while also maintaining the other + * settings. Once your modifications have been made, you'll need to pass it back into the location + * component using {@link LocationComponent#applyStyle(LocationComponentOptions)}. + */ +public class LocationComponentOptions implements Parcelable { + + /** + * Default accuracy alpha + */ + private static final float ACCURACY_ALPHA_DEFAULT = 0.15f; + + /** + * Default icon scale factor when the map is zoomed out + */ + private static final float MIN_ZOOM_ICON_SCALE_DEFAULT = 0.6f; + + /** + * Default icon scale factor when the map is zoomed in + */ + private static final float MAX_ZOOM_ICON_SCALE_DEFAULT = 1f; + + /** + * Default map padding + */ + private static final int[] PADDING_DEFAULT = {0, 0, 0, 0}; + + /** + * The default value which is used when the stale state is enabled + */ + private static final long STALE_STATE_DELAY_MS = 30_000L; + + /** + * Default animation duration multiplier + */ + private static final float TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT = 1.1f; + + private float accuracyAlpha; + private int accuracyColor; + private int backgroundDrawableStale; + @Nullable + private String backgroundStaleName; + private int foregroundDrawableStale; + @Nullable + private String foregroundStaleName; + private int gpsDrawable; + @Nullable + private String gpsName; + private int foregroundDrawable; + @Nullable + private String foregroundName; + private int backgroundDrawable; + @Nullable + private String backgroundName; + private int bearingDrawable; + @Nullable + private String bearingName; + @Nullable + private Integer bearingTintColor; + @Nullable + private Integer foregroundTintColor; + @Nullable + private Integer backgroundTintColor; + @Nullable + private Integer foregroundStaleTintColor; + @Nullable + private Integer backgroundStaleTintColor; + private float elevation; + private boolean enableStaleState; + private long staleStateTimeout; + @Nullable + private int[] padding; + private float maxZoomIconScale; + private float minZoomIconScale; + private boolean trackingGesturesManagement; + private float trackingInitialMoveThreshold; + private float trackingMultiFingerMoveThreshold; + private String layerAbove; + private String layerBelow; + private float trackingAnimationDurationMultiplier; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; + + public LocationComponentOptions( + float accuracyAlpha, + int accuracyColor, + int backgroundDrawableStale, + @Nullable String backgroundStaleName, + int foregroundDrawableStale, + @Nullable String foregroundStaleName, + int gpsDrawable, + @Nullable String gpsName, + int foregroundDrawable, + @Nullable String foregroundName, + int backgroundDrawable, + @Nullable String backgroundName, + int bearingDrawable, + @Nullable String bearingName, + @Nullable Integer bearingTintColor, + @Nullable Integer foregroundTintColor, + @Nullable Integer backgroundTintColor, + @Nullable Integer foregroundStaleTintColor, + @Nullable Integer backgroundStaleTintColor, + float elevation, + boolean enableStaleState, + long staleStateTimeout, + @Nullable int[] padding, + float maxZoomIconScale, + float minZoomIconScale, + boolean trackingGesturesManagement, + float trackingInitialMoveThreshold, + float trackingMultiFingerMoveThreshold, + String layerAbove, + String layerBelow, + float trackingAnimationDurationMultiplier, + boolean compassAnimationEnabled, + boolean accuracyAnimationEnabled) { + this.accuracyAlpha = accuracyAlpha; + this.accuracyColor = accuracyColor; + this.backgroundDrawableStale = backgroundDrawableStale; + this.backgroundStaleName = backgroundStaleName; + this.foregroundDrawableStale = foregroundDrawableStale; + this.foregroundStaleName = foregroundStaleName; + this.gpsDrawable = gpsDrawable; + this.gpsName = gpsName; + this.foregroundDrawable = foregroundDrawable; + this.foregroundName = foregroundName; + this.backgroundDrawable = backgroundDrawable; + this.backgroundName = backgroundName; + this.bearingDrawable = bearingDrawable; + this.bearingName = bearingName; + this.bearingTintColor = bearingTintColor; + this.foregroundTintColor = foregroundTintColor; + this.backgroundTintColor = backgroundTintColor; + this.foregroundStaleTintColor = foregroundStaleTintColor; + this.backgroundStaleTintColor = backgroundStaleTintColor; + this.elevation = elevation; + this.enableStaleState = enableStaleState; + this.staleStateTimeout = staleStateTimeout; + if (padding == null) { + throw new NullPointerException("Null padding"); + } + this.padding = padding; + this.maxZoomIconScale = maxZoomIconScale; + this.minZoomIconScale = minZoomIconScale; + this.trackingGesturesManagement = trackingGesturesManagement; + this.trackingInitialMoveThreshold = trackingInitialMoveThreshold; + this.trackingMultiFingerMoveThreshold = trackingMultiFingerMoveThreshold; + this.layerAbove = layerAbove; + this.layerBelow = layerBelow; + this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; + this.compassAnimationEnabled = compassAnimationEnabled; + this.accuracyAnimationEnabled = accuracyAnimationEnabled; + } + + /** + * Construct a new Location Component Options class using the attributes found within a style + * resource. It's important to note that you only need to define the attributes you plan to + * change and can safely ignore the other attributes which will be set to their default value. + * + * @param context your activity's context used for acquiring resources + * @param styleRes the style id where your custom attributes are defined + * @return a new {@link LocationComponentOptions} object with the settings you defined in your style + * resource + */ + @NonNull + public static LocationComponentOptions createFromAttributes(@NonNull Context context, + @StyleRes int styleRes) { + + TypedArray typedArray = context.obtainStyledAttributes( + styleRes, R.styleable.mapbox_LocationComponent); + + LocationComponentOptions.Builder builder = new LocationComponentOptions.Builder() + .enableStaleState(true) + .staleStateTimeout(STALE_STATE_DELAY_MS) + .maxZoomIconScale(MAX_ZOOM_ICON_SCALE_DEFAULT) + .minZoomIconScale(MIN_ZOOM_ICON_SCALE_DEFAULT) + .padding(PADDING_DEFAULT); + + builder.foregroundDrawable(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawable, -1)); + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_foregroundTintColor)) { + builder.foregroundTintColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_foregroundTintColor, -1)); + } + builder.backgroundDrawable(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawable, -1)); + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_backgroundTintColor)) { + builder.backgroundTintColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_backgroundTintColor, -1)); + } + builder.foregroundDrawableStale(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawableStale, -1)); + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_foregroundStaleTintColor)) { + builder.foregroundStaleTintColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_foregroundStaleTintColor, -1)); + } + builder.backgroundDrawableStale(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawableStale, -1)); + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_backgroundStaleTintColor)) { + builder.backgroundStaleTintColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_backgroundStaleTintColor, -1)); + } + builder.bearingDrawable(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_bearingDrawable, -1)); + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_bearingTintColor)) { + builder.bearingTintColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_bearingTintColor, -1)); + } + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_enableStaleState)) { + builder.enableStaleState(typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_enableStaleState, true)); + } + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_staleStateTimeout)) { + builder.staleStateTimeout(typedArray.getInteger( + R.styleable.mapbox_LocationComponent_mapbox_staleStateTimeout, (int) STALE_STATE_DELAY_MS)); + } + builder.gpsDrawable(typedArray.getResourceId( + R.styleable.mapbox_LocationComponent_mapbox_gpsDrawable, -1)); + float elevation = typedArray.getDimension( + R.styleable.mapbox_LocationComponent_mapbox_elevation, 0); + builder.accuracyColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_accuracyColor, -1)); + builder.accuracyAlpha(typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_accuracyAlpha, ACCURACY_ALPHA_DEFAULT)); + builder.elevation(elevation); + + builder.trackingGesturesManagement(typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_trackingGesturesManagement, false)); + builder.trackingInitialMoveThreshold(typedArray.getDimension( + R.styleable.mapbox_LocationComponent_mapbox_trackingInitialMoveThreshold, + context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingInitialMoveThreshold))); + builder.trackingMultiFingerMoveThreshold(typedArray.getDimension( + R.styleable.mapbox_LocationComponent_mapbox_trackingMultiFingerMoveThreshold, + context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold))); + + builder.padding(new int[] { + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingLeft, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingTop, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingRight, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingBottom, 0), + }); + + builder.layerAbove( + typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_above)); + + builder.layerBelow( + typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_below)); + + float minScale = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_minZoomIconScale, MIN_ZOOM_ICON_SCALE_DEFAULT); + float maxScale = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_maxZoomIconScale, MAX_ZOOM_ICON_SCALE_DEFAULT); + builder.minZoomIconScale(minScale); + builder.maxZoomIconScale(maxScale); + + float trackingAnimationDurationMultiplier = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_trackingAnimationDurationMultiplier, + TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT + ); + builder.trackingAnimationDurationMultiplier(trackingAnimationDurationMultiplier); + + builder.compassAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_compassAnimationEnabled, true + ); + + builder.accuracyAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true + ); + + typedArray.recycle(); + + return builder.build(); + } + + /** + * Takes the currently constructed {@link LocationComponentOptions} object and provides it's builder + * with all the values set matching the values in this instance. This allows you to modify a + * single attribute and then rebuild the object. + * + * @return the builder which contains the values defined in this current instance as defaults. + */ + @NonNull + public Builder toBuilder() { + return new Builder(this); + } + + /** + * Build a new instance of the {@link LocationComponentOptions} class with all the attributes set + * automatically to their defined defaults in this library. This allows you to adjust a few + * attributes while leaving the rest alone and maintaining their default behavior. + * + * @param context your activities context used to acquire the style resource + * @return the builder which contains the default values defined by the style resource + */ + @NonNull + public static Builder builder(@NonNull Context context) { + return LocationComponentOptions.createFromAttributes(context, + R.style.mapbox_LocationComponent).toBuilder(); + } + + /** + * Set the opacity of the accuracy view to a value from 0 to 1, where 0 means the accuracy view is + * completely transparent and 1 means the view is completely opaque. + * References style attribute R.styleable#LocationComponent_accuracyAlpha + * + * @return the opacity of the accuracy view + */ + public float accuracyAlpha() { + return accuracyAlpha; + } + + /** + * Solid color to use as the accuracy view color property. + * References style attribute R.styleable#LocationComponent_accuracyColor + * + * @return the color of the accuracy view + */ + @ColorInt + public int accuracyColor() { + return accuracyColor; + } + + /** + * Defines the drawable used for the stale background icon. + * References style attribute R.styleable#LocationComponent_backgroundDrawableStale + * + * @return the drawable resource ID + */ + @DrawableRes + public int backgroundDrawableStale() { + return backgroundDrawableStale; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will use this image in place of the provided or default mapbox_foregroundDrawableStale. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String backgroundStaleName() { + return backgroundStaleName; + } + + /** + * Defines the drawable used for the stale foreground icon. + * References style attribute R.styleable#LocationComponent_foregroundDrawableStale + * + * @return the drawable resource ID + */ + @DrawableRes + public int foregroundDrawableStale() { + return foregroundDrawableStale; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_foregroundDrawableStale. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String foregroundStaleName() { + return foregroundStaleName; + } + + /** + * Defines the drawable used for the navigation state icon. + * References style attribute R.styleable#LocationComponent_gpsDrawable + * + * @return the drawable resource ID + */ + @DrawableRes + public int gpsDrawable() { + return gpsDrawable; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_gpsDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String gpsName() { + return gpsName; + } + + /** + * Supply a Drawable that is to be rendered on top of all of the content in the Location LayerComponent layer stack. + * References style attribute R.styleable#LocationComponent_foregroundDrawable + * + * @return the drawable resource used for the foreground layer + */ + @DrawableRes + public int foregroundDrawable() { + return foregroundDrawable; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_foregroundDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String foregroundName() { + return foregroundName; + } + + /** + * Defines the drawable used for the background state icon. + * References style attribute R.styleable#LocationComponent_backgroundDrawable + * + * @return the drawable resource ID + */ + @DrawableRes + public int backgroundDrawable() { + return backgroundDrawable; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_backgroundDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String backgroundName() { + return backgroundName; + } + + /** + * Defines the drawable used for the bearing icon. + * References style attribute R.styleable#LocationComponent_bearingDrawable + * + * @return the drawable resource ID + */ + @DrawableRes + public int bearingDrawable() { + return bearingDrawable; + } + + /** + * String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_bearingDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @return String icon or maki-icon name + */ + @Nullable + public String bearingName() { + return bearingName; + } + + /** + * Defines the bearing icon color as an integer. + * References style attribute R.styleable#LocationComponent_bearingTintColor + * + * @return the color integer resource + */ + @ColorInt + @Nullable + public Integer bearingTintColor() { + return bearingTintColor; + } + + /** + * Defines the foreground color as an integer. + * References style attribute R.styleable#LocationComponent_foregroundTintColor + * + * @return the color integer resource + */ + @ColorInt + @Nullable + public Integer foregroundTintColor() { + return foregroundTintColor; + } + + /** + * Defines the background color as an integer. + * References style attribute R.styleable#LocationComponent_backgroundTintColor + * + * @return the color integer resource + */ + @ColorInt + @Nullable + public Integer backgroundTintColor() { + return backgroundTintColor; + } + + /** + * Defines the foreground stale color as an integer. + * References style attribute R.styleable#LocationComponent_foregroundStaleTintColor + * + * @return the color integer resource + */ + @ColorInt + @Nullable + public Integer foregroundStaleTintColor() { + return foregroundStaleTintColor; + } + + /** + * Defines the background stale color as an integer. + * References style attribute R.styleable#LocationComponent_backgroundStaleTintColor + * + * @return the color integer resource + */ + @ColorInt + @Nullable + public Integer backgroundStaleTintColor() { + return backgroundStaleTintColor; + } + + /** + * Sets the base elevation of this view, in pixels. To turn off the shadow that appears under + * the location icon, set the elevation to 0. + * References style attribute R.styleable#LocationComponent_elevation + * + * @return the elevation currently set for the location component icon + */ + @Dimension + public float elevation() { + return elevation; + } + + /** + * Enable or disable to stale state mode. This mode indicates to the user that the location being + * displayed on the map hasn't been updated in a specific amount of time. + * References style attribute R.styleable#LocationComponent_enableStaleState + * + * @return whether the stale state mode is enabled or not + */ + public boolean enableStaleState() { + return enableStaleState; + } + + /** + * Set the delay before the location icon becomes stale. The timer begins approximately when a new + * location update comes in and using this defined time, if an update hasn't occured by the end, + * the location is considered stale. + * References style attribute R.styleable#LocationComponent_staleStateDelay + * + * @return the duration in milliseconds which it should take before the location is + * considered stale + */ + public long staleStateTimeout() { + return staleStateTimeout; + } + + /** + * Sets the distance from the edges of the map view’s frame to the edges of the map + * view’s logical viewport. + *

+ *

+ * When the value of this property is equal to {0,0,0,0}, viewport + * properties such as `centerCoordinate` assume a viewport that matches the map + * view’s frame. Otherwise, those properties are inset, excluding part of the + * frame from the viewport. For instance, if the only the top edge is inset, the + * map center is effectively shifted downward. + *

+ * + * @return integer array of padding values + */ + @Nullable + @SuppressWarnings("mutable") + public int[] padding() { + return padding; + } + + /** + * The scale factor of the location icon when the map is zoomed in. + * Scaling is linear. + * + * @return icon scale factor + */ + public float maxZoomIconScale() { + return maxZoomIconScale; + } + + /** + * The scale factor of the location icon when the map is zoomed out. + * Scaling is linear. + * + * @return icon scale factor + */ + public float minZoomIconScale() { + return minZoomIconScale; + } + + /** + * Returns whether gesture threshold should be adjusted when camera is in one of the tracking modes. + * This will adjust the focal point and increase thresholds to enable camera manipulation, + * like zooming in and out, without breaking tracking. + *

+ * Note: If set to true, this can overwrite some of the gesture thresholds + * and the custom {@link com.mapbox.android.gestures.AndroidGesturesManager} that was set with + * {@link com.mapbox.mapboxsdk.maps.MapboxMap#setGesturesManager(AndroidGesturesManager, boolean, boolean)}. + * + * @return true if gestures are adjusted when in one of the camera tracking modes, false otherwise + * @see Builder#trackingInitialMoveThreshold(float) + * @see Builder#trackingMultiFingerMoveThreshold(float) + */ + public boolean trackingGesturesManagement() { + return trackingGesturesManagement; + } + + /** + * Minimum single pointer movement in pixels required to break camera tracking. + * + * @return the minimum movement + */ + public float trackingInitialMoveThreshold() { + return trackingInitialMoveThreshold; + } + + /** + * Minimum multi pointer movement in pixels required to break camera tracking (for example during scale gesture). + * + * @return the minimum movement + */ + public float trackingMultiFingerMoveThreshold() { + return trackingMultiFingerMoveThreshold; + } + + /** + * Gets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerAbove(Layer, String)}. + *

+ * The component is going to placed directly above this layer. + * + * @return layerAbove the id of the layer the component is going to placed directly above. + */ + public String layerAbove() { + return layerAbove; + } + + /** + * Gets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerBelow(Layer, String)}. + *

+ * The component is going to placed directly below this layer. + * + * @return layerBelow the id of the layer the component is going to placed directly below. + */ + public String layerBelow() { + return layerBelow; + } + + /** + * Get the tracking animation duration multiplier. + * + * @return tracking animation duration multiplier + */ + public float trackingAnimationDurationMultiplier() { + return trackingAnimationDurationMultiplier; + } + + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public boolean compassAnimationEnabled() { + return compassAnimationEnabled; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public boolean accuracyAnimationEnabled() { + return accuracyAnimationEnabled; + } + + @NonNull + @Override + public String toString() { + return "LocationComponentOptions{" + + "accuracyAlpha=" + accuracyAlpha + ", " + + "accuracyColor=" + accuracyColor + ", " + + "backgroundDrawableStale=" + backgroundDrawableStale + ", " + + "backgroundStaleName=" + backgroundStaleName + ", " + + "foregroundDrawableStale=" + foregroundDrawableStale + ", " + + "foregroundStaleName=" + foregroundStaleName + ", " + + "gpsDrawable=" + gpsDrawable + ", " + + "gpsName=" + gpsName + ", " + + "foregroundDrawable=" + foregroundDrawable + ", " + + "foregroundName=" + foregroundName + ", " + + "backgroundDrawable=" + backgroundDrawable + ", " + + "backgroundName=" + backgroundName + ", " + + "bearingDrawable=" + bearingDrawable + ", " + + "bearingName=" + bearingName + ", " + + "bearingTintColor=" + bearingTintColor + ", " + + "foregroundTintColor=" + foregroundTintColor + ", " + + "backgroundTintColor=" + backgroundTintColor + ", " + + "foregroundStaleTintColor=" + foregroundStaleTintColor + ", " + + "backgroundStaleTintColor=" + backgroundStaleTintColor + ", " + + "elevation=" + elevation + ", " + + "enableStaleState=" + enableStaleState + ", " + + "staleStateTimeout=" + staleStateTimeout + ", " + + "padding=" + Arrays.toString(padding) + ", " + + "maxZoomIconScale=" + maxZoomIconScale + ", " + + "minZoomIconScale=" + minZoomIconScale + ", " + + "trackingGesturesManagement=" + trackingGesturesManagement + ", " + + "trackingInitialMoveThreshold=" + trackingInitialMoveThreshold + ", " + + "trackingMultiFingerMoveThreshold=" + trackingMultiFingerMoveThreshold + ", " + + "layerAbove=" + layerAbove + + "layerBelow=" + layerBelow + + "trackingAnimationDurationMultiplier=" + trackingAnimationDurationMultiplier + + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LocationComponentOptions options = (LocationComponentOptions) o; + + if (Float.compare(options.accuracyAlpha, accuracyAlpha) != 0) { + return false; + } + if (accuracyColor != options.accuracyColor) { + return false; + } + if (backgroundDrawableStale != options.backgroundDrawableStale) { + return false; + } + if (foregroundDrawableStale != options.foregroundDrawableStale) { + return false; + } + if (gpsDrawable != options.gpsDrawable) { + return false; + } + if (foregroundDrawable != options.foregroundDrawable) { + return false; + } + if (backgroundDrawable != options.backgroundDrawable) { + return false; + } + if (bearingDrawable != options.bearingDrawable) { + return false; + } + if (Float.compare(options.elevation, elevation) != 0) { + return false; + } + if (enableStaleState != options.enableStaleState) { + return false; + } + if (staleStateTimeout != options.staleStateTimeout) { + return false; + } + if (Float.compare(options.maxZoomIconScale, maxZoomIconScale) != 0) { + return false; + } + if (Float.compare(options.minZoomIconScale, minZoomIconScale) != 0) { + return false; + } + if (trackingGesturesManagement != options.trackingGesturesManagement) { + return false; + } + if (Float.compare(options.trackingInitialMoveThreshold, trackingInitialMoveThreshold) != 0) { + return false; + } + if (Float.compare(options.trackingMultiFingerMoveThreshold, trackingMultiFingerMoveThreshold) != 0) { + return false; + } + if (Float.compare(options.trackingAnimationDurationMultiplier, trackingAnimationDurationMultiplier) != 0) { + return false; + } + if (compassAnimationEnabled != options.compassAnimationEnabled) { + return false; + } + if (accuracyAnimationEnabled != options.accuracyAnimationEnabled) { + return false; + } + if (backgroundStaleName != null ? !backgroundStaleName.equals(options.backgroundStaleName) : + options.backgroundStaleName != null) { + return false; + } + if (foregroundStaleName != null ? !foregroundStaleName.equals(options.foregroundStaleName) : + options.foregroundStaleName != null) { + return false; + } + if (gpsName != null ? !gpsName.equals(options.gpsName) : options.gpsName != null) { + return false; + } + if (foregroundName != null ? !foregroundName.equals(options.foregroundName) : options.foregroundName != null) { + return false; + } + if (backgroundName != null ? !backgroundName.equals(options.backgroundName) : options.backgroundName != null) { + return false; + } + if (bearingName != null ? !bearingName.equals(options.bearingName) : options.bearingName != null) { + return false; + } + if (bearingTintColor != null ? !bearingTintColor.equals(options.bearingTintColor) : + options.bearingTintColor != null) { + return false; + } + if (foregroundTintColor != null ? !foregroundTintColor.equals(options.foregroundTintColor) : + options.foregroundTintColor != null) { + return false; + } + if (backgroundTintColor != null ? !backgroundTintColor.equals(options.backgroundTintColor) : + options.backgroundTintColor != null) { + return false; + } + if (foregroundStaleTintColor != null ? !foregroundStaleTintColor.equals(options.foregroundStaleTintColor) : + options.foregroundStaleTintColor != null) { + return false; + } + if (backgroundStaleTintColor != null ? !backgroundStaleTintColor.equals(options.backgroundStaleTintColor) : + options.backgroundStaleTintColor != null) { + return false; + } + if (!Arrays.equals(padding, options.padding)) { + return false; + } + if (layerAbove != null ? !layerAbove.equals(options.layerAbove) : options.layerAbove != null) { + return false; + } + return layerBelow != null ? layerBelow.equals(options.layerBelow) : options.layerBelow == null; + } + + @Override + public int hashCode() { + int result = (accuracyAlpha != +0.0f ? Float.floatToIntBits(accuracyAlpha) : 0); + result = 31 * result + accuracyColor; + result = 31 * result + backgroundDrawableStale; + result = 31 * result + (backgroundStaleName != null ? backgroundStaleName.hashCode() : 0); + result = 31 * result + foregroundDrawableStale; + result = 31 * result + (foregroundStaleName != null ? foregroundStaleName.hashCode() : 0); + result = 31 * result + gpsDrawable; + result = 31 * result + (gpsName != null ? gpsName.hashCode() : 0); + result = 31 * result + foregroundDrawable; + result = 31 * result + (foregroundName != null ? foregroundName.hashCode() : 0); + result = 31 * result + backgroundDrawable; + result = 31 * result + (backgroundName != null ? backgroundName.hashCode() : 0); + result = 31 * result + bearingDrawable; + result = 31 * result + (bearingName != null ? bearingName.hashCode() : 0); + result = 31 * result + (bearingTintColor != null ? bearingTintColor.hashCode() : 0); + result = 31 * result + (foregroundTintColor != null ? foregroundTintColor.hashCode() : 0); + result = 31 * result + (backgroundTintColor != null ? backgroundTintColor.hashCode() : 0); + result = 31 * result + (foregroundStaleTintColor != null ? foregroundStaleTintColor.hashCode() : 0); + result = 31 * result + (backgroundStaleTintColor != null ? backgroundStaleTintColor.hashCode() : 0); + result = 31 * result + (elevation != +0.0f ? Float.floatToIntBits(elevation) : 0); + result = 31 * result + (enableStaleState ? 1 : 0); + result = 31 * result + (int) (staleStateTimeout ^ (staleStateTimeout >>> 32)); + result = 31 * result + Arrays.hashCode(padding); + result = 31 * result + (maxZoomIconScale != +0.0f ? Float.floatToIntBits(maxZoomIconScale) : 0); + result = 31 * result + (minZoomIconScale != +0.0f ? Float.floatToIntBits(minZoomIconScale) : 0); + result = 31 * result + (trackingGesturesManagement ? 1 : 0); + result = 31 * result + (trackingInitialMoveThreshold != +0.0f + ? Float.floatToIntBits(trackingInitialMoveThreshold) : 0); + result = 31 * result + (trackingMultiFingerMoveThreshold != +0.0f + ? Float.floatToIntBits(trackingMultiFingerMoveThreshold) : 0); + result = 31 * result + (layerAbove != null ? layerAbove.hashCode() : 0); + result = 31 * result + (layerBelow != null ? layerBelow.hashCode() : 0); + result = 31 * result + (trackingAnimationDurationMultiplier != +0.0f + ? Float.floatToIntBits(trackingAnimationDurationMultiplier) : 0); + result = 31 * result + (compassAnimationEnabled ? 1 : 0); + result = 31 * result + (accuracyAnimationEnabled ? 1 : 0); + return result; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public LocationComponentOptions createFromParcel(Parcel in) { + return new LocationComponentOptions( + in.readFloat(), + in.readInt(), + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readFloat(), + in.readInt() == 1, + in.readLong(), + in.createIntArray(), + in.readFloat(), + in.readFloat(), + in.readInt() == 1, + in.readFloat(), + in.readFloat(), + in.readString(), + in.readString(), + in.readFloat(), + in.readInt() == 1, + in.readInt() == 1 + ); + } + + @Override + public LocationComponentOptions[] newArray(int size) { + return new LocationComponentOptions[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeFloat(accuracyAlpha()); + dest.writeInt(accuracyColor()); + dest.writeInt(backgroundDrawableStale()); + if (backgroundStaleName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(backgroundStaleName()); + } + dest.writeInt(foregroundDrawableStale()); + if (foregroundStaleName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(foregroundStaleName()); + } + dest.writeInt(gpsDrawable()); + if (gpsName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(gpsName()); + } + dest.writeInt(foregroundDrawable()); + if (foregroundName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(foregroundName()); + } + dest.writeInt(backgroundDrawable()); + if (backgroundName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(backgroundName()); + } + dest.writeInt(bearingDrawable()); + if (bearingName() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeString(bearingName()); + } + if (bearingTintColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(bearingTintColor()); + } + if (foregroundTintColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(foregroundTintColor()); + } + if (backgroundTintColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(backgroundTintColor()); + } + if (foregroundStaleTintColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(foregroundStaleTintColor()); + } + if (backgroundStaleTintColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(backgroundStaleTintColor()); + } + dest.writeFloat(elevation()); + dest.writeInt(enableStaleState() ? 1 : 0); + dest.writeLong(staleStateTimeout()); + dest.writeIntArray(padding()); + dest.writeFloat(maxZoomIconScale()); + dest.writeFloat(minZoomIconScale()); + dest.writeInt(trackingGesturesManagement() ? 1 : 0); + dest.writeFloat(trackingInitialMoveThreshold()); + dest.writeFloat(trackingMultiFingerMoveThreshold()); + dest.writeString(layerAbove()); + dest.writeString(layerBelow()); + dest.writeFloat(trackingAnimationDurationMultiplier); + dest.writeInt(compassAnimationEnabled() ? 1 : 0); + dest.writeInt(accuracyAnimationEnabled() ? 1 : 0); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Builder class for constructing a new instance of {@link LocationComponentOptions}. + */ + public static class Builder { + + /** + * Build a new instance of this {@link LocationComponentOptions} class. + * + * @return a new instance of {@link LocationComponentOptions} + */ + @NonNull + public LocationComponentOptions build() { + LocationComponentOptions locationComponentOptions = autoBuild(); + if (locationComponentOptions.accuracyAlpha() < 0 || locationComponentOptions.accuracyAlpha() > 1) { + throw new IllegalArgumentException( + "Accuracy alpha value must be between 0.0 and 1.0."); + } + + if (locationComponentOptions.elevation() < 0f) { + throw new IllegalArgumentException("Invalid shadow size " + + locationComponentOptions.elevation() + ". Must be >= 0"); + } + + if (locationComponentOptions.layerAbove() != null && locationComponentOptions.layerBelow() != null) { + throw new IllegalArgumentException("You cannot set both layerAbove and layerBelow options." + + "Choose one or the other."); + } + + return locationComponentOptions; + } + + private Float accuracyAlpha; + private Integer accuracyColor; + private Integer backgroundDrawableStale; + @Nullable + private String backgroundStaleName; + private Integer foregroundDrawableStale; + @Nullable + private String foregroundStaleName; + private Integer gpsDrawable; + @Nullable + private String gpsName; + private Integer foregroundDrawable; + @Nullable + private String foregroundName; + private Integer backgroundDrawable; + @Nullable + private String backgroundName; + private Integer bearingDrawable; + @Nullable + private String bearingName; + @Nullable + private Integer bearingTintColor; + @Nullable + private Integer foregroundTintColor; + @Nullable + private Integer backgroundTintColor; + @Nullable + private Integer foregroundStaleTintColor; + @Nullable + private Integer backgroundStaleTintColor; + private Float elevation; + private Boolean enableStaleState; + private Long staleStateTimeout; + @Nullable + private int[] padding; + private Float maxZoomIconScale; + private Float minZoomIconScale; + private Boolean trackingGesturesManagement; + private Float trackingInitialMoveThreshold; + private Float trackingMultiFingerMoveThreshold; + private String layerAbove; + private String layerBelow; + private Float trackingAnimationDurationMultiplier; + private Boolean compassAnimationEnabled; + private Boolean accuracyAnimationEnabled; + + Builder() { + } + + private Builder(LocationComponentOptions source) { + this.accuracyAlpha = source.accuracyAlpha(); + this.accuracyColor = source.accuracyColor(); + this.backgroundDrawableStale = source.backgroundDrawableStale(); + this.backgroundStaleName = source.backgroundStaleName(); + this.foregroundDrawableStale = source.foregroundDrawableStale(); + this.foregroundStaleName = source.foregroundStaleName(); + this.gpsDrawable = source.gpsDrawable(); + this.gpsName = source.gpsName(); + this.foregroundDrawable = source.foregroundDrawable(); + this.foregroundName = source.foregroundName(); + this.backgroundDrawable = source.backgroundDrawable(); + this.backgroundName = source.backgroundName(); + this.bearingDrawable = source.bearingDrawable(); + this.bearingName = source.bearingName(); + this.bearingTintColor = source.bearingTintColor(); + this.foregroundTintColor = source.foregroundTintColor(); + this.backgroundTintColor = source.backgroundTintColor(); + this.foregroundStaleTintColor = source.foregroundStaleTintColor(); + this.backgroundStaleTintColor = source.backgroundStaleTintColor(); + this.elevation = source.elevation(); + this.enableStaleState = source.enableStaleState(); + this.staleStateTimeout = source.staleStateTimeout(); + this.padding = source.padding(); + this.maxZoomIconScale = source.maxZoomIconScale(); + this.minZoomIconScale = source.minZoomIconScale(); + this.trackingGesturesManagement = source.trackingGesturesManagement(); + this.trackingInitialMoveThreshold = source.trackingInitialMoveThreshold(); + this.trackingMultiFingerMoveThreshold = source.trackingMultiFingerMoveThreshold(); + this.layerAbove = source.layerAbove(); + this.layerBelow = source.layerBelow(); + this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); + this.compassAnimationEnabled = source.compassAnimationEnabled(); + this.accuracyAnimationEnabled = source.accuracyAnimationEnabled(); + } + + /** + * Set the opacity of the accuracy view to a value from 0 to 1, where 0 means the accuracy view + * is completely transparent and 1 means the view is completely opaque. + * References style attribute R.styleable#LocationComponent_accuracyAlpha + * + * @param accuracyAlpha the opacity of the accuracy view + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder accuracyAlpha(float accuracyAlpha) { + this.accuracyAlpha = accuracyAlpha; + return this; + } + + /** + * Solid color to use as the accuracy view color property. + * References style attribute R.styleable#LocationComponent_accuracyColor + * + * @param accuracyColor the color of the accuracy view + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder accuracyColor(int accuracyColor) { + this.accuracyColor = accuracyColor; + return this; + } + + /** + * Defines the drawable used for the stale background icon. + * References style attribute R.styleable#LocationComponent_backgroundDrawableStale + * + * @param backgroundDrawableStale the drawable resource ID + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundDrawableStale(int backgroundDrawableStale) { + this.backgroundDrawableStale = backgroundDrawableStale; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_backgroundDrawableStale. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param backgroundStaleName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundStaleName(@Nullable String backgroundStaleName) { + this.backgroundStaleName = backgroundStaleName; + return this; + } + + /** + * Defines the drawable used for the stale foreground icon. + * References style attribute R.styleable#LocationComponent_foregroundDrawableStale + * + * @param foregroundDrawableStale the drawable resource ID + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundDrawableStale(int foregroundDrawableStale) { + this.foregroundDrawableStale = foregroundDrawableStale; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_foregroundDrawableStale. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param foregroundStaleName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundStaleName(@Nullable String foregroundStaleName) { + this.foregroundStaleName = foregroundStaleName; + return this; + } + + /** + * Defines the drawable used for the navigation state icon. + * References style attribute R.styleable#LocationComponent_gpsDrawable + * + * @param gpsDrawable the drawable resource ID + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder gpsDrawable(int gpsDrawable) { + this.gpsDrawable = gpsDrawable; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_gpsDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param gpsName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder gpsName(@Nullable String gpsName) { + this.gpsName = gpsName; + return this; + } + + /** + * Supply a Drawable that is to be rendered on top of all of the content in the Location Component layer stack. + * References style attribute R.styleable#LocationComponent_foregroundDrawable + * + * @param foregroundDrawable the drawable resource used for the foreground layer + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundDrawable(int foregroundDrawable) { + this.foregroundDrawable = foregroundDrawable; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_foregroundDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param foregroundName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundName(@Nullable String foregroundName) { + this.foregroundName = foregroundName; + return this; + } + + /** + * Defines the drawable used for the background state icon. + * References style attribute R.styleable#LocationComponent_backgroundDrawable + * + * @param backgroundDrawable the drawable resource ID + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundDrawable(int backgroundDrawable) { + this.backgroundDrawable = backgroundDrawable; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_backgroundDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param backgroundName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundName(@Nullable String backgroundName) { + this.backgroundName = backgroundName; + return this; + } + + /** + * Defines the drawable used for the bearing icon. + * References style attribute R.styleable#LocationComponent_bearingDrawable + * + * @param bearingDrawable the drawable resource ID + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder bearingDrawable(int bearingDrawable) { + this.bearingDrawable = bearingDrawable; + return this; + } + + /** + * Given a String image name, identical to one used in + * the first parameter of {@link com.mapbox.mapboxsdk.maps.Style.Builder#addImage(String, Bitmap)}, the + * component, will used this image in place of the provided or default mapbox_bearingDrawable. + *

+ * A maki-icon name (example: "circle-15") may also be provided. These are images that can be loaded + * with certain styles. Note, this will fail if the provided icon name is not provided by the loaded map style. + *

+ * + * @param bearingName String icon or maki-icon name + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder bearingName(@Nullable String bearingName) { + this.bearingName = bearingName; + return this; + } + + /** + * Defines the bearing icon color as an integer. + * References style attribute R.styleable#LocationComponent_bearingTintColor + * + * @param bearingTintColor the color integer resource + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder bearingTintColor(@Nullable Integer bearingTintColor) { + this.bearingTintColor = bearingTintColor; + return this; + } + + /** + * Defines the foreground color as an integer. + * References style attribute R.styleable#LocationComponent_foregroundTintColor + * + * @param foregroundTintColor the color integer resource + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundTintColor(@Nullable Integer foregroundTintColor) { + this.foregroundTintColor = foregroundTintColor; + return this; + } + + /** + * Defines the background color as an integer. + * References style attribute R.styleable#LocationComponent_backgroundTintColor + * + * @param backgroundTintColor the color integer resource + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundTintColor(@Nullable Integer backgroundTintColor) { + this.backgroundTintColor = backgroundTintColor; + return this; + } + + /** + * Defines the foreground stale color as an integer. + * References style attribute R.styleable#LocationComponent_foregroundStaleTintColor + * + * @param foregroundStaleTintColor the color integer resource + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder foregroundStaleTintColor(@Nullable Integer foregroundStaleTintColor) { + this.foregroundStaleTintColor = foregroundStaleTintColor; + return this; + } + + /** + * Defines the background stale color as an integer. + * References style attribute R.styleable#LocationComponent_backgroundStaleTintColor + * + * @param backgroundStaleTintColor the color integer resource + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder backgroundStaleTintColor(@Nullable Integer backgroundStaleTintColor) { + this.backgroundStaleTintColor = backgroundStaleTintColor; + return this; + } + + /** + * Sets the base elevation of this view, in pixels. + * References style attribute R.styleable#LocationComponent_elevation + * + * @param elevation the elevation currently set for the location icon + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder elevation(float elevation) { + this.elevation = elevation; + return this; + } + + /** + * Enable or disable to stale state mode. This mode indicates to the user that the location + * being displayed on the map hasn't been updated in a specific amount of time. + * References style attribute R.styleable#LocationComponent_enableStaleState + * + * @param enabled whether the stale state mode is enabled or not + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder enableStaleState(boolean enabled) { + this.enableStaleState = enabled; + return this; + } + + /** + * Set the timeout before the location icon becomes stale. The timer begins approximately when a + * new location update comes in and using this defined time, if an update hasn't occurred by the + * end, the location is considered stale. + * References style attribute R.styleable#LocationComponent_staleStateTimeout + * + * @param timeout the duration in milliseconds which it should take before the location is + * considered stale + * @return this builder for chaining options together + */ + @NonNull + public LocationComponentOptions.Builder staleStateTimeout(long timeout) { + this.staleStateTimeout = timeout; + return this; + } + + /** + * Sets the distance from the edges of the map view’s frame to the edges of the map + * view’s logical viewport. + *

+ *

+ * When the value of this property is equal to {0,0,0,0}, viewport + * properties such as `centerCoordinate` assume a viewport that matches the map + * view’s frame. Otherwise, those properties are inset, excluding part of the + * frame from the viewport. For instance, if the only the top edge is inset, the + * map center is effectively shifted downward. + *

+ * + * @param padding The margins for the map in pixels (left, top, right, bottom). + * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)} + * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead. + */ + @NonNull + @Deprecated + public LocationComponentOptions.Builder padding(@Nullable int[] padding) { + if (padding == null) { + throw new NullPointerException("Null padding"); + } + this.padding = padding; + return this; + } + + /** + * Sets the scale factor of the location icon when the map is zoomed in. + * Scaling is linear and the new pixel size of the image will be the original pixel size multiplied by the argument. + *

+ * Set both this and {@link #minZoomIconScale(float)} to 1f to disable location icon scaling. + *

+ * Scaling is based on the maps minimum and maximum zoom levels in time of component's style application. + * + * @param maxZoomIconScale icon scale factor + */ + @NonNull + public LocationComponentOptions.Builder maxZoomIconScale(float maxZoomIconScale) { + this.maxZoomIconScale = maxZoomIconScale; + return this; + } + + /** + * Sets the scale factor of the location icon when the map is zoomed out. + * Scaling is linear and the new pixel size of the image will be the original pixel size multiplied by the argument. + *

+ * Set both this and {@link #maxZoomIconScale(float)} to 1f to disable location icon scaling. + *

+ * Scaling is based on the maps minimum and maximum zoom levels in time of component's style application. + * + * @param minZoomIconScale icon scale factor + */ + @NonNull + public LocationComponentOptions.Builder minZoomIconScale(float minZoomIconScale) { + this.minZoomIconScale = minZoomIconScale; + return this; + } + + /** + * Set whether gesture threshold should be adjusted when camera is in one of the tracking modes. + * This will adjust the focal point and increase thresholds to enable camera manipulation, + * like zooming in and out, without breaking tracking. + *

+ * Note: This can overwrite some of the gesture thresholds + * and the custom {@link com.mapbox.android.gestures.AndroidGesturesManager} that was set with + * {@link com.mapbox.mapboxsdk.maps.MapboxMap#setGesturesManager(AndroidGesturesManager, boolean, boolean)}. + * + * @param trackingGesturesManagement true if gestures should be adjusted when in one of the camera tracking modes, + * false otherwise + * @see Builder#trackingInitialMoveThreshold(float) + * @see Builder#trackingMultiFingerMoveThreshold(float) + */ + @NonNull + public LocationComponentOptions.Builder trackingGesturesManagement(boolean trackingGesturesManagement) { + this.trackingGesturesManagement = trackingGesturesManagement; + return this; + } + + /** + * Sets minimum single pointer movement (map pan) in pixels required to break camera tracking. + * + * @param moveThreshold the minimum movement + */ + @NonNull + public LocationComponentOptions.Builder trackingInitialMoveThreshold(float moveThreshold) { + this.trackingInitialMoveThreshold = moveThreshold; + return this; + } + + /** + * Sets minimum multi pointer movement (map pan) in pixels required to break camera tracking + * (for example during scale gesture). + * + * @param moveThreshold the minimum movement + */ + @NonNull + public LocationComponentOptions.Builder trackingMultiFingerMoveThreshold(float moveThreshold) { + this.trackingMultiFingerMoveThreshold = moveThreshold; + return this; + } + + /** + * Sets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerAbove(Layer, String)}. + *

+ * The component is going to placed directly above this layer. + * + * @param layerAbove the id of the layer the component is going to placed directly above. + */ + @NonNull + public LocationComponentOptions.Builder layerAbove(String layerAbove) { + this.layerAbove = layerAbove; + return this; + } + + /** + * Sets the id of the layer that's referenced when placing the component on the map using + * {@link com.mapbox.mapboxsdk.maps.Style#addLayerBelow(Layer, String)}. + *

+ * The component is going to placed directly below this layer. + * + * @param layerBelow the id of the layer the component is going to placed directly below. + */ + @NonNull + public LocationComponentOptions.Builder layerBelow(String layerBelow) { + this.layerBelow = layerBelow; + return this; + } + + /** + * Sets the tracking animation duration multiplier. + * + * @param trackingAnimationDurationMultiplier the tracking animation duration multiplier + */ + @NonNull + public LocationComponentOptions.Builder trackingAnimationDurationMultiplier( + float trackingAnimationDurationMultiplier) { + this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; + return this; + } + + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public LocationComponentOptions.Builder compassAnimationEnabled(Boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + return this; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; + return this; + } + + @Nullable + LocationComponentOptions autoBuild() { + String missing = ""; + if (this.accuracyAlpha == null) { + missing += " accuracyAlpha"; + } + if (this.accuracyColor == null) { + missing += " accuracyColor"; + } + if (this.backgroundDrawableStale == null) { + missing += " backgroundDrawableStale"; + } + if (this.foregroundDrawableStale == null) { + missing += " foregroundDrawableStale"; + } + if (this.gpsDrawable == null) { + missing += " gpsDrawable"; + } + if (this.foregroundDrawable == null) { + missing += " foregroundDrawable"; + } + if (this.backgroundDrawable == null) { + missing += " backgroundDrawable"; + } + if (this.bearingDrawable == null) { + missing += " bearingDrawable"; + } + if (this.elevation == null) { + missing += " elevation"; + } + if (this.enableStaleState == null) { + missing += " enableStaleState"; + } + if (this.staleStateTimeout == null) { + missing += " staleStateTimeout"; + } + if (this.padding == null) { + missing += " padding"; + } + if (this.maxZoomIconScale == null) { + missing += " maxZoomIconScale"; + } + if (this.minZoomIconScale == null) { + missing += " minZoomIconScale"; + } + if (this.trackingGesturesManagement == null) { + missing += " trackingGesturesManagement"; + } + if (this.trackingInitialMoveThreshold == null) { + missing += " trackingInitialMoveThreshold"; + } + if (this.trackingMultiFingerMoveThreshold == null) { + missing += " trackingMultiFingerMoveThreshold"; + } + if (this.trackingAnimationDurationMultiplier == null) { + missing += " trackingAnimationDurationMultiplier"; + } + if (!missing.isEmpty()) { + throw new IllegalStateException("Missing required properties:" + missing); + } + return new LocationComponentOptions( + this.accuracyAlpha, + this.accuracyColor, + this.backgroundDrawableStale, + this.backgroundStaleName, + this.foregroundDrawableStale, + this.foregroundStaleName, + this.gpsDrawable, + this.gpsName, + this.foregroundDrawable, + this.foregroundName, + this.backgroundDrawable, + this.backgroundName, + this.bearingDrawable, + this.bearingName, + this.bearingTintColor, + this.foregroundTintColor, + this.backgroundTintColor, + this.foregroundStaleTintColor, + this.backgroundStaleTintColor, + this.elevation, + this.enableStaleState, + this.staleStateTimeout, + this.padding, + this.maxZoomIconScale, + this.minZoomIconScale, + trackingGesturesManagement, + this.trackingInitialMoveThreshold, + this.trackingMultiFingerMoveThreshold, + this.layerAbove, + this.layerBelow, + this.trackingAnimationDurationMultiplier, + this.compassAnimationEnabled, + this.accuracyAnimationEnabled); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java new file mode 100644 index 000000000..f2e4d0bb4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java @@ -0,0 +1,48 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.Layer; + +class LocationComponentPositionManager { + + @NonNull + private final Style style; + + @Nullable + private String layerAbove; + + @Nullable + private String layerBelow; + + LocationComponentPositionManager(@NonNull Style style, @Nullable String layerAbove, @Nullable String layerBelow) { + this.style = style; + this.layerAbove = layerAbove; + this.layerBelow = layerBelow; + } + + /** + * Returns true whenever layer above/below configuration has changed and requires re-layout. + */ + boolean update(@Nullable String layerAbove, @Nullable String layerBelow) { + boolean requiresUpdate = + !(this.layerAbove == layerAbove || (this.layerAbove != null && this.layerAbove.equals(layerAbove))) + || !(this.layerBelow == layerBelow || (this.layerBelow != null && this.layerBelow.equals(layerBelow))); + + this.layerAbove = layerAbove; + this.layerBelow = layerBelow; + return requiresUpdate; + } + + void addLayerToMap(@NonNull Layer layer) { + if (layerAbove != null) { + style.addLayerAbove(layer, layerAbove); + } else if (layerBelow != null) { + style.addLayerBelow(layer, layerBelow); + } else { + style.addLayer(layer); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java new file mode 100644 index 000000000..54f8ee6d1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -0,0 +1,464 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_ALPHA; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_COLOR; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; +import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; +import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; +import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; +import static com.mapbox.mapboxsdk.style.layers.Property.NONE; +import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; +import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; + +final class LocationLayerController { + + @RenderMode.Mode + private int renderMode; + + private final MapboxMap mapboxMap; + private Style style; + private final LayerSourceProvider layerSourceProvider; + private final LayerBitmapProvider bitmapProvider; + private LocationComponentOptions options; + private final OnRenderModeChangedListener internalRenderModeChangedListener; + + @VisibleForTesting + final Set layerSet = new HashSet<>(); + private Feature locationFeature; + private GeoJsonSource locationSource; + + private boolean isHidden = true; + + private LocationComponentPositionManager positionManager; + + LocationLayerController(MapboxMap mapboxMap, Style style, LayerSourceProvider layerSourceProvider, + LayerFeatureProvider featureProvider, LayerBitmapProvider bitmapProvider, + @NonNull LocationComponentOptions options, + @NonNull OnRenderModeChangedListener internalRenderModeChangedListener) { + this.mapboxMap = mapboxMap; + this.style = style; + this.layerSourceProvider = layerSourceProvider; + this.bitmapProvider = bitmapProvider; + this.locationFeature = featureProvider.generateLocationFeature(locationFeature, options); + this.internalRenderModeChangedListener = internalRenderModeChangedListener; + initializeComponents(style, options); + } + + void initializeComponents(Style style, LocationComponentOptions options) { + this.style = style; + this.positionManager = new LocationComponentPositionManager(style, options.layerAbove(), options.layerBelow()); + addLocationSource(); + addLayers(); + applyStyle(options); + + if (isHidden) { + hide(); + } else { + show(); + } + } + + void applyStyle(@NonNull LocationComponentOptions options) { + if (positionManager.update(options.layerAbove(), options.layerBelow())) { + removeLayers(); + addLayers(); + if (isHidden) { + hide(); + } + } + + this.options = options; + + float elevation = options.elevation(); + // Only add icon elevation if the values greater than 0. + if (elevation > 0) { + styleShadow(options); + } + styleForeground(options); + styleBackground(options); + styleBearing(options); + styleAccuracy(options.accuracyAlpha(), options.accuracyColor()); + styleScaling(options); + determineIconsSource(options); + + if (!isHidden) { + show(); + } + } + + void setRenderMode(@RenderMode.Mode int renderMode) { + if (this.renderMode == renderMode) { + return; + } + this.renderMode = renderMode; + + styleForeground(options); + determineIconsSource(options); + if (!isHidden) { + show(); + } + internalRenderModeChangedListener.onRenderModeChanged(renderMode); + } + + int getRenderMode() { + return renderMode; + } + + // + // Layer action + // + + void show() { + isHidden = false; + boolean isStale = locationFeature.getBooleanProperty(PROPERTY_LOCATION_STALE); + switch (renderMode) { + case RenderMode.NORMAL: + setLayerVisibility(SHADOW_LAYER, true); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, !isStale); + setLayerVisibility(BEARING_LAYER, false); + break; + case RenderMode.COMPASS: + setLayerVisibility(SHADOW_LAYER, true); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, !isStale); + setLayerVisibility(BEARING_LAYER, true); + break; + case RenderMode.GPS: + setLayerVisibility(SHADOW_LAYER, false); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, false); + setLayerVisibility(BEARING_LAYER, false); + break; + default: + break; + } + } + + void hide() { + isHidden = true; + for (String layerId : layerSet) { + setLayerVisibility(layerId, false); + } + } + + void updateForegroundOffset(double tilt) { + JsonArray foregroundJsonArray = new JsonArray(); + foregroundJsonArray.add(0f); + foregroundJsonArray.add((float) (-0.05 * tilt)); + locationFeature.addProperty(PROPERTY_FOREGROUND_ICON_OFFSET, foregroundJsonArray); + + JsonArray backgroundJsonArray = new JsonArray(); + backgroundJsonArray.add(0f); + backgroundJsonArray.add((float) (0.05 * tilt)); + locationFeature.addProperty(PROPERTY_SHADOW_ICON_OFFSET, backgroundJsonArray); + + refreshSource(); + } + + void updateForegroundBearing(float bearing) { + if (renderMode != RenderMode.GPS) { + setBearingProperty(PROPERTY_GPS_BEARING, bearing); + } + } + + boolean isHidden() { + return isHidden; + } + + boolean isConsumingCompass() { + return renderMode == RenderMode.COMPASS; + } + + private void setLayerVisibility(@NonNull String layerId, boolean visible) { + Layer layer = style.getLayer(layerId); + if (layer != null) { + String targetVisibility = visible ? VISIBLE : NONE; + if (!layer.getVisibility().value.equals(targetVisibility)) { + layer.setProperties(visibility(visible ? VISIBLE : NONE)); + } + } + } + + private void addLayers() { + // positions the top-most reference layer + Layer layer = layerSourceProvider.generateLayer(BEARING_LAYER); + positionManager.addLayerToMap(layer); + layerSet.add(layer.getId()); + + // adds remaining layers while keeping the order + addSymbolLayer(FOREGROUND_LAYER, BEARING_LAYER); + addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); + addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); + addAccuracyLayer(); + } + + private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) { + Layer layer = layerSourceProvider.generateLayer(layerId); + addLayerToMap(layer, beforeLayerId); + } + + private void addAccuracyLayer() { + Layer accuracyLayer = layerSourceProvider.generateAccuracyLayer(); + addLayerToMap(accuracyLayer, BACKGROUND_LAYER); + } + + private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { + style.addLayerBelow(layer, idBelowLayer); + layerSet.add(layer.getId()); + } + + private void removeLayers() { + for (String layerId : layerSet) { + style.removeLayer(layerId); + } + layerSet.clear(); + } + + private void setBearingProperty(@NonNull String propertyId, float bearing) { + locationFeature.addNumberProperty(propertyId, bearing); + refreshSource(); + } + + private void updateAccuracyRadius(float accuracy) { + locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracy); + refreshSource(); + } + + // + // Source actions + // + + private void addLocationSource() { + locationSource = layerSourceProvider.generateSource(locationFeature); + style.addSource(locationSource); + } + + private void refreshSource() { + GeoJsonSource source = style.getSourceAs(LOCATION_SOURCE); + if (source != null) { + locationSource.setGeoJson(locationFeature); + } + } + + private void setLocationPoint(Point locationPoint) { + JsonObject properties = locationFeature.properties(); + if (properties != null) { + locationFeature = Feature.fromGeometry(locationPoint, properties); + refreshSource(); + } + } + + // + // Styling + // + + private void styleBackground(LocationComponentOptions options) { + Bitmap backgroundBitmap = bitmapProvider.generateBitmap( + options.backgroundDrawable(), options.backgroundTintColor() + ); + Bitmap backgroundStaleBitmap = bitmapProvider.generateBitmap( + options.backgroundDrawableStale(), options.backgroundStaleTintColor() + ); + style.addImage(BACKGROUND_ICON, backgroundBitmap); + style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap); + } + + private void styleShadow(@NonNull LocationComponentOptions options) { + style.addImage(SHADOW_ICON, bitmapProvider.generateShadowBitmap(options)); + } + + private void styleBearing(LocationComponentOptions options) { + Bitmap bearingBitmap = bitmapProvider.generateBitmap(options.bearingDrawable(), options.bearingTintColor()); + style.addImage(BEARING_ICON, bearingBitmap); + } + + private void styleAccuracy(float accuracyAlpha, @ColorInt int accuracyColor) { + locationFeature.addNumberProperty(PROPERTY_ACCURACY_ALPHA, accuracyAlpha); + locationFeature.addStringProperty(PROPERTY_ACCURACY_COLOR, colorToRgbaString(accuracyColor)); + refreshSource(); + } + + private void styleForeground(LocationComponentOptions options) { + Bitmap foregroundBitmap = bitmapProvider.generateBitmap( + options.foregroundDrawable(), options.foregroundTintColor() + ); + Bitmap foregroundBitmapStale = bitmapProvider.generateBitmap( + options.foregroundDrawableStale(), options.foregroundStaleTintColor() + ); + if (renderMode == RenderMode.GPS) { + foregroundBitmap = bitmapProvider.generateBitmap( + options.gpsDrawable(), options.foregroundTintColor() + ); + foregroundBitmapStale = bitmapProvider.generateBitmap( + options.gpsDrawable(), options.foregroundStaleTintColor() + ); + } + style.addImage(FOREGROUND_ICON, foregroundBitmap); + style.addImage(FOREGROUND_STALE_ICON, foregroundBitmapStale); + } + + private void styleScaling(@NonNull LocationComponentOptions options) { + for (String layerId : layerSet) { + Layer layer = style.getLayer(layerId); + if (layer instanceof SymbolLayer) { + layer.setProperties( + iconSize( + interpolate(linear(), zoom(), + stop(mapboxMap.getMinZoomLevel(), options.minZoomIconScale()), + stop(mapboxMap.getMaxZoomLevel(), options.maxZoomIconScale()) + ) + ) + ); + } + } + } + + private void determineIconsSource(LocationComponentOptions options) { + String foregroundIconString = buildIconString( + renderMode == RenderMode.GPS ? options.gpsName() : options.foregroundName(), FOREGROUND_ICON); + String foregroundStaleIconString = buildIconString(options.foregroundStaleName(), FOREGROUND_STALE_ICON); + String backgroundIconString = buildIconString(options.backgroundName(), BACKGROUND_ICON); + String backgroundStaleIconString = buildIconString(options.backgroundStaleName(), BACKGROUND_STALE_ICON); + String bearingIconString = buildIconString(options.bearingName(), BEARING_ICON); + + locationFeature.addStringProperty(PROPERTY_FOREGROUND_ICON, foregroundIconString); + locationFeature.addStringProperty(PROPERTY_BACKGROUND_ICON, backgroundIconString); + locationFeature.addStringProperty(PROPERTY_FOREGROUND_STALE_ICON, foregroundStaleIconString); + locationFeature.addStringProperty(PROPERTY_BACKGROUND_STALE_ICON, backgroundStaleIconString); + locationFeature.addStringProperty(PROPERTY_BEARING_ICON, bearingIconString); + refreshSource(); + } + + @NonNull + private String buildIconString(@Nullable String bitmapName, @NonNull String drawableName) { + if (bitmapName != null) { + return bitmapName; + } + return drawableName; + } + + void setLocationsStale(boolean isStale) { + locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, isStale); + refreshSource(); + if (renderMode != RenderMode.GPS) { + setLayerVisibility(ACCURACY_LAYER, !isStale); + } + } + + // + // Map click event + // + + boolean onMapClick(@NonNull LatLng point) { + PointF screenLoc = mapboxMap.getProjection().toScreenLocation(point); + List features = mapboxMap.queryRenderedFeatures(screenLoc, + BACKGROUND_LAYER, + FOREGROUND_LAYER, + BEARING_LAYER + ); + return !features.isEmpty(); + } + + private final MapboxAnimator.AnimationsValueChangeListener latLngValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(LatLng value) { + Point point = Point.fromLngLat(value.getLongitude(), value.getLatitude()); + setLocationPoint(point); + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener gpsBearingValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + setBearingProperty(PROPERTY_GPS_BEARING, value); + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener compassBearingValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + setBearingProperty(PROPERTY_COMPASS_BEARING, value); + } + }; + + private final MapboxAnimator.AnimationsValueChangeListener accuracyValueListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float value) { + updateAccuracyRadius(value); + } + }; + + Set getAnimationListeners() { + Set holders = new HashSet<>(); + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_LATLNG, latLngValueListener)); + + if (renderMode == RenderMode.GPS) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING, gpsBearingValueListener)); + } else if (renderMode == RenderMode.COMPASS) { + holders.add( + new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING, compassBearingValueListener)); + } + + if (renderMode == RenderMode.COMPASS || renderMode == RenderMode.NORMAL) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_ACCURACY, accuracyValueListener)); + } + + return holders; + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java new file mode 100644 index 000000000..dff7369cd --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -0,0 +1,95 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Abstract class for all of the location component animators. + * + * @param Data type that will be animated. + */ +abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener { + @Retention(RetentionPolicy.SOURCE) + @IntDef( { + ANIMATOR_LAYER_LATLNG, + ANIMATOR_CAMERA_LATLNG, + ANIMATOR_LAYER_GPS_BEARING, + ANIMATOR_LAYER_COMPASS_BEARING, + ANIMATOR_CAMERA_GPS_BEARING, + ANIMATOR_CAMERA_COMPASS_BEARING, + ANIMATOR_LAYER_ACCURACY, + ANIMATOR_ZOOM, + ANIMATOR_TILT + }) + @interface Type { + } + + static final int ANIMATOR_LAYER_LATLNG = 0; + static final int ANIMATOR_CAMERA_LATLNG = 1; + static final int ANIMATOR_LAYER_GPS_BEARING = 2; + static final int ANIMATOR_LAYER_COMPASS_BEARING = 3; + static final int ANIMATOR_CAMERA_GPS_BEARING = 4; + static final int ANIMATOR_CAMERA_COMPASS_BEARING = 5; + static final int ANIMATOR_LAYER_ACCURACY = 6; + static final int ANIMATOR_ZOOM = 7; + static final int ANIMATOR_TILT = 8; + + private final AnimationsValueChangeListener updateListener; + private final K target; + private K animatedValue; + + private final double minUpdateInterval; + private long timeElapsed; + + MapboxAnimator(@NonNull K previous, @NonNull K target, @NonNull AnimationsValueChangeListener updateListener, + int maxAnimationFps) { + minUpdateInterval = 1E9 / maxAnimationFps; + setObjectValues(previous, target); + setEvaluator(provideEvaluator()); + this.updateListener = updateListener; + this.target = target; + addUpdateListener(this); + addListener(new AnimatorListener()); + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + animatedValue = (K) animation.getAnimatedValue(); + + long currentTime = System.nanoTime(); + if ((currentTime - timeElapsed) < minUpdateInterval) { + return; + } + + postUpdates(); + timeElapsed = currentTime; + } + + private class AnimatorListener extends AnimatorListenerAdapter { + @Override + public void onAnimationEnd(Animator animation) { + postUpdates(); + } + } + + private void postUpdates() { + updateListener.onNewAnimationValue(animatedValue); + } + + K getTarget() { + return target; + } + + abstract TypeEvaluator provideEvaluator(); + + interface AnimationsValueChangeListener { + void onNewAnimationValue(K value); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java new file mode 100644 index 000000000..938f4ec74 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java @@ -0,0 +1,40 @@ +package com.mapbox.mapboxsdk.location; + +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +final class MapboxAnimatorProvider { + + private static MapboxAnimatorProvider INSTANCE; + + private MapboxAnimatorProvider() { + // private constructor + } + + public static MapboxAnimatorProvider getInstance() { + if (INSTANCE == null) { + INSTANCE = new MapboxAnimatorProvider(); + } + return INSTANCE; + } + + MapboxLatLngAnimator latLngAnimator(LatLng previous, LatLng target, + MapboxAnimator.AnimationsValueChangeListener updateListener, + int maxAnimationFps) { + return new MapboxLatLngAnimator(previous, target, updateListener, maxAnimationFps); + } + + MapboxFloatAnimator floatAnimator(Float previous, Float target, + MapboxAnimator.AnimationsValueChangeListener updateListener, + int maxAnimationFps) { + return new MapboxFloatAnimator(previous, target, updateListener, maxAnimationFps); + } + + MapboxCameraAnimatorAdapter cameraAnimator(Float previous, Float target, + MapboxAnimator.AnimationsValueChangeListener updateListener, + @Nullable MapboxMap.CancelableCallback cancelableCallback) { + return new MapboxCameraAnimatorAdapter(previous, target, updateListener, cancelableCallback); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java new file mode 100644 index 000000000..1d09f8ae7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.support.annotation.NonNull; +import android.view.animation.Interpolator; + +import java.util.List; + +class MapboxAnimatorSetProvider { + private static MapboxAnimatorSetProvider instance; + + private MapboxAnimatorSetProvider() { + // private constructor + } + + static MapboxAnimatorSetProvider getInstance() { + if (instance == null) { + instance = new MapboxAnimatorSetProvider(); + } + return instance; + } + + void startAnimation(@NonNull List animators, @NonNull Interpolator interpolator, + long duration) { + AnimatorSet locationAnimatorSet = new AnimatorSet(); + locationAnimatorSet.playTogether(animators); + locationAnimatorSet.setInterpolator(interpolator); + locationAnimatorSet.setDuration(duration); + locationAnimatorSet.start(); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java new file mode 100644 index 000000000..24bb82a2d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java @@ -0,0 +1,36 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.maps.MapboxMap; + +class MapboxCameraAnimatorAdapter extends MapboxFloatAnimator { + @Nullable + private final MapboxMap.CancelableCallback cancelableCallback; + + MapboxCameraAnimatorAdapter(Float previous, Float target, + AnimationsValueChangeListener updateListener, + @Nullable MapboxMap.CancelableCallback cancelableCallback) { + super(previous, target, updateListener, Integer.MAX_VALUE); + this.cancelableCallback = cancelableCallback; + addListener(new MapboxAnimatorListener()); + } + + private final class MapboxAnimatorListener extends AnimatorListenerAdapter { + @Override + public void onAnimationCancel(Animator animation) { + if (cancelableCallback != null) { + cancelableCallback.onCancel(); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (cancelableCallback != null) { + cancelableCallback.onFinish(); + } + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java new file mode 100644 index 000000000..d7d518bc8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java @@ -0,0 +1,17 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.FloatEvaluator; +import android.animation.TypeEvaluator; +import android.support.annotation.NonNull; + +class MapboxFloatAnimator extends MapboxAnimator { + MapboxFloatAnimator(Float previous, Float target, AnimationsValueChangeListener updateListener, int maxAnimationFps) { + super(previous, target, updateListener, maxAnimationFps); + } + + @NonNull + @Override + TypeEvaluator provideEvaluator() { + return new FloatEvaluator(); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java new file mode 100644 index 000000000..507069114 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java @@ -0,0 +1,20 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.TypeEvaluator; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.geometry.LatLng; + +class MapboxLatLngAnimator extends MapboxAnimator { + + MapboxLatLngAnimator(LatLng previous, LatLng target, AnimationsValueChangeListener updateListener, + int maxAnimationFps) { + super(previous, target, updateListener, maxAnimationFps); + } + + @NonNull + @Override + TypeEvaluator provideEvaluator() { + return new LatLngEvaluator(); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraMoveInvalidateListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraMoveInvalidateListener.java new file mode 100644 index 000000000..6594e543f --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraMoveInvalidateListener.java @@ -0,0 +1,7 @@ +package com.mapbox.mapboxsdk.location; + +interface OnCameraMoveInvalidateListener { + + void onInvalidateCameraMove(); + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraTrackingChangedListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraTrackingChangedListener.java new file mode 100644 index 000000000..1ea80d26a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnCameraTrackingChangedListener.java @@ -0,0 +1,21 @@ +package com.mapbox.mapboxsdk.location; + +import com.mapbox.mapboxsdk.location.modes.CameraMode; + +/** + * Listener that gets invoked when camera tracking state changes. + */ +public interface OnCameraTrackingChangedListener { + /** + * Invoked whenever camera tracking is broken. + * This callback gets invoked just after {@link #onCameraTrackingChanged(int)}, if needed. + */ + void onCameraTrackingDismissed(); + + /** + * Invoked on every {@link CameraMode} change. + * + * @param currentMode current active {@link CameraMode}. + */ + void onCameraTrackingChanged(@CameraMode.Mode int currentMode); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java new file mode 100644 index 000000000..824432efc --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java @@ -0,0 +1,24 @@ +package com.mapbox.mapboxsdk.location; + +import com.mapbox.mapboxsdk.location.modes.CameraMode; + +/** + * Callback for {@link CameraMode } transition state. + */ +public interface OnLocationCameraTransitionListener { + /** + * Invoked when the camera mode transition animation has been finished. + * + * @param cameraMode camera mode change that initiated the transition + */ + void onLocationCameraTransitionFinished(@CameraMode.Mode int cameraMode); + + /** + * Invoked when the camera mode transition animation has been canceled. + *

+ * The camera mode is set regardless of the cancellation of the transition animation. + * + * @param cameraMode camera mode change that initiated the transition + */ + void onLocationCameraTransitionCanceled(@CameraMode.Mode int cameraMode); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationClickListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationClickListener.java new file mode 100644 index 000000000..fdd2aeb81 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationClickListener.java @@ -0,0 +1,14 @@ +package com.mapbox.mapboxsdk.location; + +/** + * The Location Component exposes an API for listening to when the user clicks on the location + * layer icon visible on the map. When this event occurs, the {@link #onLocationComponentClick()} method + * gets invoked. + */ +public interface OnLocationClickListener { + + /** + * Called whenever user clicks on the location layer drawn on the map. + */ + void onLocationComponentClick(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationLongClickListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationLongClickListener.java new file mode 100644 index 000000000..0c34614f3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationLongClickListener.java @@ -0,0 +1,14 @@ +package com.mapbox.mapboxsdk.location; + +/** + * The Location Component exposes an API for listening to when the user long clicks on the location + * layer icon visible on the map. when this event occurs, the {@link #onLocationComponentLongClick()} method + * gets invoked. + */ +public interface OnLocationLongClickListener { + + /** + * Called whenever user long clicks on the location layer drawn on the map. + */ + void onLocationComponentLongClick(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationStaleListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationStaleListener.java new file mode 100644 index 000000000..6bbe7f34b --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationStaleListener.java @@ -0,0 +1,17 @@ +package com.mapbox.mapboxsdk.location; + +/** + * Listener that can be added as a callback when the last location update + * is considered stale. + *

+ * The time from the last location update that determines if a location update + * is stale or not is provided by {@link LocationComponentOptions#staleStateTimeout()}. + */ +public interface OnLocationStaleListener { + + /** + * Called when the stale state changes. + * @param isStale true if location is stale, false otherwise + */ + void onStaleStateChange(boolean isStale); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnRenderModeChangedListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnRenderModeChangedListener.java new file mode 100644 index 000000000..12ac220c5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnRenderModeChangedListener.java @@ -0,0 +1,16 @@ +package com.mapbox.mapboxsdk.location; + +import com.mapbox.mapboxsdk.location.modes.RenderMode; + +/** + * Listener that gets invoked when layer render mode changes. + */ +public interface OnRenderModeChangedListener { + + /** + * Invoked on every {@link RenderMode} change. + * + * @param currentMode current active {@link RenderMode}. + */ + void onRenderModeChanged(@RenderMode.Mode int currentMode); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java new file mode 100644 index 000000000..74c2e3a73 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java @@ -0,0 +1,99 @@ +package com.mapbox.mapboxsdk.location; + +import android.os.Handler; +import android.os.Message; +import android.support.annotation.NonNull; + +import java.lang.ref.WeakReference; + +/** + * Class controls the location stale state when the {@link android.location.Location} hasn't + * been updated in 'x' amount of time. {@link LocationComponentOptions#staleStateTimeout()} can be used to + * control the amount of time before the location's considered stale. + * {@link LocationComponentOptions#enableStaleState()} is available for disabling this behaviour. + */ +class StaleStateManager { + + private boolean isEnabled; + private final OnLocationStaleListener innerOnLocationStaleListeners; + @NonNull + private final StaleMessageHandler handler; + private boolean isStale = true; + private long delayTime; + + private final int staleStateMessage = 1; + + StaleStateManager(OnLocationStaleListener innerListener, LocationComponentOptions options) { + innerOnLocationStaleListeners = innerListener; + handler = new StaleMessageHandler(this); + isEnabled = options.enableStaleState(); + delayTime = options.staleStateTimeout(); + } + + void setEnabled(boolean enabled) { + if (enabled) { + setState(isStale); + } else if (isEnabled) { + onStop(); + innerOnLocationStaleListeners.onStaleStateChange(false); + } + isEnabled = enabled; + } + + boolean isStale() { + return isStale; + } + + void updateLatestLocationTime() { + setState(false); + postTheCallback(); + } + + void setDelayTime(long delayTime) { + this.delayTime = delayTime; + if (handler.hasMessages(staleStateMessage)) { + postTheCallback(); + } + } + + void onStart() { + if (!isStale) { + postTheCallback(); + } + } + + void onStop() { + handler.removeCallbacksAndMessages(null); + } + + private void postTheCallback() { + handler.removeCallbacksAndMessages(null); + handler.sendEmptyMessageDelayed(staleStateMessage, delayTime); + } + + private void setState(boolean stale) { + if (stale != isStale) { + isStale = stale; + if (isEnabled) { + innerOnLocationStaleListeners.onStaleStateChange(stale); + } + } + } + + private static class StaleMessageHandler extends Handler { + + private final WeakReference managerWeakReference; + + private StaleMessageHandler(StaleStateManager staleStateManager) { + this.managerWeakReference = new WeakReference<>(staleStateManager); + } + + @Override + public void handleMessage(Message msg) { + StaleStateManager manager = managerWeakReference.get(); + if (manager != null) { + manager.setState(true); + } + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java new file mode 100644 index 000000000..178183ca0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java @@ -0,0 +1,121 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.location.Location; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD; + +public final class Utils { + + private static final String TAG = "Mbgl-com.mapbox.mapboxsdk.location.Utils"; + + private Utils() { + // Class should not be initialized + } + + /** + * Util for finding the shortest path from the current rotated degree to the new degree. + * + * @param heading the new position of the rotation + * @param previousHeading the current position of the rotation + * @return the shortest degree of rotation possible + */ + public static float shortestRotation(float heading, float previousHeading) { + double diff = previousHeading - heading; + if (diff > 180.0f) { + heading += 360.0f; + } else if (diff < -180.0f) { + heading -= 360.f; + } + return heading; + } + + /** + * Normalizes an angle to be in the [0, 360] range. + * + * @param angle the provided angle + * @return the normalized angle + */ + public static float normalize(float angle) { + return (angle % 360 + 360) % 360; + } + + static Bitmap generateShadow(Drawable drawable, float elevation) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + try { + drawable.draw(canvas); + } catch (IllegalArgumentException ex) { + if (ex.getMessage().equals("radius must be > 0") && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + Logger.w(TAG, + "Location's shadow gradient drawable has a radius <= 0px, resetting to 1px in order to avoid crashing"); + ensureShadowGradientRadius(drawable); + return generateShadow(drawable, elevation); + } else { + throw ex; + } + } + bitmap = Bitmap.createScaledBitmap(bitmap, + toEven(width + elevation), toEven(height + elevation), false); + return bitmap; + } + + /** + * We need to ensure that the radius of any {@link GradientDrawable} is greater than 0 for API levels < 21. + * + * @see mapbox-gl-native-#15026 + */ + private static void ensureShadowGradientRadius(Drawable drawable) { + if (drawable instanceof GradientDrawable) { + ((GradientDrawable) drawable).setGradientRadius(1); + } else if (drawable instanceof LayerDrawable) { + LayerDrawable layerDrawable = (LayerDrawable) drawable; + for (int i = 0; i < layerDrawable.getNumberOfLayers(); i++) { + Drawable layers = layerDrawable.getDrawable(i); + if (layers instanceof GradientDrawable) { + ((GradientDrawable) layers).setGradientRadius(1); + } + } + } + } + + static float calculateZoomLevelRadius(@NonNull MapboxMap mapboxMap, @Nullable Location location) { + if (location == null) { + return 0; + } + double metersPerPixel = mapboxMap.getProjection().getMetersPerPixelAtLatitude(location.getLatitude()); + return (float) (location.getAccuracy() * (1 / metersPerPixel)); + } + + static boolean immediateAnimation(@NonNull Projection projection, @NonNull LatLng current, @NonNull LatLng target) { + double metersPerPixel = projection.getMetersPerPixelAtLatitude((current.getLatitude() + target.getLatitude()) / 2); + double distance = current.distanceTo(target); + return distance / metersPerPixel > INSTANT_LOCATION_TRANSITION_THRESHOLD; + } + + /** + * Casts the value to an even integer. + */ + private static int toEven(float value) { + int i = (int) (value + .5f); + if (i % 2 == 1) { + return i - 1; + } + return i; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java new file mode 100644 index 000000000..51806a33c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.location.modes; + +import android.location.Location; +import android.support.annotation.IntDef; + +import com.mapbox.mapboxsdk.location.LocationComponent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Contains the variety of camera modes which determine how the camera will track + * the user location. + */ +public final class CameraMode { + + private CameraMode() { + // Class should not be initialized + } + + /** + * Determine the camera tracking behavior in the {@link LocationComponent}. + */ + @IntDef( {NONE, NONE_COMPASS, NONE_GPS, TRACKING, TRACKING_COMPASS, TRACKING_GPS, TRACKING_GPS_NORTH}) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { + } + + /** + * No camera tracking. + */ + public static final int NONE = 0x00000008; + + /** + * Camera does not track location, but does track compass bearing. + */ + public static final int NONE_COMPASS = 0x00000010; + + /** + * Camera does not track location, but does track GPS {@link Location} bearing. + */ + public static final int NONE_GPS = 0x00000016; + + /** + * Camera tracks the user location. + */ + public static final int TRACKING = 0x00000018; + + /** + * Camera tracks the user location, with bearing + * provided by a compass. + */ + public static final int TRACKING_COMPASS = 0x00000020; + + /** + * Camera tracks the user location, with bearing + * provided by a normalized {@link Location#getBearing()}. + */ + public static final int TRACKING_GPS = 0x00000022; + + /** + * Camera tracks the user location, with bearing + * always set to north (0). + */ + public static final int TRACKING_GPS_NORTH = 0x00000024; +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java new file mode 100644 index 000000000..3d20313df --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java @@ -0,0 +1,45 @@ +package com.mapbox.mapboxsdk.location.modes; + +import android.support.annotation.IntDef; + +import com.mapbox.mapboxsdk.location.CompassEngine; +import com.mapbox.mapboxsdk.location.LocationComponent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Contains the variety of ways the user location can be rendered on the map. + */ +public final class RenderMode { + + private RenderMode() { + // Class should not be initialized + } + + /** + * One of these constants should be used with {@link LocationComponent#setRenderMode(int)}. + * Mode can be switched at anytime by calling the {@code setLocationLayerMode} method passing + * in the new mode you'd like the location layer to be in. + */ + @IntDef( {COMPASS, GPS, NORMAL}) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { + } + + /** + * Basic tracking is enabled, bearing ignored. + */ + public static final int NORMAL = 0x00000012; + + /** + * Tracking the user location with bearing considered + * from a {@link CompassEngine}. + */ + public static final int COMPASS = 0x00000004; + + /** + * Tracking the user location with bearing considered from {@link android.location.Location}. + */ + public static final int GPS = 0x00000008; +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/package-info.java new file mode 100644 index 000000000..70dd8cf27 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Location layer component camera and render modes. + */ +package com.mapbox.mapboxsdk.location.modes; \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java new file mode 100644 index 000000000..d37eddffc --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Location layer component. + */ +package com.mapbox.mapboxsdk.location; \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java new file mode 100644 index 000000000..b6c4bc872 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java @@ -0,0 +1,321 @@ +package com.mapbox.mapboxsdk.log; + +import android.support.annotation.IntDef; +import android.support.annotation.Keep; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + + +/** + * Logger for the Mapbox Maps SDK for Android + *

+ * Default implementation relies on {@link Log}. + * Alternative implementations can be set with {@link #setLoggerDefinition(LoggerDefinition)}. + *

+ */ +@Keep +public final class Logger { + + private static final LoggerDefinition DEFAULT = new LoggerDefinition() { + + @Override + public void v(String tag, String msg) { + Log.v(tag, msg); + } + + @Override + public void v(String tag, String msg, Throwable tr) { + Log.v(tag, msg, tr); + } + + @Override + public void d(String tag, String msg) { + Log.d(tag, msg); + } + + @Override + public void d(String tag, String msg, Throwable tr) { + Log.d(tag, msg, tr); + } + + @Override + public void i(String tag, String msg) { + Log.i(tag, msg); + } + + @Override + public void i(String tag, String msg, Throwable tr) { + Log.i(tag, msg, tr); + } + + @Override + public void w(String tag, String msg) { + Log.w(tag, msg); + } + + @Override + public void w(String tag, String msg, Throwable tr) { + Log.w(tag, msg, tr); + } + + @Override + public void e(String tag, String msg) { + Log.e(tag, msg); + } + + @Override + public void e(String tag, String msg, Throwable tr) { + Log.e(tag, msg, tr); + } + }; + + private static volatile LoggerDefinition logger = DEFAULT; + + @LogLevel + private static int logLevel; + + /** + * Set the verbosity of the Logger. + *

+ * This configuration can be used to have more granular control over which logs are emitted by the + * Mapbox Maps SDK for Android. + *

+ * + * @param logLevel the verbosity level + */ + public static void setVerbosity(@LogLevel int logLevel) { + Logger.logLevel = logLevel; + } + + /** + * Replace the current used logger definition. + * + * @param loggerDefinition the definition of the logger + */ + public static void setLoggerDefinition(LoggerDefinition loggerDefinition) { + logger = loggerDefinition; + } + + /** + * Send a verbose log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + public static void v(String tag, String msg) { + if (logLevel <= VERBOSE) { + logger.v(tag, msg); + } + } + + /** + * Send a verbose log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + public static void v(String tag, String msg, Throwable tr) { + if (logLevel <= VERBOSE) { + logger.v(tag, msg, tr); + } + } + + /** + * Send a debug log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + public static void d(String tag, String msg) { + if (logLevel <= DEBUG) { + logger.d(tag, msg); + } + } + + /** + * Send a debug log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + public static void d(String tag, String msg, Throwable tr) { + if (logLevel <= DEBUG) { + logger.d(tag, msg, tr); + } + } + + /** + * Send an info log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + public static void i(String tag, String msg) { + if (logLevel <= INFO) { + logger.i(tag, msg); + } + } + + /** + * Send an info log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + public static void i(String tag, String msg, Throwable tr) { + if (logLevel <= INFO) { + logger.i(tag, msg, tr); + } + } + + /** + * Send a warning log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + public static void w(String tag, String msg) { + if (logLevel <= WARN) { + logger.w(tag, msg); + } + } + + /** + * Send a warning log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + public static void w(String tag, String msg, Throwable tr) { + if (logLevel <= WARN) { + logger.w(tag, msg, tr); + } + } + + /** + * Send an error log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + public static void e(String tag, String msg) { + if (logLevel <= ERROR) { + logger.e(tag, msg); + } + } + + /** + * Send an error log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + public static void e(String tag, String msg, Throwable tr) { + if (logLevel <= ERROR) { + logger.e(tag, msg, tr); + } + } + + /** + * Send a log message based on severity. + * + * @param severity the log severity + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param message The message you would like logged. + */ + public static void log(int severity, String tag, String message) { + switch (severity) { + case Log.VERBOSE: + Logger.v(tag, message); + break; + case Log.DEBUG: + Logger.d(tag, message); + break; + case Log.INFO: + Logger.i(tag, message); + break; + case Log.WARN: + Logger.w(tag, message); + break; + case Log.ERROR: + Logger.e(tag, message); + break; + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Priority constant for the println method; use Logger.v + *

+ * This log level will print all logs. + *

+ */ + public static final int VERBOSE = Log.VERBOSE; + + /** + * Priority constant for the println method; use Logger.d. + *

+ * This log level will print all logs except verbose. + *

+ */ + public static final int DEBUG = Log.DEBUG; + + /** + * Priority constant for the println method; use Logger.i. + *

+ * This log level will print all logs except verbose and debug. + *

+ */ + public static final int INFO = Log.INFO; + + /** + * Priority constant for the println method; use Logger.w. + *

+ * This log level will print only warn and error logs. + *

+ */ + public static final int WARN = Log.WARN; + + /** + * Priority constant for the println method; use Logger.e. + *

+ * This log level will print only error logs. + *

+ */ + public static final int ERROR = Log.ERROR; + + /** + * Priority constant for the println method. + *

+ * This log level won't print any logs. + *

+ */ + public static final int NONE = 99; + + /** + * Log level indicates which logs are allowed to be emitted by the Mapbox Maps SDK for Android. + */ + @IntDef( {VERBOSE, DEBUG, INFO, WARN, ERROR, NONE}) + @Retention(RetentionPolicy.SOURCE) + public @interface LogLevel { + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java new file mode 100644 index 000000000..60b6eb000 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java @@ -0,0 +1,102 @@ +package com.mapbox.mapboxsdk.log; + +/** + * Definition of a logger for the Mapbox Maps SDK for Android. + */ +public interface LoggerDefinition { + + /** + * Send a verbose log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + void v(String tag, String msg); + + /** + * Send a verbose log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + void v(String tag, String msg, Throwable tr); + + /** + * Send a debug log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + void d(String tag, String msg); + + /** + * Send a debug log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + void d(String tag, String msg, Throwable tr); + + /** + * Send an info log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + void i(String tag, String msg); + + /** + * Send an info log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + void i(String tag, String msg, Throwable tr); + + /** + * Send a warning log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + void w(String tag, String msg); + + /** + * Send a warning log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + void w(String tag, String msg, Throwable tr); + + /** + * Send an error log message. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + */ + void e(String tag, String msg); + + /** + * Send an error log message and log the exception. + * + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param msg The message you would like logged. + * @param tr An exception to log + */ + void e(String tag, String msg, Throwable tr); +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/package-info.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/package-info.java new file mode 100644 index 000000000..3476ff7cd --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Log API classes. + */ +package com.mapbox.mapboxsdk.log; \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java new file mode 100644 index 000000000..e5bf51279 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java @@ -0,0 +1,87 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; +import android.support.v4.util.LongSparseArray; + +import com.mapbox.mapboxsdk.annotations.Annotation; + +import java.util.ArrayList; +import java.util.List; + +/** + * Encapsulates {@link Annotation}'s functionality.. + */ +class AnnotationContainer implements Annotations { + + private final NativeMap nativeMap; + private final LongSparseArray annotations; + + AnnotationContainer(NativeMap nativeMap, LongSparseArray annotations) { + this.nativeMap = nativeMap; + this.annotations = annotations; + } + + @Override + public Annotation obtainBy(long id) { + return annotations.get(id); + } + + @NonNull + @Override + public List obtainAll() { + List annotations = new ArrayList<>(); + for (int i = 0; i < this.annotations.size(); i++) { + annotations.add(this.annotations.get(this.annotations.keyAt(i))); + } + return annotations; + } + + @Override + public void removeBy(long id) { + if (nativeMap != null) { + nativeMap.removeAnnotation(id); + } + annotations.remove(id); + } + + @Override + public void removeBy(@NonNull Annotation annotation) { + long id = annotation.getId(); + removeBy(id); + } + + @Override + public void removeBy(@NonNull List annotationList) { + int count = annotationList.size(); + long[] ids = new long[count]; + for (int i = 0; i < count; i++) { + ids[i] = annotationList.get(i).getId(); + } + + removeNativeAnnotations(ids); + + for (long id : ids) { + annotations.remove(id); + } + } + + @Override + public void removeAll() { + int count = annotations.size(); + long[] ids = new long[count]; + for (int i = 0; i < count; i++) { + ids[i] = annotations.keyAt(i); + } + + removeNativeAnnotations(ids); + + annotations.clear(); + } + + private void removeNativeAnnotations(long[] ids) { + if (nativeMap != null) { + nativeMap.removeAnnotations(ids); + } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java new file mode 100644 index 000000000..8875e7164 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -0,0 +1,519 @@ +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.Marker; +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; +import com.mapbox.mapboxsdk.annotations.Polyline; +import com.mapbox.mapboxsdk.annotations.PolylineOptions; +import com.mapbox.mapboxsdk.log.Logger; + +import java.util.ArrayList; +import java.util.List; + +/** + * 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. + *

+ * Responsible for referencing {@link InfoWindowManager}. + *

+ *

+ * Exposes convenience methods to add/remove/update all subtypes of annotations found in + * com.mapbox.mapboxsdk.annotations. + *

+ */ +class AnnotationManager { + + private static final String TAG = "Mbgl-AnnotationManager"; + + private static final long NO_ANNOTATION_ID = -1; + + @NonNull + private final MapView mapView; + private final IconManager iconManager; + private final InfoWindowManager infoWindowManager = new InfoWindowManager(); + private final LongSparseArray annotationsArray; + private final List selectedMarkers = new ArrayList<>(); + + private MapboxMap mapboxMap; + @Nullable + private MapboxMap.OnMarkerClickListener onMarkerClickListener; + @Nullable + private MapboxMap.OnPolygonClickListener onPolygonClickListener; + @Nullable + private MapboxMap.OnPolylineClickListener onPolylineClickListener; + + private Annotations annotations; + private ShapeAnnotations shapeAnnotations; + private Markers markers; + private Polygons polygons; + private Polylines polylines; + + AnnotationManager(@NonNull MapView mapView, LongSparseArray annotationsArray, + IconManager iconManager, Annotations annotations, Markers markers, Polygons polygons, + Polylines polylines, ShapeAnnotations shapeAnnotations) { + this.mapView = mapView; + this.annotationsArray = annotationsArray; + this.iconManager = iconManager; + this.annotations = annotations; + this.markers = markers; + this.polygons = polygons; + this.polylines = polylines; + this.shapeAnnotations = shapeAnnotations; + } + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + @NonNull + AnnotationManager bind(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + return this; + } + + void update() { + infoWindowManager.update(); + } + + // + // Annotations + // + + Annotation getAnnotation(long id) { + return annotations.obtainBy(id); + } + + List getAnnotations() { + return annotations.obtainAll(); + } + + void removeAnnotation(long id) { + annotations.removeBy(id); + } + + void removeAnnotation(@NonNull Annotation annotation) { + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + if (selectedMarkers.contains(marker)) { + selectedMarkers.remove(marker); + } + // do icon cleanup + iconManager.iconCleanup(marker.getIcon()); + } + annotations.removeBy(annotation); + } + + void removeAnnotations(@NonNull List annotationList) { + for (Annotation annotation : annotationList) { + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + if (selectedMarkers.contains(marker)) { + selectedMarkers.remove(marker); + } + iconManager.iconCleanup(marker.getIcon()); + } + } + annotations.removeBy(annotationList); + } + + void removeAnnotations() { + Annotation annotation; + int count = annotationsArray.size(); + long[] ids = new long[count]; + selectedMarkers.clear(); + for (int i = 0; i < count; i++) { + ids[i] = annotationsArray.keyAt(i); + annotation = annotationsArray.get(ids[i]); + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + iconManager.iconCleanup(marker.getIcon()); + } + } + annotations.removeAll(); + } + + // + // Markers + // + + Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) { + return markers.addBy(markerOptions, mapboxMap); + } + + List addMarkers(@NonNull List markerOptionsList, @NonNull MapboxMap mapboxMap) { + return markers.addBy(markerOptionsList, mapboxMap); + } + + void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) { + if (!isAddedToMap(updatedMarker)) { + logNonAdded(updatedMarker); + return; + } + markers.update(updatedMarker, mapboxMap); + } + + List getMarkers() { + return markers.obtainAll(); + } + + @NonNull + List getMarkersInRect(@NonNull RectF rectangle) { + return markers.obtainAllIn(rectangle); + } + + void reloadMarkers() { + markers.reload(); + } + + // + // Polygons + // + + Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) { + return polygons.addBy(polygonOptions, mapboxMap); + } + + List addPolygons(@NonNull List polygonOptionsList, @NonNull MapboxMap mapboxMap) { + return polygons.addBy(polygonOptionsList, mapboxMap); + } + + void updatePolygon(@NonNull Polygon polygon) { + if (!isAddedToMap(polygon)) { + logNonAdded(polygon); + return; + } + polygons.update(polygon); + } + + List getPolygons() { + return polygons.obtainAll(); + } + + // + // Polylines + // + + Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) { + return polylines.addBy(polylineOptions, mapboxMap); + } + + List addPolylines(@NonNull List polylineOptionsList, @NonNull MapboxMap mapboxMap) { + return polylines.addBy(polylineOptionsList, mapboxMap); + } + + void updatePolyline(@NonNull Polyline polyline) { + if (!isAddedToMap(polyline)) { + logNonAdded(polyline); + return; + } + polylines.update(polyline); + } + + List getPolylines() { + return polylines.obtainAll(); + } + + // 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; + } + + // Need to deselect any currently selected annotation first + if (!infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows()) { + deselectMarkers(); + } + + if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) { + infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapView)); + } + + // only add to selected markers if user didn't handle the click event themselves #3176 + selectedMarkers.add(marker); + } + + void deselectMarkers() { + if (selectedMarkers.isEmpty()) { + return; + } + + for (Marker marker : selectedMarkers) { + if (marker != null) { + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); + } + } + } + + // Removes all selected markers from the list + selectedMarkers.clear(); + } + + void deselectMarker(@NonNull Marker marker) { + if (!selectedMarkers.contains(marker)) { + return; + } + + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); + } + selectedMarkers.remove(marker); + } + + @NonNull + List getSelectedMarkers() { + return selectedMarkers; + } + + @NonNull + InfoWindowManager getInfoWindowManager() { + return infoWindowManager; + } + + void adjustTopOffsetPixels(@NonNull MapboxMap mapboxMap) { + int count = annotationsArray.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotationsArray.get(i); + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.setTopOffsetPixels( + iconManager.getTopOffsetPixelsForIcon(marker.getIcon())); + } + } + + for (Marker marker : selectedMarkers) { + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); + marker.showInfoWindow(mapboxMap, mapView); + } + } + } + + private boolean isAddedToMap(@Nullable Annotation annotation) { + return annotation != null && annotation.getId() != -1 && annotationsArray.indexOfKey(annotation.getId()) > -1; + } + + private void logNonAdded(@NonNull Annotation annotation) { + Logger.w(TAG, String.format( + "Attempting to update non-added %s with value %s", annotation.getClass().getCanonicalName(), annotation) + ); + } + + // + // Click event + // + + boolean onTap(@NonNull PointF tapPoint) { + MarkerHit markerHit = getMarkerHitFromTouchArea(tapPoint); + long markerId = new MarkerHitResolver(mapboxMap).execute(markerHit); + if (markerId != NO_ANNOTATION_ID) { + if (isClickHandledForMarker(markerId)) { + return true; + } + } + + ShapeAnnotationHit shapeAnnotationHit = getShapeAnnotationHitFromTap(tapPoint); + Annotation annotation = new ShapeAnnotationHitResolver(shapeAnnotations).execute(shapeAnnotationHit); + return annotation != null && handleClickForShapeAnnotation(annotation); + } + + 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) { + Marker marker = (Marker) getAnnotation(markerId); + boolean handledDefaultClick = onClickMarker(marker); + if (!handledDefaultClick) { + toggleMarkerSelectionState(marker); + } + return true; + } + + private boolean onClickMarker(@NonNull Marker marker) { + return onMarkerClickListener != null && onMarkerClickListener.onMarkerClick(marker); + } + + private void toggleMarkerSelectionState(@NonNull Marker marker) { + if (!selectedMarkers.contains(marker)) { + selectMarker(marker); + } else { + deselectMarker(marker); + } + } + + private static class ShapeAnnotationHitResolver { + + private ShapeAnnotations shapeAnnotations; + + ShapeAnnotationHitResolver(ShapeAnnotations shapeAnnotations) { + this.shapeAnnotations = shapeAnnotations; + } + + @Nullable + public Annotation execute(@NonNull ShapeAnnotationHit shapeHit) { + Annotation foundAnnotation = null; + List annotations = shapeAnnotations.obtainAllIn(shapeHit.tapPoint); + if (annotations.size() > 0) { + foundAnnotation = annotations.get(0); + } + return foundAnnotation; + } + } + + private static class MarkerHitResolver { + + @NonNull + private final Projection projection; + private final int minimalTouchSize; + + @Nullable + private View view; + + private Bitmap bitmap; + private int bitmapWidth; + private int bitmapHeight; + private PointF markerLocation; + + @NonNull + private Rect hitRectView = new Rect(); + @NonNull + private RectF hitRectMarker = new RectF(); + @NonNull + private RectF highestSurfaceIntersection = new RectF(); + + private long closestMarkerId = NO_ANNOTATION_ID; + + MarkerHitResolver(@NonNull MapboxMap mapboxMap) { + this.projection = mapboxMap.getProjection(); + this.minimalTouchSize = (int) (32 * Mapbox.getApplicationContext().getResources().getDisplayMetrics().density); + } + + public long execute(@NonNull MarkerHit markerHit) { + resolveForMarkers(markerHit); + return closestMarkerId; + } + + private void resolveForMarkers(MarkerHit markerHit) { + for (Marker marker : markerHit.markers) { + resolveForMarker(markerHit, marker); + } + } + + private void resolveForMarker(@NonNull MarkerHit markerHit, Marker marker) { + markerLocation = projection.toScreenLocation(marker.getPosition()); + bitmap = marker.getIcon().getBitmap(); + + bitmapHeight = bitmap.getHeight(); + if (bitmapHeight < minimalTouchSize) { + bitmapHeight = minimalTouchSize; + } + + bitmapWidth = bitmap.getWidth(); + if (bitmapWidth < minimalTouchSize) { + bitmapWidth = minimalTouchSize; + } + + hitRectMarker.set(0, 0, bitmapWidth, bitmapHeight); + hitRectMarker.offsetTo( + markerLocation.x - bitmapWidth / 2, + markerLocation.y - bitmapHeight / 2 + ); + hitTestMarker(markerHit, marker, hitRectMarker); + } + + private void hitTestMarker(MarkerHit markerHit, @NonNull 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(); + } + } + } + + 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 markers; + + MarkerHit(RectF tapRect, List markers) { + this.tapRect = tapRect; + this.markers = markers; + } + + float getTapPointX() { + return tapRect.centerX(); + } + + float getTapPointY() { + return tapRect.centerY(); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java new file mode 100644 index 000000000..ae41cbb0c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java @@ -0,0 +1,25 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.annotations.Annotation; + +import java.util.List; + +/** + * Interface that defines convenient methods for working with a {@link Annotation}'s collection. + */ +interface Annotations { + Annotation obtainBy(long id); + + List obtainAll(); + + void removeBy(long id); + + void removeBy(@NonNull Annotation annotation); + + void removeBy(@NonNull List annotationList); + + void removeAll(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java new file mode 100644 index 000000000..4f523948d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -0,0 +1,208 @@ +package com.mapbox.mapboxsdk.maps; + +import android.app.Activity; +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.annotation.Nullable; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Toast; +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.attribution.Attribution; +import com.mapbox.mapboxsdk.attribution.AttributionParser; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.style.sources.Source; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * Responsible for managing attribution interactions on the map. + *

+ * When the user clicks the attribution icon, {@link AttributionDialogManager#onClick(View)} will be invoked. + * An attribution dialog will be shown to the user with contents based on the attributions found in the map style. + * Additionally an telemetry option item is shown to configure telemetry settings. + *

+ */ +public class AttributionDialogManager implements View.OnClickListener, DialogInterface.OnClickListener { + + private static final String MAP_FEEDBACK_URL = "https://apps.mapbox.com/feedback"; + private static final String MAP_FEEDBACK_LOCATION_FORMAT = MAP_FEEDBACK_URL + "/#/%f/%f/%d"; + + @NonNull + private final Context context; + @NonNull + private final MapboxMap mapboxMap; + private Set attributionSet; + private AlertDialog dialog; + + public AttributionDialogManager(@NonNull Context context, @NonNull MapboxMap mapboxMap) { + this.context = context; + this.mapboxMap = mapboxMap; + } + + // Called when someone presses the attribution icon on the map + @Override + public void onClick(@NonNull View view) { + attributionSet = new AttributionBuilder(mapboxMap, view.getContext()).build(); + + boolean isActivityFinishing = false; + if (context instanceof Activity) { + isActivityFinishing = ((Activity) context).isFinishing(); + } + + // check is hosting activity isn't finishing + // https://github.com/mapbox/mapbox-gl-native/issues/11238 + if (!isActivityFinishing) { + showAttributionDialog(getAttributionTitles()); + } + } + + protected void showAttributionDialog(@NonNull String[] attributionTitles) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.mapbox_attributionsDialogTitle); + builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, attributionTitles), this); + dialog = builder.show(); + } + + private String[] getAttributionTitles() { + List titles = new ArrayList<>(); + for (Attribution attribution : attributionSet) { + titles.add(attribution.getTitle()); + } + return titles.toArray(new String[titles.size()]); + } + + // Called when someone selects an attribution or telemetry settings from the dialog + @Override + public void onClick(DialogInterface dialog, int which) { + if (isLatestEntry(which)) { + showTelemetryDialog(); + } else { + showMapFeedbackWebPage(which); + } + } + + public void onStop() { + if (dialog != null && dialog.isShowing()) { + dialog.dismiss(); + } + } + + private boolean isLatestEntry(int attributionKeyIndex) { + return attributionKeyIndex == getAttributionTitles().length - 1; + } + + private void showTelemetryDialog() { + 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() { + @Override + public void onClick(@NonNull DialogInterface dialog, int which) { + TelemetryDefinition telemetry = Mapbox.getTelemetry(); + if (telemetry != null) { + telemetry.setUserTelemetryRequestState(true); + } + dialog.cancel(); + } + }); + builder.setNeutralButton(R.string.mapbox_attributionTelemetryNeutral, new DialogInterface.OnClickListener() { + @Override + public void onClick(@NonNull DialogInterface dialog, int which) { + showWebPage(context.getResources().getString(R.string.mapbox_telemetryLink)); + dialog.cancel(); + } + }); + builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() { + @Override + public void onClick(@NonNull DialogInterface dialog, int which) { + TelemetryDefinition telemetry = Mapbox.getTelemetry(); + if (telemetry != null) { + telemetry.setUserTelemetryRequestState(false); + } + dialog.cancel(); + } + }); + builder.show(); + } + + private void showMapFeedbackWebPage(int which) { + Attribution[] attributions = attributionSet.toArray(new Attribution[attributionSet.size()]); + String url = attributions[which].getUrl(); + if (url.contains(MAP_FEEDBACK_URL)) { + url = buildMapFeedbackMapUrl(mapboxMap.getCameraPosition()); + } + showWebPage(url); + } + + @NonNull + private String buildMapFeedbackMapUrl(@Nullable CameraPosition cameraPosition) { + // appends current location to the map feedback url if available + return cameraPosition != null ? String.format(Locale.getDefault(), + MAP_FEEDBACK_LOCATION_FORMAT, cameraPosition.target.getLongitude(), cameraPosition.target.getLatitude(), + (int) cameraPosition.zoom) : MAP_FEEDBACK_URL; + } + + private void showWebPage(@NonNull String url) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + context.startActivity(intent); + } catch (ActivityNotFoundException exception) { + // explicitly handling if the device hasn't have a web browser installed. #8899 + Toast.makeText(context, R.string.mapbox_attributionErrorNoBrowser, Toast.LENGTH_LONG).show(); + MapStrictMode.strictModeViolation(exception); + } + } + + private static class AttributionBuilder { + + private final MapboxMap mapboxMap; + @NonNull + private final WeakReference context; + + AttributionBuilder(MapboxMap mapboxMap, Context context) { + this.mapboxMap = mapboxMap; + this.context = new WeakReference<>(context); + } + + private Set build() { + Context context = this.context.get(); + if (context == null) { + return Collections.emptySet(); + } + + List attributions = new ArrayList<>(); + String attribution; + + Style style = mapboxMap.getStyle(); + if (style != null) { + for (Source source : mapboxMap.getStyle().getSources()) { + attribution = source.getAttribution(); + if (!attribution.isEmpty()) { + attributions.add(source.getAttribution()); + } + } + } + + return new AttributionParser.Options(context) + .withCopyrightSign(true) + .withImproveMap(true) + .withTelemetryAttribution(true) + .withAttributionData(attributions.toArray(new String[attributions.size()])) + .build().getAttributions(); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java new file mode 100644 index 000000000..a1fd4e7e3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java @@ -0,0 +1,204 @@ +package com.mapbox.mapboxsdk.maps; + +import android.os.Handler; +import android.os.Message; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; + +import java.lang.annotation.Retention; +import java.lang.ref.WeakReference; +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.OnCameraMoveListener; +import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Class responsible for dispatching camera change events to registered listeners. + */ +class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener, + MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener { + + private final CameraChangeHandler handler = new CameraChangeHandler(this); + + private boolean idle = true; + private int moveStartedReason; + + private final CopyOnWriteArrayList onCameraMoveStarted = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onCameraMoveCanceled = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onCameraMove = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList onCameraIdle = new CopyOnWriteArrayList<>(); + + @Retention(SOURCE) + @IntDef( {MOVE_STARTED, MOVE, MOVE_CANCELED, IDLE}) + @interface CameraChange { + } + + private static final int MOVE_STARTED = 0; + private static final int MOVE = 1; + private static final int MOVE_CANCELED = 2; + private static final int IDLE = 3; + + @Override + public void onCameraMoveStarted(final int reason) { + moveStartedReason = reason; + handler.scheduleMessage(MOVE_STARTED); + } + + @Override + public void onCameraMove() { + handler.scheduleMessage(MOVE); + } + + @Override + public void onCameraMoveCanceled() { + handler.scheduleMessage(MOVE_CANCELED); + } + + @Override + public void onCameraIdle() { + handler.scheduleMessage(IDLE); + } + + 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); + } + } + + private void executeOnCameraMoveStarted() { + if (!idle) { + return; + } + idle = false; + if (!onCameraMoveStarted.isEmpty()) { + for (OnCameraMoveStartedListener cameraMoveStartedListener : onCameraMoveStarted) { + cameraMoveStartedListener.onCameraMoveStarted(moveStartedReason); + } + } + } + + private void executeOnCameraMove() { + if (!onCameraMove.isEmpty() && !idle) { + for (OnCameraMoveListener cameraMoveListener : onCameraMove) { + cameraMoveListener.onCameraMove(); + } + } + } + + private void executeOnCameraMoveCancelled() { + if (!onCameraMoveCanceled.isEmpty() && !idle) { + for (OnCameraMoveCanceledListener cameraMoveCanceledListener : onCameraMoveCanceled) { + cameraMoveCanceledListener.onCameraMoveCanceled(); + } + } + } + + private void executeOnCameraIdle() { + if (idle) { + return; + } + idle = true; + if (!onCameraIdle.isEmpty()) { + for (OnCameraIdleListener cameraIdleListener : onCameraIdle) { + cameraIdleListener.onCameraIdle(); + } + } + } + + void onDestroy() { + handler.removeCallbacksAndMessages(null); + onCameraMoveStarted.clear(); + onCameraMoveCanceled.clear(); + onCameraMove.clear(); + onCameraIdle.clear(); + } + + private static class CameraChangeHandler extends Handler { + + private WeakReference dispatcherWeakReference; + + CameraChangeHandler(CameraChangeDispatcher dispatcher) { + super(); + this.dispatcherWeakReference = new WeakReference<>(dispatcher); + } + + @Override + public void handleMessage(@NonNull Message msg) { + CameraChangeDispatcher dispatcher = dispatcherWeakReference.get(); + if (dispatcher != null) { + switch (msg.what) { + case MOVE_STARTED: + dispatcher.executeOnCameraMoveStarted(); + break; + case MOVE: + dispatcher.executeOnCameraMove(); + break; + case MOVE_CANCELED: + dispatcher.executeOnCameraMoveCancelled(); + break; + case IDLE: + dispatcher.executeOnCameraIdle(); + break; + } + } + } + + void scheduleMessage(@CameraChange int change) { + CameraChangeDispatcher dispatcher = dispatcherWeakReference.get(); + if (dispatcher != null) { + // if there is a movement that is cancelled/stopped and restarted in the same code block + // we can safely assume that the movement will continue, no need for dispatching unnecessary callbacks sequence + if (change == MOVE_STARTED) { + boolean shouldReturn = !dispatcher.idle && (hasMessages(IDLE) || hasMessages(MOVE_CANCELED)); + removeMessages(IDLE); + removeMessages(MOVE_CANCELED); + + if (shouldReturn) { + return; + } + } + + Message message = new Message(); + message.what = change; + this.sendMessage(message); + } + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java new file mode 100644 index 000000000..aec9a848b --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.PointF; + +/** + * Interface definition of a callback that is invoked when the focal point will change. + */ +public interface FocalPointChangeListener { + + void onFocalPointChanged(PointF pointF); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java new file mode 100644 index 000000000..3a0824ad1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -0,0 +1,155 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.Bitmap; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.annotations.Marker; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Responsible for managing icons added to the Map. + *

+ * Maintains a {@link List} of {@link Icon} and is responsible for initialising default markers. + *

+ *

+ * Keep track of icons added and the resulting average icon size. This is used internally by our + * gestures detection to calculate the size of a touch target. + *

+ */ +class IconManager { + + private final Map iconMap = new HashMap<>(); + + private NativeMap nativeMap; + private int highestIconWidth; + private int highestIconHeight; + + IconManager(NativeMap nativeMap) { + this.nativeMap = nativeMap; + } + + Icon loadIconForMarker(@NonNull Marker marker) { + Icon icon = marker.getIcon(); + if (icon == null) { + // TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2 + icon = loadDefaultIconForMarker(marker); + } else { + updateHighestIconSize(icon); + } + addIcon(icon); + return icon; + } + + int getTopOffsetPixelsForIcon(@NonNull Icon icon) { + return (int) (nativeMap.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMap.getPixelRatio()); + } + + int getHighestIconWidth() { + return highestIconWidth; + } + + int getHighestIconHeight() { + return highestIconHeight; + } + + private Icon loadDefaultIconForMarker(Marker marker) { + Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker(); + Bitmap bitmap = icon.getBitmap(); + updateHighestIconSize(bitmap.getWidth(), bitmap.getHeight() / 2); + marker.setIcon(icon); + return icon; + } + + private void addIcon(@NonNull Icon icon) { + addIcon(icon, true); + } + + private void addIcon(@NonNull Icon icon, boolean addIconToMap) { + if (!iconMap.keySet().contains(icon)) { + iconMap.put(icon, 1); + if (addIconToMap) { + loadIcon(icon); + } + } else { + iconMap.put(icon, iconMap.get(icon) + 1); + } + } + + private void updateHighestIconSize(Icon icon) { + updateHighestIconSize(icon.getBitmap()); + } + + private void updateHighestIconSize(Bitmap bitmap) { + updateHighestIconSize(bitmap.getWidth(), bitmap.getHeight()); + } + + private void updateHighestIconSize(int width, int height) { + if (width > highestIconWidth) { + highestIconWidth = width; + } + + if (height > highestIconHeight) { + highestIconHeight = height; + } + } + + private void loadIcon(Icon icon) { + Bitmap bitmap = icon.getBitmap(); + nativeMap.addAnnotationIcon(icon.getId(), + bitmap.getWidth(), + bitmap.getHeight(), + icon.getScale(), + icon.toBytes()); + } + + void reloadIcons() { + for (Icon icon : iconMap.keySet()) { + loadIcon(icon); + } + } + + void ensureIconLoaded(@NonNull Marker marker, @NonNull MapboxMap mapboxMap) { + Icon icon = marker.getIcon(); + if (icon == null) { + icon = loadDefaultIconForMarker(marker); + } + addIcon(icon); + setTopOffsetPixels(marker, mapboxMap, icon); + } + + private void setTopOffsetPixels(Marker marker, @NonNull MapboxMap mapboxMap, @NonNull Icon icon) { + // this seems to be a costly operation according to the profiler so I'm trying to save some calls + Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null; + if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) { + marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon)); + } + } + + void iconCleanup(@NonNull 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) { + nativeMap.removeAnnotationIcon(icon.getId()); + iconMap.remove(icon); + } + + private void updateIconRefCounter(Icon icon, int refCounter) { + iconMap.put(icon, refCounter); + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java new file mode 100644 index 000000000..a261c2f4b --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java @@ -0,0 +1,22 @@ +package com.mapbox.mapboxsdk.maps; + +import android.support.annotation.Keep; + +@Keep +class Image { + private final byte[] buffer; + private final float pixelRatio; + private final String name; + private final int width; + private final int height; + private final boolean sdf; + + public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf) { + this.buffer = buffer; + this.pixelRatio = pixelRatio; + this.name = name; + this.width = width; + this.height = height; + this.sdf = sdf; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java new file mode 100644 index 000000000..434244a7c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java @@ -0,0 +1,96 @@ +package com.mapbox.mapboxsdk.maps; + +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.mapbox.mapboxsdk.annotations.InfoWindow; +import com.mapbox.mapboxsdk.annotations.Marker; + +import java.util.ArrayList; +import java.util.List; + +/** + * Responsible for managing InfoWindows shown on the Map. + *

+ * Maintains a {@link List} of opened {@link InfoWindow} and tracks configurations as + * allowConcurrentMultipleInfoWindows which allows to have multiple {@link InfoWindow} open at the + * same time. Responsible for managing listeners as + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowClickListener} and + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowLongClickListener}. + *

+ */ +class InfoWindowManager { + + private final List infoWindows = new ArrayList<>(); + + @Nullable + private MapboxMap.InfoWindowAdapter infoWindowAdapter; + private boolean allowConcurrentMultipleInfoWindows; + + @Nullable + private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener; + @Nullable + private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener; + @Nullable + private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener; + + void update() { + if (!infoWindows.isEmpty()) { + for (InfoWindow infoWindow : infoWindows) { + infoWindow.update(); + } + } + } + + void setInfoWindowAdapter(@Nullable MapboxMap.InfoWindowAdapter infoWindowAdapter) { + this.infoWindowAdapter = infoWindowAdapter; + } + + @Nullable + MapboxMap.InfoWindowAdapter getInfoWindowAdapter() { + return infoWindowAdapter; + } + + void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { + allowConcurrentMultipleInfoWindows = allow; + } + + boolean isAllowConcurrentMultipleOpenInfoWindows() { + return allowConcurrentMultipleInfoWindows; + } + + boolean isInfoWindowValidForMarker(@Nullable Marker marker) { + return marker != null && (!TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet())); + } + + void setOnInfoWindowClickListener(@Nullable MapboxMap.OnInfoWindowClickListener listener) { + onInfoWindowClickListener = listener; + } + + @Nullable + MapboxMap.OnInfoWindowClickListener getOnInfoWindowClickListener() { + return onInfoWindowClickListener; + } + + void setOnInfoWindowLongClickListener(@Nullable MapboxMap.OnInfoWindowLongClickListener listener) { + onInfoWindowLongClickListener = listener; + } + + @Nullable + MapboxMap.OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { + return onInfoWindowLongClickListener; + } + + void setOnInfoWindowCloseListener(@Nullable MapboxMap.OnInfoWindowCloseListener listener) { + onInfoWindowCloseListener = listener; + } + + @Nullable + MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() { + return onInfoWindowCloseListener; + } + + public void add(InfoWindow infoWindow) { + infoWindows.add(infoWindow); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java new file mode 100644 index 000000000..5932f6fbf --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java @@ -0,0 +1,395 @@ +package com.mapbox.mapboxsdk.maps; + +import com.mapbox.mapboxsdk.log.Logger; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +class MapChangeReceiver implements NativeMapView.StateCallback { + + private static final String TAG = "Mbgl-MapChangeReceiver"; + + private final List onCameraWillChangeListenerList = new CopyOnWriteArrayList<>(); + private final List onCameraIsChangingListenerList = new CopyOnWriteArrayList<>(); + private final List onCameraDidChangeListenerList = new CopyOnWriteArrayList<>(); + private final List onWillStartLoadingMapListenerList + = new CopyOnWriteArrayList<>(); + private final List onDidFinishLoadingMapListenerList + = new CopyOnWriteArrayList<>(); + private final List onDidFailLoadingMapListenerList + = new CopyOnWriteArrayList<>(); + private final List onWillStartRenderingFrameList + = new CopyOnWriteArrayList<>(); + private final List onDidFinishRenderingFrameList + = new CopyOnWriteArrayList<>(); + private final List onWillStartRenderingMapListenerList + = new CopyOnWriteArrayList<>(); + private final List onDidFinishRenderingMapListenerList + = new CopyOnWriteArrayList<>(); + private final List onDidBecomeIdleListenerList + = new CopyOnWriteArrayList<>(); + private final List onDidFinishLoadingStyleListenerList + = new CopyOnWriteArrayList<>(); + private final List onSourceChangedListenerList = new CopyOnWriteArrayList<>(); + private final List onStyleImageMissingListenerList + = new CopyOnWriteArrayList<>(); + private final List onCanRemoveUnusedStyleImageListenerList + = new CopyOnWriteArrayList<>(); + + @Override + public void onCameraWillChange(boolean animated) { + try { + if (!onCameraWillChangeListenerList.isEmpty()) { + for (MapView.OnCameraWillChangeListener onCameraWillChangeListener : onCameraWillChangeListenerList) { + onCameraWillChangeListener.onCameraWillChange(animated); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onCameraWillChange", err); + throw err; + } + } + + @Override + public void onCameraIsChanging() { + try { + if (!onCameraIsChangingListenerList.isEmpty()) { + for (MapView.OnCameraIsChangingListener onCameraIsChangingListener : onCameraIsChangingListenerList) { + onCameraIsChangingListener.onCameraIsChanging(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onCameraIsChanging", err); + throw err; + } + } + + @Override + public void onCameraDidChange(boolean animated) { + try { + if (!onCameraDidChangeListenerList.isEmpty()) { + for (MapView.OnCameraDidChangeListener onCameraDidChangeListener : onCameraDidChangeListenerList) { + onCameraDidChangeListener.onCameraDidChange(animated); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onCameraDidChange", err); + throw err; + } + } + + @Override + public void onWillStartLoadingMap() { + try { + if (!onWillStartLoadingMapListenerList.isEmpty()) { + for (MapView.OnWillStartLoadingMapListener onWillStartLoadingMapListener : onWillStartLoadingMapListenerList) { + onWillStartLoadingMapListener.onWillStartLoadingMap(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onWillStartLoadingMap", err); + throw err; + } + } + + @Override + public void onDidFinishLoadingMap() { + try { + if (!onDidFinishLoadingMapListenerList.isEmpty()) { + for (MapView.OnDidFinishLoadingMapListener onDidFinishLoadingMapListener : onDidFinishLoadingMapListenerList) { + onDidFinishLoadingMapListener.onDidFinishLoadingMap(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidFinishLoadingMap", err); + throw err; + } + } + + @Override + public void onDidFailLoadingMap(String error) { + try { + if (!onDidFailLoadingMapListenerList.isEmpty()) { + for (MapView.OnDidFailLoadingMapListener onDidFailLoadingMapListener : onDidFailLoadingMapListenerList) { + onDidFailLoadingMapListener.onDidFailLoadingMap(error); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidFailLoadingMap", err); + throw err; + } + } + + @Override + public void onWillStartRenderingFrame() { + try { + if (!onWillStartRenderingFrameList.isEmpty()) { + for (MapView.OnWillStartRenderingFrameListener listener : onWillStartRenderingFrameList) { + listener.onWillStartRenderingFrame(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onWillStartRenderingFrame", err); + throw err; + } + } + + @Override + public void onDidFinishRenderingFrame(boolean fully) { + try { + if (!onDidFinishRenderingFrameList.isEmpty()) { + for (MapView.OnDidFinishRenderingFrameListener listener : onDidFinishRenderingFrameList) { + listener.onDidFinishRenderingFrame(fully); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidFinishRenderingFrame", err); + throw err; + } + } + + @Override + public void onWillStartRenderingMap() { + try { + if (!onWillStartRenderingMapListenerList.isEmpty()) { + for (MapView.OnWillStartRenderingMapListener listener : onWillStartRenderingMapListenerList) { + listener.onWillStartRenderingMap(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onWillStartRenderingMap", err); + throw err; + } + } + + @Override + public void onDidFinishRenderingMap(boolean fully) { + try { + if (!onDidFinishRenderingMapListenerList.isEmpty()) { + for (MapView.OnDidFinishRenderingMapListener listener : onDidFinishRenderingMapListenerList) { + listener.onDidFinishRenderingMap(fully); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidFinishRenderingMap", err); + throw err; + } + } + + @Override + public void onDidBecomeIdle() { + try { + if (!onDidBecomeIdleListenerList.isEmpty()) { + for (MapView.OnDidBecomeIdleListener listener : onDidBecomeIdleListenerList) { + listener.onDidBecomeIdle(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidBecomeIdle", err); + throw err; + } + } + + @Override + public void onDidFinishLoadingStyle() { + try { + if (!onDidFinishLoadingStyleListenerList.isEmpty()) { + for (MapView.OnDidFinishLoadingStyleListener listener : onDidFinishLoadingStyleListenerList) { + listener.onDidFinishLoadingStyle(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidFinishLoadingStyle", err); + throw err; + } + } + + @Override + public void onSourceChanged(String sourceId) { + try { + if (!onSourceChangedListenerList.isEmpty()) { + for (MapView.OnSourceChangedListener onSourceChangedListener : onSourceChangedListenerList) { + onSourceChangedListener.onSourceChangedListener(sourceId); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onSourceChanged", err); + throw err; + } + } + + @Override + public void onStyleImageMissing(String imageId) { + try { + if (!onStyleImageMissingListenerList.isEmpty()) { + for (MapView.OnStyleImageMissingListener listener : onStyleImageMissingListenerList) { + listener.onStyleImageMissing(imageId); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onStyleImageMissing", err); + throw err; + } + } + + @Override + public boolean onCanRemoveUnusedStyleImage(String imageId) { + if (onCanRemoveUnusedStyleImageListenerList.isEmpty()) { + return true; + } + + try { + if (!onCanRemoveUnusedStyleImageListenerList.isEmpty()) { + boolean canRemove = true; + for (MapView.OnCanRemoveUnusedStyleImageListener listener : onCanRemoveUnusedStyleImageListenerList) { + canRemove &= listener.onCanRemoveUnusedStyleImage(imageId); + } + + return canRemove; + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onCanRemoveUnusedStyleImage", err); + throw err; + } + + return true; + } + + void addOnCameraWillChangeListener(MapView.OnCameraWillChangeListener listener) { + onCameraWillChangeListenerList.add(listener); + } + + void removeOnCameraWillChangeListener(MapView.OnCameraWillChangeListener listener) { + onCameraWillChangeListenerList.remove(listener); + } + + void addOnCameraIsChangingListener(MapView.OnCameraIsChangingListener listener) { + onCameraIsChangingListenerList.add(listener); + } + + void removeOnCameraIsChangingListener(MapView.OnCameraIsChangingListener listener) { + onCameraIsChangingListenerList.remove(listener); + } + + void addOnCameraDidChangeListener(MapView.OnCameraDidChangeListener listener) { + onCameraDidChangeListenerList.add(listener); + } + + void removeOnCameraDidChangeListener(MapView.OnCameraDidChangeListener listener) { + onCameraDidChangeListenerList.remove(listener); + } + + void addOnWillStartLoadingMapListener(MapView.OnWillStartLoadingMapListener listener) { + onWillStartLoadingMapListenerList.add(listener); + } + + void removeOnWillStartLoadingMapListener(MapView.OnWillStartLoadingMapListener listener) { + onWillStartLoadingMapListenerList.remove(listener); + } + + void addOnDidFinishLoadingMapListener(MapView.OnDidFinishLoadingMapListener listener) { + onDidFinishLoadingMapListenerList.add(listener); + } + + void removeOnDidFinishLoadingMapListener(MapView.OnDidFinishLoadingMapListener listener) { + onDidFinishLoadingMapListenerList.remove(listener); + } + + void addOnDidFailLoadingMapListener(MapView.OnDidFailLoadingMapListener listener) { + onDidFailLoadingMapListenerList.add(listener); + } + + void removeOnDidFailLoadingMapListener(MapView.OnDidFailLoadingMapListener listener) { + onDidFailLoadingMapListenerList.remove(listener); + } + + void addOnWillStartRenderingFrameListener(MapView.OnWillStartRenderingFrameListener listener) { + onWillStartRenderingFrameList.add(listener); + } + + void removeOnWillStartRenderingFrameListener(MapView.OnWillStartRenderingFrameListener listener) { + onWillStartRenderingFrameList.remove(listener); + } + + void addOnDidFinishRenderingFrameListener(MapView.OnDidFinishRenderingFrameListener listener) { + onDidFinishRenderingFrameList.add(listener); + } + + void removeOnDidFinishRenderingFrameListener(MapView.OnDidFinishRenderingFrameListener listener) { + onDidFinishRenderingFrameList.remove(listener); + } + + void addOnWillStartRenderingMapListener(MapView.OnWillStartRenderingMapListener listener) { + onWillStartRenderingMapListenerList.add(listener); + } + + void removeOnWillStartRenderingMapListener(MapView.OnWillStartRenderingMapListener listener) { + onWillStartRenderingMapListenerList.remove(listener); + } + + void addOnDidFinishRenderingMapListener(MapView.OnDidFinishRenderingMapListener listener) { + onDidFinishRenderingMapListenerList.add(listener); + } + + void removeOnDidFinishRenderingMapListener(MapView.OnDidFinishRenderingMapListener listener) { + onDidFinishRenderingMapListenerList.remove(listener); + } + + void addOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) { + onDidBecomeIdleListenerList.add(listener); + } + + void removeOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) { + onDidBecomeIdleListenerList.remove(listener); + } + + void addOnDidFinishLoadingStyleListener(MapView.OnDidFinishLoadingStyleListener listener) { + onDidFinishLoadingStyleListenerList.add(listener); + } + + void removeOnDidFinishLoadingStyleListener(MapView.OnDidFinishLoadingStyleListener listener) { + onDidFinishLoadingStyleListenerList.remove(listener); + } + + void addOnSourceChangedListener(MapView.OnSourceChangedListener listener) { + onSourceChangedListenerList.add(listener); + } + + void removeOnSourceChangedListener(MapView.OnSourceChangedListener listener) { + onSourceChangedListenerList.remove(listener); + } + + void addOnStyleImageMissingListener(MapView.OnStyleImageMissingListener listener) { + onStyleImageMissingListenerList.add(listener); + } + + void removeOnStyleImageMissingListener(MapView.OnStyleImageMissingListener listener) { + onStyleImageMissingListenerList.remove(listener); + } + + void addOnCanRemoveUnusedStyleImageListener(MapView.OnCanRemoveUnusedStyleImageListener listener) { + onCanRemoveUnusedStyleImageListenerList.add(listener); + } + + void removeOnCanRemoveUnusedStyleImageListener(MapView.OnCanRemoveUnusedStyleImageListener listener) { + onCanRemoveUnusedStyleImageListenerList.remove(listener); + } + + void clear() { + onCameraWillChangeListenerList.clear(); + onCameraIsChangingListenerList.clear(); + onCameraDidChangeListenerList.clear(); + onWillStartLoadingMapListenerList.clear(); + onDidFinishLoadingMapListenerList.clear(); + onDidFailLoadingMapListenerList.clear(); + onWillStartRenderingFrameList.clear(); + onDidFinishRenderingFrameList.clear(); + onWillStartRenderingMapListenerList.clear(); + onDidFinishRenderingMapListenerList.clear(); + onDidBecomeIdleListenerList.clear(); + onDidFinishLoadingStyleListenerList.clear(); + onSourceChangedListenerList.clear(); + onStyleImageMissingListenerList.clear(); + onCanRemoveUnusedStyleImageListenerList.clear(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java new file mode 100644 index 000000000..8af9f2c6a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java @@ -0,0 +1,241 @@ +package com.mapbox.mapboxsdk.maps; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mapbox.mapboxsdk.utils.MapFragmentUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment wrapper around a map view. + *

+ * A Map component in an app. This fragment is the simplest way to place a map in an application. + * It's a wrapper around a view of a map to automatically handle the necessary life cycle needs. + * Being a fragment, this component can be added to an activity's layout or can dynamically be added + * using a FragmentManager. + *

+ *

+ * To get a reference to the MapView, use {@link #getMapAsync(OnMapReadyCallback)}} + *

+ * + * @see #getMapAsync(OnMapReadyCallback) + */ +public final class MapFragment extends Fragment implements OnMapReadyCallback { + + private final List mapReadyCallbackList = new ArrayList<>(); + private OnMapViewReadyCallback mapViewReadyCallback; + private MapboxMap mapboxMap; + private MapView map; + + /** + * Creates a default MapFragment instance + * + * @return MapFragment instantiated + */ + public static MapFragment newInstance() { + return new MapFragment(); + } + + /** + * Creates a MapFragment instance + * + * @param mapboxMapOptions The configuration options to be used. + * @return MapFragment instantiated. + */ + @NonNull + public static MapFragment newInstance(@Nullable MapboxMapOptions mapboxMapOptions) { + MapFragment mapFragment = new MapFragment(); + mapFragment.setArguments(MapFragmentUtils.createFragmentArgs(mapboxMapOptions)); + return mapFragment; + } + + /** + * Called when this fragment is inflated, parses XML tag attributes. + * + * @param context The context inflating this fragment. + * @param attrs The XML tag attributes. + * @param savedInstanceState The saved instance state for the map fragment. + */ + @Override + public void onInflate(@NonNull Context context, AttributeSet attrs, Bundle savedInstanceState) { + super.onInflate(context, attrs, savedInstanceState); + setArguments(MapFragmentUtils.createFragmentArgs(MapboxMapOptions.createFromAttributes(context, attrs))); + } + + /** + * Called when the context attaches to this fragment. + * + * @param context the context attaching + */ + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnMapViewReadyCallback) { + mapViewReadyCallback = (OnMapViewReadyCallback) context; + } + } + + /** + * Creates the fragment view hierarchy. + * + * @param inflater Inflater used to inflate content. + * @param container The parent layout for the map fragment. + * @param savedInstanceState The saved instance state for the map fragment. + * @return The view created + */ + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + Context context = inflater.getContext(); + map = new MapView(context, MapFragmentUtils.resolveArgs(context, getArguments())); + return map; + } + + /** + * Called when the fragment view hierarchy is created. + * + * @param view The content view of the fragment + * @param savedInstanceState The saved instance state of the fragment + */ + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + map.onCreate(savedInstanceState); + map.getMapAsync(this); + + // notify listeners about mapview creation + if (mapViewReadyCallback != null) { + mapViewReadyCallback.onMapViewReady(map); + } + } + + /** + * Called when the style of the map has successfully loaded. + * + * @param mapboxMap The public api controller of the map + */ + @Override + public void onMapReady(@NonNull MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + for (OnMapReadyCallback onMapReadyCallback : mapReadyCallbackList) { + onMapReadyCallback.onMapReady(mapboxMap); + } + } + + /** + * Called when the fragment is visible for the users. + */ + @Override + public void onStart() { + super.onStart(); + map.onStart(); + } + + /** + * Called when the fragment is ready to be interacted with. + */ + @Override + public void onResume() { + super.onResume(); + map.onResume(); + } + + /** + * Called when the fragment is pausing. + */ + @Override + public void onPause() { + super.onPause(); + map.onPause(); + } + + /** + * Called when the fragment state needs to be saved. + * + * @param outState The saved state + */ + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + if (map != null && !map.isDestroyed()) { + map.onSaveInstanceState(outState); + } + } + + /** + * Called when the fragment is no longer visible for the user. + */ + @Override + public void onStop() { + super.onStop(); + map.onStop(); + } + + /** + * Called when the fragment receives onLowMemory call from the hosting Activity. + */ + @Override + public void onLowMemory() { + super.onLowMemory(); + if (map != null && !map.isDestroyed()) { + map.onLowMemory(); + } + } + + /** + * Called when the fragment is view hiearchy is being destroyed. + */ + @Override + public void onDestroyView() { + super.onDestroyView(); + map.onDestroy(); + } + + /** + * Called when the fragment is destroyed. + */ + @Override + public void onDestroy() { + super.onDestroy(); + mapReadyCallbackList.clear(); + } + + /** + * Sets a callback object which will be triggered when the MapboxMap instance is ready to be used. + * + * @param onMapReadyCallback The callback to be invoked. + */ + public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) { + if (mapboxMap == null) { + mapReadyCallbackList.add(onMapReadyCallback); + } else { + onMapReadyCallback.onMapReady(mapboxMap); + } + } + + /** + * Callback to be invoked when the map fragment has inflated its MapView. + *

+ * To use this interface the context hosting the fragment must implement this interface. + * That instance will be set as part of Fragment#onAttach(Context context). + *

+ */ + public interface OnMapViewReadyCallback { + + /** + * Called when the map has been created. + * + * @param mapView The created mapview + */ + void onMapViewReady(MapView mapView); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java new file mode 100644 index 000000000..90e3934f7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -0,0 +1,1140 @@ +package com.mapbox.mapboxsdk.maps; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PointF; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.animation.DecelerateInterpolator; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.MultiFingerTapGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.utils.MathUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAXIMUM_ANGULAR_VELOCITY; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.QUICK_ZOOM_MAX_ZOOM_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.ROTATE_VELOCITY_RATIO_THRESHOLD; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_RATIO_THRESHOLD; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.ZOOM_RATE; +import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE; +import static com.mapbox.mapboxsdk.utils.MathUtils.normalize; + +/** + * Manages gestures events on a MapView. + */ +final class MapGestureDetector { + + private final Transform transform; + private final Projection projection; + private final UiSettings uiSettings; + private final AnnotationManager annotationManager; + private final CameraChangeDispatcher cameraChangeDispatcher; + + // new map touch API + private final CopyOnWriteArrayList onMapClickListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onMapLongClickListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onFlingListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onMoveListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onRotateListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onScaleListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList onShoveListenerList + = new CopyOnWriteArrayList<>(); + + /** + * User-set focal point. + */ + @Nullable + private PointF constantFocalPoint; + + @NonNull + private PointF doubleTapFocalPoint = new PointF(); + + private AndroidGesturesManager gesturesManager; + + private Animator scaleAnimator; + private Animator rotateAnimator; + private final List scheduledAnimators = new ArrayList<>(); + + /** + * Cancels scheduled velocity animations if user doesn't lift fingers within + * {@link MapboxConstants#SCHEDULED_ANIMATION_TIMEOUT} + */ + @NonNull + private Handler animationsTimeoutHandler = new Handler(); + + private boolean doubleTapRegistered; + + MapGestureDetector(@Nullable Context context, Transform transform, Projection projection, UiSettings uiSettings, + AnnotationManager annotationManager, CameraChangeDispatcher cameraChangeDispatcher) { + this.annotationManager = annotationManager; + this.transform = transform; + this.projection = projection; + this.uiSettings = uiSettings; + this.cameraChangeDispatcher = cameraChangeDispatcher; + + // Checking for context != null for testing purposes + if (context != null) { + // Initialize gestures manager + AndroidGesturesManager androidGesturesManager = new AndroidGesturesManager(context); + initializeGesturesManager(androidGesturesManager, true); + + // Initialize gesture listeners + initializeGestureListeners(context, true); + } + } + + private void initializeGestureListeners(@NonNull Context context, boolean attachDefaultListeners) { + if (attachDefaultListeners) { + StandardGestureListener standardGestureListener = new StandardGestureListener( + context.getResources().getDimension( + com.mapbox.android.gestures.R.dimen.mapbox_defaultScaleSpanSinceStartThreshold)); + MoveGestureListener moveGestureListener = new MoveGestureListener(); + ScaleGestureListener scaleGestureListener = new ScaleGestureListener( + context.getResources().getDimension(R.dimen.mapbox_density_constant), + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_speed), + context.getResources().getDimension(R.dimen.mapbox_minimum_angled_scale_speed), + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_velocity) + ); + RotateGestureListener rotateGestureListener = new RotateGestureListener( + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_span_when_rotating), + context.getResources().getDimension(R.dimen.mapbox_density_constant), + context.getResources().getDimension(R.dimen.mapbox_angular_velocity_multiplier), + context.getResources().getDimension(R.dimen.mapbox_minimum_angular_velocity), + context.getResources().getDimension( + com.mapbox.android.gestures.R.dimen.mapbox_defaultScaleSpanSinceStartThreshold)); + ShoveGestureListener shoveGestureListener = new ShoveGestureListener(); + TapGestureListener tapGestureListener = new TapGestureListener(); + + gesturesManager.setStandardGestureListener(standardGestureListener); + gesturesManager.setMoveGestureListener(moveGestureListener); + gesturesManager.setStandardScaleGestureListener(scaleGestureListener); + gesturesManager.setRotateGestureListener(rotateGestureListener); + gesturesManager.setShoveGestureListener(shoveGestureListener); + gesturesManager.setMultiFingerTapGestureListener(tapGestureListener); + } + } + + private void initializeGesturesManager(@NonNull AndroidGesturesManager androidGesturesManager, + boolean setDefaultMutuallyExclusives) { + if (setDefaultMutuallyExclusives) { + Set shoveScaleSet = new HashSet<>(); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + + Set shoveRotateSet = new HashSet<>(); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_ROTATE); + + Set ScaleLongPressSet = new HashSet<>(); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_LONG_PRESS); + + androidGesturesManager.setMutuallyExclusiveGestures(shoveScaleSet, shoveRotateSet, ScaleLongPressSet); + } + + gesturesManager = androidGesturesManager; + gesturesManager.getRotateGestureDetector().setAngleThreshold(3f); + } + + /** + * Set the gesture focal point. + *

+ * This is the center point used for calculate transformations from gestures, value is + * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. + *

+ * + * @param focalPoint the center point for gestures + */ + void setFocalPoint(@Nullable PointF focalPoint) { + if (focalPoint == null) { + // resetting focal point, + if (uiSettings.getFocalPoint() != null) { + // using user provided one to reset + focalPoint = uiSettings.getFocalPoint(); + } + } + this.constantFocalPoint = focalPoint; + } + + /** + * Called when user touches the screen, all positions are absolute. + *

+ * Forwards event to the related gesture detectors. + *

+ * + * @param motionEvent the MotionEvent + * @return True if touch event is handled + */ + boolean onTouchEvent(@Nullable MotionEvent motionEvent) { + // Framework can return null motion events in edge cases #9432 + if (motionEvent == null) { + return false; + } + + // Check and ignore non touch or left clicks + if ((motionEvent.getButtonState() != 0) && (motionEvent.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + return false; + } + + if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) { + cancelAnimators(); + transform.setGestureInProgress(true); + } + + boolean result = gesturesManager.onTouchEvent(motionEvent); + + switch (motionEvent.getActionMasked()) { + case MotionEvent.ACTION_POINTER_DOWN: + doubleTapFinished(); + break; + + case MotionEvent.ACTION_UP: + doubleTapFinished(); + transform.setGestureInProgress(false); + + if (!scheduledAnimators.isEmpty()) { + // Start all awaiting velocity animations + animationsTimeoutHandler.removeCallbacksAndMessages(null); + for (Animator animator : scheduledAnimators) { + animator.start(); + } + scheduledAnimators.clear(); + } + break; + + case MotionEvent.ACTION_CANCEL: + scheduledAnimators.clear(); + transform.setGestureInProgress(false); + doubleTapFinished(); + break; + } + + return result; + } + + void cancelAnimators() { + animationsTimeoutHandler.removeCallbacksAndMessages(null); + scheduledAnimators.clear(); + + cancelAnimator(scaleAnimator); + cancelAnimator(rotateAnimator); + + dispatchCameraIdle(); + } + + private void cancelAnimator(@Nullable Animator animator) { + if (animator != null && animator.isStarted()) { + animator.cancel(); + } + } + + /** + * Posted on main thread with {@link #animationsTimeoutHandler}. Cancels all scheduled animators if needed. + */ + @NonNull + private final Runnable cancelAnimatorsRunnable = new Runnable() { + @Override + public void run() { + cancelAnimators(); + } + }; + + /** + * Schedules a velocity animator to be executed when user lifts fingers, + * unless canceled by the {@link #cancelAnimatorsRunnable}. + * + * @param animator animator ot be scheduled + */ + private void scheduleAnimator(Animator animator) { + scheduledAnimators.add(animator); + animationsTimeoutHandler.removeCallbacksAndMessages(null); + animationsTimeoutHandler.postDelayed(cancelAnimatorsRunnable, MapboxConstants.SCHEDULED_ANIMATION_TIMEOUT); + } + + /** + * Called for events that don't fit the other handlers. + *

+ * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. + *

+ * + * @param event The MotionEvent occurred + * @return True is the event is handled + */ + boolean onGenericMotionEvent(MotionEvent event) { + // Mouse events + // if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { + // Choose the action + switch (event.getActionMasked()) { + // Mouse scrolls + case MotionEvent.ACTION_SCROLL: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Get the vertical scroll amount, one click = 1 + float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + + // Scale the map by the appropriate power of two factor + transform.zoomBy(scrollDist, new PointF(event.getX(), event.getY())); + + return true; + + default: + // We are not interested in this event + return false; + } + } + + // We are not interested in this event + return false; + } + + private final class StandardGestureListener extends StandardGestureDetector.SimpleStandardOnGestureListener { + private final float doubleTapMovementThreshold; + + StandardGestureListener(float doubleTapMovementThreshold) { + this.doubleTapMovementThreshold = doubleTapMovementThreshold; + } + + @Override + public boolean onDown(MotionEvent motionEvent) { + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent motionEvent) { + transform.cancelTransitions(); + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent motionEvent) { + PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + boolean tapHandled = annotationManager.onTap(tapPoint); + + if (!tapHandled) { + if (uiSettings.isDeselectMarkersOnTap()) { + // deselect any selected marker + annotationManager.deselectMarkers(); + } + + notifyOnMapClickListeners(tapPoint); + } + + return true; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent motionEvent) { + int action = motionEvent.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + doubleTapFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + doubleTapStarted(); + } + + if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { + float diffX = Math.abs(motionEvent.getX() - doubleTapFocalPoint.x); + float diffY = Math.abs(motionEvent.getY() - doubleTapFocalPoint.y); + if (diffX > doubleTapMovementThreshold || diffY > doubleTapMovementThreshold) { + // Ignore double-tap event because we've started the quick-zoom. See #14013. + return false; + } + + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled()) { + return false; + } + + // Single finger double tap + if (constantFocalPoint != null) { + // User provided focal point + doubleTapFocalPoint = constantFocalPoint; + } + + zoomInAnimated(doubleTapFocalPoint, false); + + return true; + } + + return super.onDoubleTapEvent(motionEvent); + } + + @Override + public void onLongPress(MotionEvent motionEvent) { + PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + notifyOnMapLongClickListeners(longClickPoint); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (!uiSettings.isScrollGesturesEnabled()) { + // don't allow a fling if scroll is disabled + return false; + } + + notifyOnFlingListeners(); + + if (!uiSettings.isFlingVelocityAnimationEnabled()) { + return false; + } + + float screenDensity = uiSettings.getPixelRatio(); + + // calculate velocity vector for xy dimensions, independent from screen size + double velocityXY = Math.hypot(velocityX / screenDensity, velocityY / screenDensity); + if (velocityXY < MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING) { + // ignore short flings, these can occur when other gestures just have finished executing + return false; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + // tilt results in a bigger translation, limiting input for #5281 + double tilt = transform.getTilt(); + double tiltFactor = 1.5 + ((tilt != 0) ? (tilt / 10) : 0); + double offsetX = velocityX / tiltFactor / screenDensity; + double offsetY = velocityY / tiltFactor / screenDensity; + + // calculate animation time based on displacement + long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE); + + // update transformation + transform.moveBy(offsetX, offsetY, animationTime); + + return true; + } + } + + private void doubleTapStarted() { + // disable the move detector in preparation for the quickzoom, + // so that we don't move the map's center slightly before the quickzoom is started (see #14227) + gesturesManager.getMoveGestureDetector().setEnabled(false); + doubleTapRegistered = true; + } + + private void doubleTapFinished() { + if (doubleTapRegistered) { + // re-enable the move detector in case of double tap + gesturesManager.getMoveGestureDetector().setEnabled(true); + doubleTapRegistered = false; + } + } + + private final class MoveGestureListener extends MoveGestureDetector.SimpleOnMoveGestureListener { + @Override + public boolean onMoveBegin(@NonNull MoveGestureDetector detector) { + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + cancelTransitionsIfRequired(); + notifyOnMoveBeginListeners(detector); + return true; + } + + @Override + public boolean onMove(@NonNull MoveGestureDetector detector, float distanceX, float distanceY) { + // first move event is often delivered with no displacement + if (distanceX != 0 || distanceY != 0) { + // dispatching camera start event only when the movement actually occurred + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + // Scroll the map + transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); + + notifyOnMoveListeners(detector); + } + return true; + } + + @Override + public void onMoveEnd(@NonNull MoveGestureDetector detector, float velocityX, float velocityY) { + dispatchCameraIdle(); + notifyOnMoveEndListeners(detector); + } + } + + private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener { + + private final float minimumGestureSpeed; + private final float minimumAngledGestureSpeed; + private final float minimumVelocity; + private final double scaleVelocityRatioThreshold; + private boolean quickZoom; + private float spanSinceLast; + private double screenHeight; + private double startZoom; + + ScaleGestureListener(double densityMultiplier, float minimumGestureSpeed, float minimumAngledGestureSpeed, + float minimumVelocity) { + this.minimumGestureSpeed = minimumGestureSpeed; + this.minimumAngledGestureSpeed = minimumAngledGestureSpeed; + this.minimumVelocity = minimumVelocity; + this.scaleVelocityRatioThreshold = SCALE_VELOCITY_RATIO_THRESHOLD * densityMultiplier; + } + + @Override + public boolean onScaleBegin(@NonNull StandardScaleGestureDetector detector) { + quickZoom = detector.getPointersCount() == 1; + + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + if (quickZoom) { + if (!uiSettings.isQuickZoomGesturesEnabled()) { + return false; + } + // re-try disabling the move detector in case double tap has been interrupted before quickzoom started + gesturesManager.getMoveGestureDetector().setEnabled(false); + } else { + if (detector.getPreviousSpan() > 0) { + float currSpan = detector.getCurrentSpan(); + float prevSpan = detector.getPreviousSpan(); + double currTime = detector.getCurrentEvent().getEventTime(); + double prevTime = detector.getPreviousEvent().getEventTime(); + if (currTime == prevTime) { + return false; + } + double speed = Math.abs(currSpan - prevSpan) / (currTime - prevTime); + if (speed < minimumGestureSpeed) { + // do not scale if the minimal gesture speed is not met + return false; + } else if (!gesturesManager.getRotateGestureDetector().isInProgress()) { + float rotationDeltaSinceLast = gesturesManager.getRotateGestureDetector().getDeltaSinceLast(); + if (Math.abs(rotationDeltaSinceLast) > 0.4 && speed < minimumAngledGestureSpeed) { + // do not scale in case we're preferring to start rotation + return false; + } + + if (uiSettings.isDisableRotateWhenScaling()) { + // disable rotate gesture when scale is detected first + gesturesManager.getRotateGestureDetector().setEnabled(false); + } + } + } else { + return false; + } + } + + screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + startZoom = transform.getRawZoom(); + + cancelTransitionsIfRequired(); + + notifyOnScaleBeginListeners(detector); + + spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan()); + + return true; + } + + @Override + public boolean onScale(@NonNull StandardScaleGestureDetector detector) { + // dispatching camera start event only when the movement actually occurred + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + PointF focalPoint = getScaleFocalPoint(detector); + if (quickZoom) { + double pixelDeltaChange = Math.abs(detector.getCurrentEvent().getY() - doubleTapFocalPoint.y); + boolean zoomedOut = detector.getCurrentEvent().getY() < doubleTapFocalPoint.y; + + // normalize the pixel delta change, ranging from 0 to screen height, to a constant zoom change range + double normalizedDeltaChange = normalize(pixelDeltaChange, 0, screenHeight, 0, QUICK_ZOOM_MAX_ZOOM_CHANGE); + + // calculate target zoom and adjust for a multiplier + double targetZoom = (zoomedOut ? startZoom - normalizedDeltaChange : startZoom + normalizedDeltaChange); + targetZoom *= uiSettings.getZoomRate(); + + transform.setZoom(targetZoom, focalPoint); + } else { + double zoomBy = + (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) * ZOOM_RATE * uiSettings.getZoomRate(); + transform.zoomBy(zoomBy, focalPoint); + } + + notifyOnScaleListeners(detector); + + spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan()); + + return true; + } + + @Override + public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) { + if (quickZoom) { + // re-enabled the move detector if the quickzoom happened + gesturesManager.getMoveGestureDetector().setEnabled(true); + } else { + // re-enable rotation in case it's been disabled + gesturesManager.getRotateGestureDetector().setEnabled(true); + } + + notifyOnScaleEndListeners(detector); + + float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); + + if (!uiSettings.isScaleVelocityAnimationEnabled() + || velocityXY < minimumVelocity + || spanSinceLast / velocityXY < scaleVelocityRatioThreshold) { + // notifying listeners that camera is idle only if there is no follow-up animation + dispatchCameraIdle(); + return; + } + + double zoomAddition = calculateScale(velocityXY, detector.isScalingOut()); + double currentZoom = transform.getRawZoom(); + PointF focalPoint = getScaleFocalPoint(detector); + // (log(x + 1 / e^2) + 2) * 150, x=0 to 2.5 (MapboxConstants#MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE) + long animationTime = (long) ((Math.log((Math.abs(zoomAddition)) + 1 / Math.pow(Math.E, 2)) + 2) + * SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER); + scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, focalPoint, animationTime); + scheduleAnimator(scaleAnimator); + } + + @NonNull + private PointF getScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) { + if (constantFocalPoint != null) { + // around user provided focal point + return constantFocalPoint; + } else if (quickZoom) { + // around center + return new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } else { + // around gesture + return detector.getFocalPoint(); + } + } + + private double calculateScale(double velocityXY, boolean isScalingOut) { + double zoomAddition = velocityXY * MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE * 1e-4; + zoomAddition = MathUtils.clamp(zoomAddition, 0, MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE); + if (isScalingOut) { + zoomAddition = -zoomAddition; + } + return zoomAddition; + } + } + + private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + private final float minimumScaleSpanWhenRotating; + private final float angularVelocityMultiplier; + private final float minimumAngularVelocity; + private final double rotateVelocityRatioThreshold; + private final float defaultSpanSinceStartThreshold; + + RotateGestureListener(float minimumScaleSpanWhenRotating, double densityMultiplier, float angularVelocityMultiplier, + float minimumAngularVelocity, float defaultSpanSinceStartThreshold) { + this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating; + this.angularVelocityMultiplier = angularVelocityMultiplier; + this.minimumAngularVelocity = minimumAngularVelocity; + this.rotateVelocityRatioThreshold = ROTATE_VELOCITY_RATIO_THRESHOLD * densityMultiplier; + this.defaultSpanSinceStartThreshold = defaultSpanSinceStartThreshold; + } + + @Override + public boolean onRotateBegin(@NonNull RotateGestureDetector detector) { + if (!uiSettings.isRotateGesturesEnabled()) { + return false; + } + + float deltaSinceLast = Math.abs(detector.getDeltaSinceLast()); + double currTime = detector.getCurrentEvent().getEventTime(); + double prevTime = detector.getPreviousEvent().getEventTime(); + if (currTime == prevTime) { + return false; + } + double speed = deltaSinceLast / (currTime - prevTime); + float deltaSinceStart = Math.abs(detector.getDeltaSinceStart()); + + // adjust the responsiveness of a rotation gesture - the higher the speed, the bigger the threshold + if (speed < 0.04 + || (speed > 0.07 && deltaSinceStart < 5) + || (speed > 0.15 && deltaSinceStart < 7) + || (speed > 0.5 && deltaSinceStart < 15) + ) { + return false; + } + + if (uiSettings.isIncreaseScaleThresholdWhenRotating()) { + // when rotation starts, interrupting scale and increasing the threshold + // to make rotation without scaling easier + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(minimumScaleSpanWhenRotating); + gesturesManager.getStandardScaleGestureDetector().interrupt(); + } + + cancelTransitionsIfRequired(); + + notifyOnRotateBeginListeners(detector); + + return true; + } + + @Override + public boolean onRotate(@NonNull RotateGestureDetector detector, float rotationDegreesSinceLast, + float rotationDegreesSinceFirst) { + // dispatching camera start event only when the movement actually occurred + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + // Calculate map bearing value + double bearing = transform.getRawBearing() + rotationDegreesSinceLast; + + // Rotate the map + PointF focalPoint = getRotateFocalPoint(detector); + transform.setBearing(bearing, focalPoint.x, focalPoint.y); + + notifyOnRotateListeners(detector); + + return true; + } + + @Override + public void onRotateEnd(@NonNull RotateGestureDetector detector, float velocityX, + float velocityY, float angularVelocity) { + if (uiSettings.isIncreaseScaleThresholdWhenRotating()) { + // resetting default scale threshold values + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(defaultSpanSinceStartThreshold); + } + + notifyOnRotateEndListeners(detector); + + angularVelocity = angularVelocity * angularVelocityMultiplier; + angularVelocity = MathUtils.clamp(angularVelocity, -MAXIMUM_ANGULAR_VELOCITY, MAXIMUM_ANGULAR_VELOCITY); + + float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); + float delta = Math.abs(detector.getDeltaSinceLast()); + double ratio = delta / velocityXY; + + if (!uiSettings.isRotateVelocityAnimationEnabled() + || Math.abs(angularVelocity) < minimumAngularVelocity + || (gesturesManager.getStandardScaleGestureDetector().isInProgress() && ratio < rotateVelocityRatioThreshold)) { + // notifying listeners that camera is idle only if there is no follow-up animation + dispatchCameraIdle(); + return; + } + + long animationTime = (long) ((Math.log((Math.abs(angularVelocity)) + 1 / Math.pow(Math.E, 2)) + 2) + * SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER); + + PointF focalPoint = getRotateFocalPoint(detector); + rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint); + scheduleAnimator(rotateAnimator); + } + + @NonNull + private PointF getRotateFocalPoint(@NonNull RotateGestureDetector detector) { + if (constantFocalPoint != null) { + // User provided focal point + return constantFocalPoint; + } else { + // around gesture + return detector.getFocalPoint(); + } + } + + private Animator createRotateAnimator(float angularVelocity, long animationTime, + @NonNull final PointF animationFocalPoint) { + ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f); + animator.setDuration(animationTime); + animator.setInterpolator(new DecelerateInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(@NonNull ValueAnimator animation) { + transform.setBearing( + transform.getRawBearing() + (float) animation.getAnimatedValue(), + animationFocalPoint.x, animationFocalPoint.y, + 0L + ); + } + }); + + animator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + } + + @Override + public void onAnimationCancel(Animator animation) { + transform.cancelTransitions(); + } + + @Override + public void onAnimationEnd(Animator animation) { + dispatchCameraIdle(); + } + }); + + return animator; + } + } + + private final class ShoveGestureListener extends ShoveGestureDetector.SimpleOnShoveGestureListener { + @Override + public boolean onShoveBegin(@NonNull ShoveGestureDetector detector) { + if (!uiSettings.isTiltGesturesEnabled()) { + return false; + } + + cancelTransitionsIfRequired(); + + // disabling move gesture during shove + gesturesManager.getMoveGestureDetector().setEnabled(false); + + notifyOnShoveBeginListeners(detector); + + return true; + } + + @Override + public boolean onShove(@NonNull ShoveGestureDetector detector, + float deltaPixelsSinceLast, float deltaPixelsSinceStart) { + // dispatching camera start event only when the movement actually occurred + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + // Get tilt value (scale and clamp) + double pitch = transform.getTilt(); + pitch -= MapboxConstants.SHOVE_PIXEL_CHANGE_FACTOR * deltaPixelsSinceLast; + pitch = MathUtils.clamp(pitch, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT); + + // Tilt the map + transform.setTilt(pitch); + + notifyOnShoveListeners(detector); + + return true; + } + + @Override + public void onShoveEnd(@NonNull ShoveGestureDetector detector, float velocityX, float velocityY) { + dispatchCameraIdle(); + + // re-enabling move gesture + gesturesManager.getMoveGestureDetector().setEnabled(true); + + notifyOnShoveEndListeners(detector); + } + } + + private final class TapGestureListener implements MultiFingerTapGestureDetector.OnMultiFingerTapGestureListener { + @Override + public boolean onMultiFingerTap(@NonNull MultiFingerTapGestureDetector detector, int pointersCount) { + if (!uiSettings.isZoomGesturesEnabled() || pointersCount != 2) { + return false; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + PointF zoomFocalPoint; + // Single finger double tap + if (constantFocalPoint != null) { + // User provided focal point + zoomFocalPoint = constantFocalPoint; + } else { + // Zoom in on gesture + zoomFocalPoint = detector.getFocalPoint(); + } + + zoomOutAnimated(zoomFocalPoint, false); + + return true; + } + } + + private Animator createScaleAnimator(double currentZoom, double zoomAddition, + @NonNull final PointF animationFocalPoint, long animationTime) { + ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition)); + animator.setDuration(animationTime); + animator.setInterpolator(new DecelerateInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + + @Override + public void onAnimationUpdate(@NonNull ValueAnimator animation) { + transform.setZoom((Float) animation.getAnimatedValue(), animationFocalPoint); + } + }); + + animator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + } + + @Override + public void onAnimationCancel(Animator animation) { + transform.cancelTransitions(); + } + + @Override + public void onAnimationEnd(Animator animation) { + dispatchCameraIdle(); + } + }); + return animator; + } + + /** + * Zoom in by 1. + * + * @param zoomFocalPoint focal point of zoom animation + * @param runImmediately if true, animation will be started right away, otherwise it will wait until + * {@link MotionEvent#ACTION_UP} is registered. + */ + void zoomInAnimated(@NonNull PointF zoomFocalPoint, boolean runImmediately) { + zoomAnimated(true, zoomFocalPoint, runImmediately); + } + + /** + * Zoom out by 1. + * + * @param zoomFocalPoint focal point of zoom animation + * @param runImmediately if true, animation will be started right away, otherwise it will wait until + * {@link MotionEvent#ACTION_UP} is registered. + */ + void zoomOutAnimated(@NonNull PointF zoomFocalPoint, boolean runImmediately) { + zoomAnimated(false, zoomFocalPoint, runImmediately); + } + + private void zoomAnimated(boolean zoomIn, @NonNull PointF zoomFocalPoint, boolean runImmediately) { + //canceling here as well, because when using a button it will not be canceled automatically by onDown() + cancelAnimator(scaleAnimator); + + double currentZoom = transform.getRawZoom(); + scaleAnimator = createScaleAnimator( + currentZoom, + zoomIn ? 1 : -1, + zoomFocalPoint, + MapboxConstants.ANIMATION_DURATION); + if (runImmediately) { + scaleAnimator.start(); + } else { + scheduleAnimator(scaleAnimator); + } + } + + private void dispatchCameraIdle() { + // we need to dispatch camera idle callback only if there is no other gestures in progress + if (noGesturesInProgress()) { + // invalidate the camera position, so that it's valid when fetched from the #onIdle event + // and doesn't rely on the last frame being rendered + transform.invalidateCameraPosition(); + cameraChangeDispatcher.onCameraIdle(); + } + } + + private void cancelTransitionsIfRequired() { + // we need to cancel core transitions only if there is no started gesture yet + if (noGesturesInProgress()) { + transform.cancelTransitions(); + } + } + + private boolean noGesturesInProgress() { + return (!uiSettings.isScrollGesturesEnabled() || !gesturesManager.getMoveGestureDetector().isInProgress()) + && (!uiSettings.isZoomGesturesEnabled() || !gesturesManager.getStandardScaleGestureDetector().isInProgress()) + && (!uiSettings.isRotateGesturesEnabled() || !gesturesManager.getRotateGestureDetector().isInProgress()) + && (!uiSettings.isTiltGesturesEnabled() || !gesturesManager.getShoveGestureDetector().isInProgress()); + } + + void notifyOnMapClickListeners(@NonNull PointF tapPoint) { + for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { + if (listener.onMapClick(projection.fromScreenLocation(tapPoint))) { + return; + } + } + } + + void notifyOnMapLongClickListeners(@NonNull PointF longClickPoint) { + for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) { + if (listener.onMapLongClick(projection.fromScreenLocation(longClickPoint))) { + return; + } + } + } + + void notifyOnFlingListeners() { + for (MapboxMap.OnFlingListener listener : onFlingListenerList) { + listener.onFling(); + } + } + + void notifyOnMoveBeginListeners(@NonNull MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveBegin(detector); + } + } + + void notifyOnMoveListeners(@NonNull MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMove(detector); + } + } + + void notifyOnMoveEndListeners(@NonNull MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveEnd(detector); + } + } + + void notifyOnRotateBeginListeners(@NonNull RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateBegin(detector); + } + } + + void notifyOnRotateListeners(@NonNull RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotate(detector); + } + } + + void notifyOnRotateEndListeners(@NonNull RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateEnd(detector); + } + } + + void notifyOnScaleBeginListeners(@NonNull StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleBegin(detector); + } + } + + void notifyOnScaleListeners(@NonNull StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScale(detector); + } + } + + void notifyOnScaleEndListeners(@NonNull StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleEnd(detector); + } + } + + void notifyOnShoveBeginListeners(@NonNull ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveBegin(detector); + } + } + + void notifyOnShoveListeners(@NonNull ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShove(detector); + } + } + + void notifyOnShoveEndListeners(@NonNull ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveEnd(detector); + } + } + + 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 addOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.add(listener); + } + + void removeOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.remove(listener); + } + + void addOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.add(listener); + } + + void removeOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.remove(listener); + } + + void addOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.add(listener); + } + + void removeOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.remove(listener); + } + + void addShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.add(listener); + } + + void removeShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.remove(listener); + } + + AndroidGesturesManager getGesturesManager() { + return gesturesManager; + } + + void setGesturesManager(@NonNull Context context, @NonNull AndroidGesturesManager gesturesManager, + boolean attachDefaultListeners, boolean setDefaultMutuallyExclusives) { + initializeGesturesManager(gesturesManager, setDefaultMutuallyExclusives); + initializeGestureListeners(context, attachDefaultListeners); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java new file mode 100644 index 000000000..afb80027d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -0,0 +1,271 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.PointF; +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +/** + * Manages key events on a MapView. + *

+ *

    + *
  • Uses {@link Transform} to change the map state
  • + *
  • Uses {@link UiSettings} to verify validity of user restricted movement.
  • + *
+ *

+ */ +final class MapKeyListener { + + private final Transform transform; + private final UiSettings uiSettings; + private final MapGestureDetector mapGestureDetector; + + @Nullable + private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; + + MapKeyListener(Transform transform, UiSettings uiSettings, MapGestureDetector mapGestureDetector) { + this.transform = transform; + this.uiSettings = uiSettings; + this.mapGestureDetector = mapGestureDetector; + } + + /** + * Called when the user presses a key, alse called for repeated keys held down. + * + * @param keyCode the id of the pressed key + * @param event the related key event + * @return true if the wevent is handled + */ + boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { + // If the user has held the scroll key down for a while then accelerate + // the scroll speed + double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; + + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + event.startTracking(); + return true; + + case KeyEvent.KEYCODE_DPAD_LEFT: + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move left + transform.moveBy(scrollDist, 0.0, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move right + transform.moveBy(-scrollDist, 0.0, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_UP: + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move up + transform.moveBy(0.0, scrollDist, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_DOWN: + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move down + transform.moveBy(0.0, -scrollDist, 0 /*no animation*/); + return true; + + default: + // We are not interested in this key + return false; + } + } + + /** + * Called when the user long presses a key that is being tracked. + * + * @param keyCode the id of the long pressed key + * @param event the related key event + * @return true if event is handled + */ + boolean onKeyLongPress(int keyCode, KeyEvent event) { + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Zoom out + PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + mapGestureDetector.zoomOutAnimated(focalPoint, true); + return true; + + default: + // We are not interested in this key + return false; + } + } + + /** + * Called when the user releases a key. + * + * @param keyCode the id of the released key + * @param event the related key event + * @return true if the event is handled + */ + boolean onKeyUp(int keyCode, KeyEvent event) { + // Check if the key action was canceled (used for virtual keyboards) + if (event.isCanceled()) { + return false; + } + + // Check which key was pressed via hardware/real key code + // Note if keyboard does not have physical key (ie primary non-shifted + // key) then it will not appear here + // Must use the key character map as physical to character is not + // fixed/guaranteed + switch (keyCode) { + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Zoom in + PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + mapGestureDetector.zoomInAnimated(focalPoint, true); + return true; + } + + // We are not interested in this key + return false; + } + + /** + * Called for trackball events, all motions are relative in device specific units. + * + * @param event the related motion event + * @return true if the event is handled + */ + boolean onTrackballEvent(MotionEvent event) { + // Choose the action + switch (event.getActionMasked()) { + // The trackball was rotated + case MotionEvent.ACTION_MOVE: + if (!uiSettings.isScrollGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Scroll the map + transform.moveBy(-10.0 * event.getX(), -10.0 * event.getY(), 0 /*no animation*/); + return true; + + // Trackball was pushed in so start tracking and tell system we are + // interested + // We will then get the up action + case MotionEvent.ACTION_DOWN: + // Set up a delayed callback to check if trackball is still + // After waiting the system long press time out + if (currentTrackballLongPressTimeOut != null) { + currentTrackballLongPressTimeOut.cancel(); + currentTrackballLongPressTimeOut = null; + } + currentTrackballLongPressTimeOut = new TrackballLongPressTimeOut(); + new Handler(Looper.getMainLooper()).postDelayed(currentTrackballLongPressTimeOut, + ViewConfiguration.getLongPressTimeout()); + return true; + + // Trackball was released + case MotionEvent.ACTION_UP: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Only handle if we have not already long pressed + if (currentTrackballLongPressTimeOut != null) { + // Zoom in + PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + mapGestureDetector.zoomInAnimated(focalPoint, true); + } + return true; + + // Trackball was cancelled + case MotionEvent.ACTION_CANCEL: + if (currentTrackballLongPressTimeOut != null) { + currentTrackballLongPressTimeOut.cancel(); + currentTrackballLongPressTimeOut = null; + } + return true; + + default: + // We are not interested in this event + return false; + } + } + + /** + * This class implements the trackball long press time out callback + */ + private class TrackballLongPressTimeOut implements Runnable { + + // Track if we have been cancelled + private boolean cancelled; + + TrackballLongPressTimeOut() { + cancelled = false; + } + + // Cancel the timeout + public void cancel() { + cancelled = true; + } + + // Called when long press time out expires + @Override + public void run() { + // Check if the trackball is still pressed + if (!cancelled) { + // Zoom out + PointF pointF = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + mapGestureDetector.zoomOutAnimated(pointF, true); + + // Ensure the up action is not run + currentTrackballLongPressTimeOut = null; + } + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java new file mode 100644 index 000000000..4521d2ae6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -0,0 +1,1350 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.annotation.CallSuper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.support.v4.util.LongSparseArray; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.TextureView; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; +import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer; +import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.MapboxGLSurfaceView; +import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; +import com.mapbox.mapboxsdk.maps.widgets.CompassView; +import com.mapbox.mapboxsdk.net.ConnectivityReceiver; +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.utils.BitmapUtils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; +import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; + +/** + *

+ * A {@code MapView} provides an embeddable map interface. + * You use this class to display map information and to manipulate the map contents from your application. + * You can center the map on a given coordinate, specify the size of the area you want to display, + * and style the features of the map to fit your application's use case. + *

+ *

+ * Use of {@code MapView} requires a Mapbox API access token. + * Obtain an access token on the Mapbox account page. + *

+ * Warning: Please note that you are responsible for getting permission to use the map data, + * and for ensuring your use adheres to the relevant terms of use. + */ +public class MapView extends FrameLayout implements NativeMapView.ViewCallback { + + private final MapChangeReceiver mapChangeReceiver = new MapChangeReceiver(); + private final MapCallback mapCallback = new MapCallback(); + private final InitialRenderCallback initialRenderCallback = new InitialRenderCallback(); + + @Nullable + private NativeMap nativeMapView; + @Nullable + private MapboxMap mapboxMap; + private AttributionClickListener attributionClickListener; + private MapboxMapOptions mapboxMapOptions; + private MapRenderer mapRenderer; + private boolean destroyed; + + private CompassView compassView; + private PointF focalPoint; + private ImageView attrView; + private ImageView logoView; + + @Nullable + private MapGestureDetector mapGestureDetector; + @Nullable + private MapKeyListener mapKeyListener; + @Nullable + private Bundle savedInstanceState; + private boolean isStarted; + + @UiThread + public MapView(@NonNull Context context) { + super(context); + initialize(context, MapboxMapOptions.createFromAttributes(context)); + } + + @UiThread + public MapView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initialize(context, MapboxMapOptions.createFromAttributes(context, attrs)); + } + + @UiThread + public MapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context, MapboxMapOptions.createFromAttributes(context, attrs)); + } + + @UiThread + public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) { + super(context); + initialize(context, options == null ? MapboxMapOptions.createFromAttributes(context) : options); + } + + @CallSuper + @UiThread + protected void initialize(@NonNull final Context context, @NonNull final MapboxMapOptions options) { + if (isInEditMode()) { + // in IDE layout editor, just return + return; + } + + if (!Mapbox.hasInstance()) { + throw new MapboxConfigurationException(); + } + + // hide surface until map is fully loaded #10990 + setForeground(new ColorDrawable(options.getForegroundLoadColor())); + + mapboxMapOptions = options; + + // inflate view + View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this); + compassView = view.findViewById(R.id.compassView); + attrView = view.findViewById(R.id.attributionView); + attrView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_info_bg_selector)); + logoView = view.findViewById(R.id.logoView); + logoView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_logo_icon)); + + // add accessibility support + setContentDescription(context.getString(R.string.mapbox_mapActionDescription)); + setWillNotDraw(false); + initialiseDrawingSurface(options); + } + + private void initialiseMap() { + Context context = getContext(); + + // callback for focal point invalidation + final FocalPointInvalidator focalInvalidator = new FocalPointInvalidator(); + focalInvalidator.addListener(createFocalPointChangeListener()); + + // callback for registering touch listeners + GesturesManagerInteractionListener registerTouchListener = new GesturesManagerInteractionListener(); + + // callback for camera change events + final CameraChangeDispatcher cameraDispatcher = new CameraChangeDispatcher(); + + // setup components for MapboxMap creation + Projection proj = new Projection(nativeMapView, this); + UiSettings uiSettings = new UiSettings(proj, focalInvalidator, compassView, attrView, logoView, getPixelRatio()); + LongSparseArray annotationsArray = new LongSparseArray<>(); + IconManager iconManager = new IconManager(nativeMapView); + Annotations annotations = new AnnotationContainer(nativeMapView, annotationsArray); + Markers markers = new MarkerContainer(nativeMapView, annotationsArray, iconManager); + Polygons polygons = new PolygonContainer(nativeMapView, annotationsArray); + Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray); + ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray); + AnnotationManager annotationManager = new AnnotationManager(this, annotationsArray, iconManager, + annotations, markers, polygons, polylines, shapeAnnotations); + Transform transform = new Transform(this, nativeMapView, cameraDispatcher); + + // MapboxMap + List developerAnimationListeners = new ArrayList<>(); + mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, proj, registerTouchListener, cameraDispatcher, + developerAnimationListeners); + mapboxMap.injectAnnotationManager(annotationManager); + + // user input + mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, + annotationManager, cameraDispatcher); + mapKeyListener = new MapKeyListener(transform, uiSettings, mapGestureDetector); + + // compass + compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraDispatcher)); + compassView.setOnClickListener(createCompassClickListener(cameraDispatcher)); + + // LocationComponent + mapboxMap.injectLocationComponent(new LocationComponent(mapboxMap, transform, developerAnimationListeners)); + + // inject widgets with MapboxMap + attrView.setOnClickListener(attributionClickListener = new AttributionClickListener(context, mapboxMap)); + + // Ensure this view is interactable + setClickable(true); + setLongClickable(true); + setFocusable(true); + setFocusableInTouchMode(true); + requestDisallowInterceptTouchEvent(true); + + // notify Map object about current connectivity state + nativeMapView.setReachability(Mapbox.isConnected()); + + // initialise MapboxMap + if (savedInstanceState == null) { + mapboxMap.initialise(context, mapboxMapOptions); + } else { + mapboxMap.onRestoreInstanceState(savedInstanceState); + } + + mapCallback.initialised(); + } + + private FocalPointChangeListener createFocalPointChangeListener() { + return new FocalPointChangeListener() { + @Override + public void onFocalPointChanged(PointF pointF) { + focalPoint = pointF; + } + }; + } + + private MapboxMap.OnCompassAnimationListener createCompassAnimationListener(@NonNull 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(@NonNull 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); + } + } + }; + } + + // + // Lifecycle events + // + + /** + *

+ * You must call this method from the parent's Activity#onCreate(Bundle)} or + * Fragment#onViewCreated(View, Bundle). + *

+ * 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 com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String) + */ + @UiThread + public void onCreate(@Nullable Bundle savedInstanceState) { + if (savedInstanceState == null) { + TelemetryDefinition telemetry = Mapbox.getTelemetry(); + if (telemetry != null) { + telemetry.onAppUserTurnstileEvent(); + } + } else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) { + this.savedInstanceState = savedInstanceState; + } + } + + private void initialiseDrawingSurface(MapboxMapOptions options) { + String localFontFamily = options.getLocalIdeographFontFamily(); + if (options.getTextureMode()) { + TextureView textureView = new TextureView(getContext()); + boolean translucentSurface = options.getTranslucentTextureSurface(); + mapRenderer = new TextureViewMapRenderer(getContext(), + textureView, localFontFamily, translucentSurface) { + @Override + protected void onSurfaceCreated(GL10 gl, EGLConfig config) { + MapView.this.onSurfaceCreated(); + super.onSurfaceCreated(gl, config); + } + }; + + addView(textureView, 0); + } else { + MapboxGLSurfaceView glSurfaceView = new MapboxGLSurfaceView(getContext()); + glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop()); + mapRenderer = new GLSurfaceViewMapRenderer(getContext(), glSurfaceView, localFontFamily) { + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + MapView.this.onSurfaceCreated(); + super.onSurfaceCreated(gl, config); + } + }; + + addView(glSurfaceView, 0); + } + + boolean crossSourceCollisions = mapboxMapOptions.getCrossSourceCollisions(); + nativeMapView = new NativeMapView( + getContext(), getPixelRatio(), crossSourceCollisions, this, mapChangeReceiver, mapRenderer + ); + } + + private void onSurfaceCreated() { + post(new Runnable() { + @Override + public void run() { + // Initialise only when not destroyed and only once + if (!destroyed && mapboxMap == null) { + MapView.this.initialiseMap(); + mapboxMap.onStart(); + } + } + }); + } + + /** + * 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) { + if (mapboxMap != null) { + outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true); + mapboxMap.onSaveInstanceState(outState); + } + } + + /** + * You must call this method from the parent's Activity#onStart() or Fragment#onStart() + */ + @UiThread + public void onStart() { + if (!isStarted) { + ConnectivityReceiver.instance(getContext()).activate(); + FileSource.getInstance(getContext()).activate(); + isStarted = true; + } + if (mapboxMap != null) { + mapboxMap.onStart(); + } + + if (mapRenderer != null) { + mapRenderer.onStart(); + } + } + + /** + * You must call this method from the parent's Activity#onResume() or Fragment#onResume(). + */ + @UiThread + public void onResume() { + if (mapRenderer != null) { + mapRenderer.onResume(); + } + } + + /** + * You must call this method from the parent's Activity#onPause() or Fragment#onPause(). + */ + @UiThread + public void onPause() { + if (mapRenderer != null) { + mapRenderer.onPause(); + } + } + + /** + * You must call this method from the parent's Activity#onStop() or Fragment#onStop(). + */ + @UiThread + public void onStop() { + if (attributionClickListener != null) { + attributionClickListener.onStop(); + } + + if (mapboxMap != null) { + // map was destroyed before it was started + mapGestureDetector.cancelAnimators(); + mapboxMap.onStop(); + } + + if (mapRenderer != null) { + mapRenderer.onStop(); + } + + if (isStarted) { + ConnectivityReceiver.instance(getContext()).deactivate(); + FileSource.getInstance(getContext()).deactivate(); + isStarted = false; + } + } + + /** + * You must call this method from the parent's Activity#onDestroy() or Fragment#onDestroyView(). + */ + @UiThread + public void onDestroy() { + destroyed = true; + mapChangeReceiver.clear(); + mapCallback.onDestroy(); + initialRenderCallback.onDestroy(); + + if (compassView != null) { + // avoid leaking context through animator #13742 + compassView.resetAnimation(); + } + + if (mapboxMap != null) { + mapboxMap.onDestroy(); + } + + if (nativeMapView != null) { + // null when destroying an activity programmatically mapbox-navigation-android/issues/503 + nativeMapView.destroy(); + nativeMapView = null; + } + + if (mapRenderer != null) { + mapRenderer.onDestroy(); + } + } + + /** + * The maximum frame rate at which the map view is rendered, + * but it can't excess the ability of device hardware. + * + * @param maximumFps Can be set to arbitrary integer values. + */ + public void setMaximumFps(int maximumFps) { + if (mapRenderer != null) { + mapRenderer.setMaximumFps(maximumFps); + } else { + throw new IllegalStateException("Calling MapView#setMaximumFps before mapRenderer is created."); + } + } + + /** + * Returns if the map has been destroyed. + *

+ * This method can be used to determine if the result of an asynchronous operation should be set. + *

+ * + * @return true, if the map has been destroyed + */ + @UiThread + public boolean isDestroyed() { + return destroyed; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!isGestureDetectorInitialized()) { + return super.onTouchEvent(event); + } + + return mapGestureDetector.onTouchEvent(event) || super.onTouchEvent(event); + } + + @Override + public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { + return mapKeyListener.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + return mapKeyListener.onKeyLongPress(keyCode, event) || super.onKeyLongPress(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { + return mapKeyListener.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); + } + + @Override + public boolean onTrackballEvent(@NonNull MotionEvent event) { + return mapKeyListener.onTrackballEvent(event) || super.onTrackballEvent(event); + } + + @Override + public boolean onGenericMotionEvent(@NonNull MotionEvent event) { + if (!isGestureDetectorInitialized()) { + return super.onGenericMotionEvent(event); + } + return mapGestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); + } + + /** + * You must call this method from the parent's Activity#onLowMemory() or Fragment#onLowMemory(). + */ + @UiThread + public void onLowMemory() { + if (nativeMapView != null && mapboxMap != null && !destroyed) { + nativeMapView.onLowMemory(); + } + } + + // + // Rendering + // + + @Override + protected void onSizeChanged(int width, int height, int oldw, int oldh) { + if (!isInEditMode() && nativeMapView != null) { + // null-checking the nativeMapView, see #13277 + nativeMapView.resizeView(width, height); + } + } + + private float getPixelRatio() { + // check is user defined his own pixel ratio value + float pixelRatio = mapboxMapOptions.getPixelRatio(); + if (pixelRatio == 0) { + // if not, get the one defined by the system + pixelRatio = getResources().getDisplayMetrics().density; + } + return pixelRatio; + } + + // + // ViewCallback + // + + @Nullable + @Override + public Bitmap getViewContent() { + return BitmapUtils.createBitmapFromView(this); + } + + // + // Map events + // + + /** + * Set a callback that's invoked when the camera region will change. + * + * @param listener The callback that's invoked when the camera region will change + */ + public void addOnCameraWillChangeListener(@NonNull OnCameraWillChangeListener listener) { + mapChangeReceiver.addOnCameraWillChangeListener(listener); + } + + /** + * Remove a callback that's invoked when the camera region will change. + * + * @param listener The callback that's invoked when the camera region will change + */ + public void removeOnCameraWillChangeListener(@NonNull OnCameraWillChangeListener listener) { + mapChangeReceiver.removeOnCameraWillChangeListener(listener); + } + + /** + * Set a callback that's invoked when the camera is changing. + * + * @param listener The callback that's invoked when the camera is changing + */ + public void addOnCameraIsChangingListener(@NonNull OnCameraIsChangingListener listener) { + mapChangeReceiver.addOnCameraIsChangingListener(listener); + } + + /** + * Remove a callback that's invoked when the camera is changing. + * + * @param listener The callback that's invoked when the camera is changing + */ + public void removeOnCameraIsChangingListener(@NonNull OnCameraIsChangingListener listener) { + mapChangeReceiver.removeOnCameraIsChangingListener(listener); + } + + /** + * Set a callback that's invoked when the camera region did change. + * + * @param listener The callback that's invoked when the camera region did change + */ + public void addOnCameraDidChangeListener(@NonNull OnCameraDidChangeListener listener) { + mapChangeReceiver.addOnCameraDidChangeListener(listener); + } + + /** + * Set a callback that's invoked when the camera region did change. + * + * @param listener The callback that's invoked when the camera region did change + */ + public void removeOnCameraDidChangeListener(@NonNull OnCameraDidChangeListener listener) { + mapChangeReceiver.removeOnCameraDidChangeListener(listener); + } + + /** + * Set a callback that's invoked when the map will start loading. + * + * @param listener The callback that's invoked when the map will start loading + */ + public void addOnWillStartLoadingMapListener(@NonNull OnWillStartLoadingMapListener listener) { + mapChangeReceiver.addOnWillStartLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map will start loading. + * + * @param listener The callback that's invoked when the map will start loading + */ + public void removeOnWillStartLoadingMapListener(@NonNull OnWillStartLoadingMapListener listener) { + mapChangeReceiver.removeOnWillStartLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map has finished loading. + * + * @param listener The callback that's invoked when the map has finished loading + */ + public void addOnDidFinishLoadingMapListener(@NonNull OnDidFinishLoadingMapListener listener) { + mapChangeReceiver.addOnDidFinishLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map has finished loading. + * + * @param listener The callback that's invoked when the map has finished loading + */ + public void removeOnDidFinishLoadingMapListener(@NonNull OnDidFinishLoadingMapListener listener) { + mapChangeReceiver.removeOnDidFinishLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map failed to load. + * + * @param listener The callback that's invoked when the map failed to load + */ + public void addOnDidFailLoadingMapListener(@NonNull OnDidFailLoadingMapListener listener) { + mapChangeReceiver.addOnDidFailLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map failed to load. + * + * @param listener The callback that's invoked when the map failed to load + */ + public void removeOnDidFailLoadingMapListener(@NonNull OnDidFailLoadingMapListener listener) { + mapChangeReceiver.removeOnDidFailLoadingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map will start rendering a frame. + * + * @param listener The callback that's invoked when the camera will start rendering a frame + */ + public void addOnWillStartRenderingFrameListener(@NonNull OnWillStartRenderingFrameListener listener) { + mapChangeReceiver.addOnWillStartRenderingFrameListener(listener); + } + + /** + * Set a callback that's invoked when the map will start rendering a frame. + * + * @param listener The callback that's invoked when the camera will start rendering a frame + */ + public void removeOnWillStartRenderingFrameListener(@NonNull OnWillStartRenderingFrameListener listener) { + mapChangeReceiver.removeOnWillStartRenderingFrameListener(listener); + } + + /** + * Set a callback that's invoked when the map has finished rendering a frame. + * + * @param listener The callback that's invoked when the map has finished rendering a frame + */ + public void addOnDidFinishRenderingFrameListener(@NonNull OnDidFinishRenderingFrameListener listener) { + mapChangeReceiver.addOnDidFinishRenderingFrameListener(listener); + } + + /** + * Set a callback that's invoked when the map has finished rendering a frame. + * + * @param listener The callback that's invoked when the map has finished rendering a frame + */ + public void removeOnDidFinishRenderingFrameListener(@NonNull OnDidFinishRenderingFrameListener listener) { + mapChangeReceiver.removeOnDidFinishRenderingFrameListener(listener); + } + + /** + * Set a callback that's invoked when the map will start rendering. + * + * @param listener The callback that's invoked when the map will start rendering + */ + public void addOnWillStartRenderingMapListener(@NonNull OnWillStartRenderingMapListener listener) { + mapChangeReceiver.addOnWillStartRenderingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map will start rendering. + * + * @param listener The callback that's invoked when the map will start rendering + */ + public void removeOnWillStartRenderingMapListener(@NonNull OnWillStartRenderingMapListener listener) { + mapChangeReceiver.removeOnWillStartRenderingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map has finished rendering. + * + * @param listener The callback that's invoked when the map has finished rendering + */ + public void addOnDidFinishRenderingMapListener(@NonNull OnDidFinishRenderingMapListener listener) { + mapChangeReceiver.addOnDidFinishRenderingMapListener(listener); + } + + /** + * Remove a callback that's invoked when the map has finished rendering. + * + * @param listener The callback that's invoked when the map has has finished rendering. + */ + public void removeOnDidFinishRenderingMapListener(OnDidFinishRenderingMapListener listener) { + mapChangeReceiver.removeOnDidFinishRenderingMapListener(listener); + } + + /** + * Set a callback that's invoked when the map has entered the idle state. + * + * @param listener The callback that's invoked when the map has entered the idle state. + */ + public void addOnDidBecomeIdleListener(@NonNull OnDidBecomeIdleListener listener) { + mapChangeReceiver.addOnDidBecomeIdleListener(listener); + } + + /** + * Remove a callback that's invoked when the map has entered the idle state. + * + * @param listener The callback that's invoked when the map has entered the idle state. + */ + public void removeOnDidBecomeIdleListener(@NonNull OnDidBecomeIdleListener listener) { + mapChangeReceiver.removeOnDidBecomeIdleListener(listener); + } + + /** + * Set a callback that's invoked when the style has finished loading. + * + * @param listener The callback that's invoked when the style has finished loading + */ + public void addOnDidFinishLoadingStyleListener(@NonNull OnDidFinishLoadingStyleListener listener) { + mapChangeReceiver.addOnDidFinishLoadingStyleListener(listener); + } + + /** + * Set a callback that's invoked when the style has finished loading. + * + * @param listener The callback that's invoked when the style has finished loading + */ + public void removeOnDidFinishLoadingStyleListener(@NonNull OnDidFinishLoadingStyleListener listener) { + mapChangeReceiver.removeOnDidFinishLoadingStyleListener(listener); + } + + /** + * Set a callback that's invoked when a map source has changed. + * + * @param listener The callback that's invoked when the source has changed + */ + public void addOnSourceChangedListener(@NonNull OnSourceChangedListener listener) { + mapChangeReceiver.addOnSourceChangedListener(listener); + } + + /** + * Set a callback that's invoked when a map source has changed. + * + * @param listener The callback that's invoked when the source has changed + */ + public void removeOnSourceChangedListener(@NonNull OnSourceChangedListener listener) { + mapChangeReceiver.removeOnSourceChangedListener(listener); + } + + /** + * Set a callback that's invoked when the id of an icon is missing. + * + * @param listener The callback that's invoked when the id of an icon is missing + */ + public void addOnStyleImageMissingListener(@NonNull OnStyleImageMissingListener listener) { + mapChangeReceiver.addOnStyleImageMissingListener(listener); + } + + /** + * Set a callback that's invoked when a map source has changed. + * + * @param listener The callback that's invoked when the source has changed + */ + public void removeOnStyleImageMissingListener(@NonNull OnStyleImageMissingListener listener) { + mapChangeReceiver.removeOnStyleImageMissingListener(listener); + } + + /** + * Set a callback that's invoked when map needs to release unused image resources. + *

+ * A callback will be called only for unused images that were provided by the client via + * {@link OnStyleImageMissingListener#onStyleImageMissing(String)} listener interface. + *

+ *

+ * By default, platform will remove unused images from the style. By adding listener, default + * behavior can be overridden and client can control whether to release unused resources. + *

+ * + * @param listener The callback that's invoked when map needs to release unused image resources + */ + public void addOnCanRemoveUnusedStyleImageListener(@NonNull OnCanRemoveUnusedStyleImageListener listener) { + mapChangeReceiver.addOnCanRemoveUnusedStyleImageListener(listener); + } + + /** + * Removes a callback that's invoked when map needs to release unused image resources. + *

+ * When all listeners are removed, platform will fallback to default behavior, which is to remove + * unused images from the style. + *

+ * + * @param listener The callback that's invoked when map needs to release unused image resources + */ + public void removeOnCanRemoveUnusedStyleImageListener(@NonNull OnCanRemoveUnusedStyleImageListener listener) { + mapChangeReceiver.removeOnCanRemoveUnusedStyleImageListener(listener); + } + + /** + * Interface definition for a callback to be invoked when the camera will change. + *

+ * {@link MapView#addOnCameraWillChangeListener(OnCameraWillChangeListener)} + *

+ */ + public interface OnCameraWillChangeListener { + + /** + * Called when the camera region will change. + */ + void onCameraWillChange(boolean animated); + } + + /** + * Interface definition for a callback to be invoked when the camera is changing. + *

+ * {@link MapView#addOnCameraIsChangingListener(OnCameraIsChangingListener)} + *

+ */ + public interface OnCameraIsChangingListener { + /** + * Called when the camera is changing. + */ + void onCameraIsChanging(); + } + + /** + * Interface definition for a callback to be invoked when the map region did change. + *

+ * {@link MapView#addOnCameraDidChangeListener(OnCameraDidChangeListener)} + *

+ */ + public interface OnCameraDidChangeListener { + /** + * Called when the camera did change. + */ + void onCameraDidChange(boolean animated); + } + + /** + * Interface definition for a callback to be invoked when the map will start loading. + *

+ * {@link MapView#addOnWillStartLoadingMapListener(OnWillStartLoadingMapListener)} + *

+ */ + public interface OnWillStartLoadingMapListener { + /** + * Called when the map will start loading. + */ + void onWillStartLoadingMap(); + } + + /** + * Interface definition for a callback to be invoked when the map finished loading. + *

+ * {@link MapView#addOnDidFinishLoadingMapListener(OnDidFinishLoadingMapListener)} + *

+ */ + public interface OnDidFinishLoadingMapListener { + /** + * Called when the map has finished loading. + */ + void onDidFinishLoadingMap(); + } + + /** + * Interface definition for a callback to be invoked when the map is changing. + *

+ * {@link MapView#addOnDidFailLoadingMapListener(OnDidFailLoadingMapListener)} + *

+ */ + public interface OnDidFailLoadingMapListener { + /** + * Called when the map failed to load. + * + * @param errorMessage The reason why the map failed to load + */ + void onDidFailLoadingMap(String errorMessage); + } + + /** + * Interface definition for a callback to be invoked when the map will start rendering a frame. + *

+ * {@link MapView#addOnWillStartRenderingFrameListener(OnWillStartRenderingFrameListener)} + *

+ */ + public interface OnWillStartRenderingFrameListener { + /** + * Called when the map will start rendering a frame. + */ + void onWillStartRenderingFrame(); + } + + /** + * Interface definition for a callback to be invoked when the map finished rendering a frame. + *

+ * {@link MapView#addOnDidFinishRenderingFrameListener(OnDidFinishRenderingFrameListener)} + *

+ */ + public interface OnDidFinishRenderingFrameListener { + /** + * Called when the map has finished rendering a frame + * + * @param fully true if all frames have been rendered, false if partially rendered + */ + void onDidFinishRenderingFrame(boolean fully); + } + + /** + * Interface definition for a callback to be invoked when the map will start rendering the map. + *

+ * {@link MapView#addOnDidFailLoadingMapListener(OnDidFailLoadingMapListener)} + *

+ */ + public interface OnWillStartRenderingMapListener { + /** + * Called when the map will start rendering. + */ + void onWillStartRenderingMap(); + } + + /** + * Interface definition for a callback to be invoked when the map is changing. + *

+ * {@link MapView#addOnDidFinishRenderingMapListener(OnDidFinishRenderingMapListener)} + *

+ */ + public interface OnDidFinishRenderingMapListener { + /** + * Called when the map has finished rendering. + * + * @param fully true if map is fully rendered, false if not fully rendered + */ + void onDidFinishRenderingMap(boolean fully); + } + + /** + * Interface definition for a callback to be invoked when the map has entered the idle state. + *

+ * Calling {@link MapboxMap#snapshot(MapboxMap.SnapshotReadyCallback)} from this callback + * will result in recursive execution. Use {@link OnDidFinishRenderingFrameListener} instead. + *

+ *

+ * {@link MapView#addOnDidBecomeIdleListener(OnDidBecomeIdleListener)} + *

+ */ + public interface OnDidBecomeIdleListener { + /** + * Called when the map has entered the idle state. + */ + void onDidBecomeIdle(); + } + + /** + * Interface definition for a callback to be invoked when the map has loaded the style. + *

+ * {@link MapView#addOnDidFailLoadingMapListener(OnDidFailLoadingMapListener)} + *

+ */ + public interface OnDidFinishLoadingStyleListener { + /** + * Called when a style has finished loading. + */ + void onDidFinishLoadingStyle(); + } + + /** + * Interface definition for a callback to be invoked when a map source has changed. + *

+ * {@link MapView#addOnDidFailLoadingMapListener(OnDidFailLoadingMapListener)} + *

+ */ + public interface OnSourceChangedListener { + /** + * Called when a map source has changed. + * + * @param id the id of the source that has changed + */ + void onSourceChangedListener(String id); + } + + /** + * Interface definition for a callback to be invoked with the id of a missing icon. The icon should be added + * synchronously with {@link Style#addImage(String, Bitmap)} to be rendered on the current zoom level. When loading + * icons asynchronously, you can load a placeholder image and replace it when you icon has loaded. + *

+ * {@link MapView#addOnStyleImageMissingListener(OnStyleImageMissingListener)} + *

+ */ + public interface OnStyleImageMissingListener { + /** + * Called when the map is missing an icon.The icon should be added synchronously with + * {@link Style#addImage(String, Bitmap)} to be rendered on the current zoom level. When loading icons + * asynchronously, you can load a placeholder image and replace it when you icon has loaded. + * + * @param id the id of the icon that is missing + */ + void onStyleImageMissing(@NonNull String id); + } + + /** + * Interface definition for a callback to be invoked with an unused image identifier. + *

+ * {@link MapView#addOnCanRemoveUnusedStyleImageListener(OnCanRemoveUnusedStyleImageListener)} + *

+ */ + public interface OnCanRemoveUnusedStyleImageListener { + /** + * Called when the map needs to release unused image resources. + * + * @param id of an image that is not used by the map and can be removed from the style. + * @return true if image can be removed, false otherwise. + */ + boolean onCanRemoveUnusedStyleImage(@NonNull String id); + } + + /** + * Sets a callback object which will be triggered when the {@link MapboxMap} instance is ready to be used. + * + * @param callback The callback object that will be triggered when the map is ready to be used. + */ + @UiThread + public void getMapAsync(final @NonNull OnMapReadyCallback callback) { + if (mapboxMap == null) { + // Add callback to the list only if the style hasn't loaded, or the drawing surface isn't ready + mapCallback.addOnMapReadyCallback(callback); + } else { + callback.onMapReady(mapboxMap); + } + } + + private boolean isGestureDetectorInitialized() { + return mapGestureDetector != null; + } + + @Nullable + MapboxMap getMapboxMap() { + return mapboxMap; + } + + void setMapboxMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } + + private class FocalPointInvalidator implements FocalPointChangeListener { + + private final List focalPointChangeListeners = new ArrayList<>(); + + void addListener(FocalPointChangeListener focalPointChangeListener) { + focalPointChangeListeners.add(focalPointChangeListener); + } + + @Override + public void onFocalPointChanged(PointF pointF) { + mapGestureDetector.setFocalPoint(pointF); + for (FocalPointChangeListener focalPointChangeListener : focalPointChangeListeners) { + focalPointChangeListener.onFocalPointChanged(pointF); + } + } + } + + /** + * The initial render callback waits for rendering to happen before making the map visible for end-users. + * We wait for the second DID_FINISH_RENDERING_FRAME map change event as the first will still show a black surface. + */ + private class InitialRenderCallback implements OnDidFinishRenderingFrameListener { + + private int renderCount; + + InitialRenderCallback() { + addOnDidFinishRenderingFrameListener(this); + } + + @Override + public void onDidFinishRenderingFrame(boolean fully) { + if (mapboxMap != null && mapboxMap.getStyle() != null && mapboxMap.getStyle().isFullyLoaded()) { + renderCount++; + if (renderCount == 3) { + MapView.this.setForeground(null); + removeOnDidFinishRenderingFrameListener(this); + } + } + } + + private void onDestroy() { + removeOnDidFinishRenderingFrameListener(this); + } + } + + private class GesturesManagerInteractionListener implements MapboxMap.OnGesturesManagerInteractionListener { + + @Override + public void onAddMapClickListener(MapboxMap.OnMapClickListener listener) { + mapGestureDetector.addOnMapClickListener(listener); + } + + @Override + public void onRemoveMapClickListener(MapboxMap.OnMapClickListener listener) { + mapGestureDetector.removeOnMapClickListener(listener); + } + + @Override + public void onAddMapLongClickListener(MapboxMap.OnMapLongClickListener listener) { + mapGestureDetector.addOnMapLongClickListener(listener); + } + + @Override + public void onRemoveMapLongClickListener(MapboxMap.OnMapLongClickListener listener) { + mapGestureDetector.removeOnMapLongClickListener(listener); + } + + @Override + public void onAddFlingListener(MapboxMap.OnFlingListener listener) { + mapGestureDetector.addOnFlingListener(listener); + } + + @Override + public void onRemoveFlingListener(MapboxMap.OnFlingListener listener) { + mapGestureDetector.removeOnFlingListener(listener); + } + + @Override + public void onAddMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.addOnMoveListener(listener); + } + + @Override + public void onRemoveMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.removeOnMoveListener(listener); + } + + @Override + public void onAddRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.addOnRotateListener(listener); + } + + @Override + public void onRemoveRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.removeOnRotateListener(listener); + } + + @Override + public void onAddScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.addOnScaleListener(listener); + } + + @Override + public void onRemoveScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.removeOnScaleListener(listener); + } + + @Override + public void onAddShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.addShoveListener(listener); + } + + @Override + public void onRemoveShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.removeShoveListener(listener); + } + + @Override + public AndroidGesturesManager getGesturesManager() { + return mapGestureDetector.getGesturesManager(); + } + + @Override + public void setGesturesManager(AndroidGesturesManager gesturesManager, boolean attachDefaultListeners, + boolean setDefaultMutuallyExclusives) { + mapGestureDetector.setGesturesManager( + getContext(), gesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); + } + + @Override + public void cancelAllVelocityAnimations() { + mapGestureDetector.cancelAnimators(); + } + } + + private class MapCallback implements OnDidFinishLoadingStyleListener, + OnDidFinishRenderingFrameListener, OnDidFinishLoadingMapListener, + OnCameraIsChangingListener, OnCameraDidChangeListener, OnDidFailLoadingMapListener { + + private final List onMapReadyCallbackList = new ArrayList<>(); + + MapCallback() { + addOnDidFinishLoadingStyleListener(this); + addOnDidFinishRenderingFrameListener(this); + addOnDidFinishLoadingMapListener(this); + addOnCameraIsChangingListener(this); + addOnCameraDidChangeListener(this); + addOnDidFailLoadingMapListener(this); + } + + void initialised() { + mapboxMap.onPreMapReady(); + onMapReady(); + mapboxMap.onPostMapReady(); + } + + /** + * Notify listeners, clear when done + */ + private void onMapReady() { + if (onMapReadyCallbackList.size() > 0) { + Iterator iterator = onMapReadyCallbackList.iterator(); + while (iterator.hasNext()) { + OnMapReadyCallback callback = iterator.next(); + if (callback != null) { + // null checking required for #13279 + callback.onMapReady(mapboxMap); + } + iterator.remove(); + } + } + } + + void addOnMapReadyCallback(OnMapReadyCallback callback) { + onMapReadyCallbackList.add(callback); + } + + void onDestroy() { + onMapReadyCallbackList.clear(); + removeOnDidFinishLoadingStyleListener(this); + removeOnDidFinishRenderingFrameListener(this); + removeOnDidFinishLoadingMapListener(this); + removeOnCameraIsChangingListener(this); + removeOnCameraDidChangeListener(this); + removeOnDidFailLoadingMapListener(this); + } + + @Override + public void onDidFinishLoadingStyle() { + if (mapboxMap != null) { + mapboxMap.onFinishLoadingStyle(); + } + } + + @Override + public void onDidFailLoadingMap(String errorMessage) { + if (mapboxMap != null) { + mapboxMap.onFailLoadingStyle(); + } + } + + @Override + public void onDidFinishRenderingFrame(boolean fully) { + if (mapboxMap != null) { + mapboxMap.onUpdateFullyRendered(); + } + } + + @Override + public void onDidFinishLoadingMap() { + if (mapboxMap != null) { + mapboxMap.onUpdateRegionChange(); + } + } + + @Override + public void onCameraIsChanging() { + if (mapboxMap != null) { + mapboxMap.onUpdateRegionChange(); + } + } + + @Override + public void onCameraDidChange(boolean animated) { + if (mapboxMap != null) { + mapboxMap.onUpdateRegionChange(); + } + } + } + + /** + * Click event hook for providing a custom attribution dialog manager. + */ + private static class AttributionClickListener implements OnClickListener { + + @NonNull + private final AttributionDialogManager defaultDialogManager; + private UiSettings uiSettings; + + private AttributionClickListener(@NonNull Context context, @NonNull MapboxMap mapboxMap) { + this.defaultDialogManager = new AttributionDialogManager(context, mapboxMap); + this.uiSettings = mapboxMap.getUiSettings(); + } + + @Override + public void onClick(View v) { + getDialogManager().onClick(v); + } + + public void onStop() { + getDialogManager().onStop(); + } + + private AttributionDialogManager getDialogManager() { + AttributionDialogManager customDialogManager = uiSettings.getAttributionDialogManager(); + if (customDialogManager != null) { + return uiSettings.getAttributionDialogManager(); + } else { + return defaultDialogManager; + } + } + } + + /** + * Sets the strict mode that will throw the {@link com.mapbox.mapboxsdk.MapStrictModeException} + * whenever the map would fail silently otherwise. + * + * @param strictModeEnabled true to enable the strict mode, false otherwise + */ + public static void setMapStrictModeEnabled(boolean strictModeEnabled) { + MapStrictMode.setStrictModeEnabled(strictModeEnabled); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java new file mode 100644 index 000000000..acd5093da --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -0,0 +1,2391 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.RectF; +import android.os.Bundle; +import android.support.annotation.FloatRange; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.Size; +import android.support.annotation.UiThread; +import android.text.TextUtils; +import android.view.View; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Geometry; +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; +import com.mapbox.mapboxsdk.annotations.Polyline; +import com.mapbox.mapboxsdk.annotations.PolylineOptions; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdate; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; +import com.mapbox.mapboxsdk.style.expressions.Expression; + +import java.util.ArrayList; +import java.util.List; + +/** + * The general class to interact with in the Android Mapbox SDK. It exposes the entry point for all + * methods related to the MapView. You cannot instantiate {@link MapboxMap} object directly, rather, + * you must obtain one from the getMapAsync() method on a MapFragment or MapView that you have + * added to your application. + *

+ * Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread. + *

+ */ +@UiThread +public final class MapboxMap { + + private static final String TAG = "Mbgl-MapboxMap"; + + private final NativeMap nativeMapView; + private final UiSettings uiSettings; + private final Projection projection; + private final Transform transform; + private final CameraChangeDispatcher cameraChangeDispatcher; + private final OnGesturesManagerInteractionListener onGesturesManagerInteractionListener; + private final List awaitingStyleGetters = new ArrayList<>(); + private final List developerAnimationStartedListeners; + + @Nullable + private Style.OnStyleLoaded styleLoadedCallback; + + private LocationComponent locationComponent; + private AnnotationManager annotationManager; + + @Nullable + private MapboxMap.OnFpsChangedListener onFpsChangedListener; + + @Nullable + private Style style; + + private boolean debugActive; + + MapboxMap(NativeMap map, Transform transform, UiSettings ui, Projection projection, + OnGesturesManagerInteractionListener listener, CameraChangeDispatcher cameraChangeDispatcher, + List developerAnimationStartedListeners) { + this.nativeMapView = map; + this.uiSettings = ui; + this.projection = projection; + this.transform = transform; + this.onGesturesManagerInteractionListener = listener; + this.cameraChangeDispatcher = cameraChangeDispatcher; + this.developerAnimationStartedListeners = developerAnimationStartedListeners; + } + + void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) { + transform.initialise(this, options); + uiSettings.initialise(context, options); + + // Map configuration + setDebugActive(options.getDebugActive()); + setApiBaseUrl(options); + setPrefetchesTiles(options); + } + + /** + * Get the Style of the map asynchronously. + */ + public void getStyle(@NonNull Style.OnStyleLoaded onStyleLoaded) { + if (style != null && style.isFullyLoaded()) { + onStyleLoaded.onStyleLoaded(style); + } else { + awaitingStyleGetters.add(onStyleLoaded); + } + } + + /** + * Get the Style of the map. + *

+ * Returns null when style is being loaded. + *

+ * + * @return the style of the map + */ + @Nullable + public Style getStyle() { + if (style == null || !style.isFullyLoaded()) { + return null; + } else { + return style; + } + } + + /** + * Called when the hosting Activity/Fragment onStart() method is called. + */ + void onStart() { + locationComponent.onStart(); + } + + /** + * Called when the hosting Activity/Fragment onStop() method is called. + */ + void onStop() { + locationComponent.onStop(); + } + + /** + * Called when the hosting Activity/Fragment is going to be destroyed and map state needs to be saved. + * + * @param outState the bundle to save the state to. + */ + void onSaveInstanceState(@NonNull Bundle outState) { + outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition()); + outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, isDebugActive()); + uiSettings.onSaveInstanceState(outState); + } + + /** + * Called when the hosting Activity/Fragment is recreated and map state needs to be restored. + * + * @param savedInstanceState the bundle containing the saved state + */ + void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { + final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION); + + uiSettings.onRestoreInstanceState(savedInstanceState); + + if (cameraPosition != null) { + moveCamera(CameraUpdateFactory.newCameraPosition( + new CameraPosition.Builder(cameraPosition).build()) + ); + } + + nativeMapView.setDebug(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE)); + } + + /** + * Called when the hosting Activity/Fragment onDestroy()/onDestroyView() method is called. + */ + void onDestroy() { + locationComponent.onDestroy(); + if (style != null) { + style.clear(); + } + cameraChangeDispatcher.onDestroy(); + } + + /** + * Called before the OnMapReadyCallback is invoked. + */ + void onPreMapReady() { + transform.invalidateCameraPosition(); + annotationManager.reloadMarkers(); + annotationManager.adjustTopOffsetPixels(this); + } + + /** + * Called when the OnMapReadyCallback has finished executing. + *

+ * Invalidation of the camera position is required to update the added components in + * OnMapReadyCallback with the correct transformation. + *

+ */ + void onPostMapReady() { + transform.invalidateCameraPosition(); + } + + /** + * Called when the map finished loading a style. + */ + void onFinishLoadingStyle() { + notifyStyleLoaded(); + } + + /** + * Called when the map failed loading a style. + */ + void onFailLoadingStyle() { + styleLoadedCallback = null; + } + + /** + * Called when the region is changing or has changed. + */ + void onUpdateRegionChange() { + annotationManager.update(); + } + + /** + * Called when the map frame is fully rendered. + */ + void onUpdateFullyRendered() { + CameraPosition cameraPosition = transform.invalidateCameraPosition(); + if (cameraPosition != null) { + uiSettings.update(cameraPosition); + } + } + + /** + * Experimental feature. Do not use. + */ + long getNativeMapPtr() { + return nativeMapView.getNativePtr(); + } + + // Style + + /** + * 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.setPrefetchTiles(enable); + } + + /** + * Check whether tile pre-fetching is enabled or not. + * + * @return true if enabled + * @see MapboxMap#setPrefetchesTiles(boolean) + */ + public boolean getPrefetchesTiles() { + return nativeMapView.getPrefetchTiles(); + } + + // + // MinZoom + // + + /** + *

+ * Sets the minimum zoom level the map can be displayed at. + *

+ * + * @param minZoom The new minimum zoom level. + */ + public void setMinZoomPreference( + @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { + transform.setMinZoom(minZoom); + } + + /** + *

+ * Gets the minimum zoom level the map can be displayed at. + *

+ * + * @return The minimum zoom level. + */ + public double getMinZoomLevel() { + return transform.getMinZoom(); + } + + // + // MaxZoom + // + + /** + *

+ * Sets the maximum zoom level the map can be displayed at. + *

+ *

+ * The default maximum zoomn level is 22. The upper bound for this value is 25.5. + *

+ * + * @param maxZoom The new maximum zoom level. + */ + public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, + to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { + transform.setMaxZoom(maxZoom); + } + + /** + *

+ * Gets the maximum zoom level the map can be displayed at. + *

+ * + * @return The maximum zoom level. + */ + public double getMaxZoomLevel() { + return transform.getMaxZoom(); + } + + // + // UiSettings + // + + /** + * Gets the user interface settings for the map. + * + * @return the UiSettings associated with this map + */ + @NonNull + public UiSettings getUiSettings() { + return uiSettings; + } + + // + // Projection + // + + /** + * Get the Projection object that you can use to convert between screen coordinates and latitude/longitude + * coordinates. + * + * @return the Projection associated with this map + */ + @NonNull + public Projection getProjection() { + return projection; + } + + // + // Camera API + // + + /** + * Cancels ongoing animations. + *

+ * This invokes the {@link CancelableCallback} for ongoing camera updates. + *

+ */ + public void cancelTransitions() { + transform.cancelTransitions(); + } + + /** + * Gets the current position of the camera. + * The CameraPosition returned is a snapshot of the current position, and will not automatically update when the + * camera moves. + * + * @return The current position of the Camera. + */ + @NonNull + public final CameraPosition getCameraPosition() { + return transform.getCameraPosition(); + } + + /** + * Repositions the camera according to the cameraPosition. + * The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position. + * See CameraUpdateFactory for a set of updates. + * + * @param cameraPosition the camera position to set + */ + public void setCameraPosition(@NonNull CameraPosition cameraPosition) { + moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), null); + } + + /** + * Repositions the camera according to the instructions defined in the update. + * The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position. + * See CameraUpdateFactory for a set of updates. + * + * @param update The change that should be applied to the camera. + */ + public final void moveCamera(@NonNull CameraUpdate update) { + moveCamera(update, null); + } + + /** + * Repositions the camera according to the instructions defined in the update. + * The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position. + * See CameraUpdateFactory for a set of updates. + * + * @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 + */ + public final void moveCamera(@NonNull final CameraUpdate update, + @Nullable final MapboxMap.CancelableCallback callback) { + notifyDeveloperAnimationListeners(); + transform.moveCamera(MapboxMap.this, update, callback); + } + + /** + * Gradually move the camera by the default duration, zoom will not be affected unless specified + * within {@link CameraUpdate}. If {@link #getCameraPosition()} is called during the animation, + * it will return the current location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void easeCamera(@NonNull CameraUpdate update) { + easeCamera(update, MapboxConstants.ANIMATION_DURATION); + } + + /** + * Gradually move the camera by the default duration, zoom will not be affected unless specified + * within {@link CameraUpdate}. If {@link #getCameraPosition()} is called during the animation, + * it will return the current location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void easeCamera(@NonNull CameraUpdate update, @Nullable final MapboxMap.CancelableCallback callback) { + easeCamera(update, MapboxConstants.ANIMATION_DURATION, callback); + } + + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. If {@link #getCameraPosition()} is called + * during the animation, it will return the current location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void easeCamera(@NonNull CameraUpdate update, int durationMs) { + easeCamera(update, durationMs, null); + } + + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void easeCamera(@NonNull CameraUpdate update, int durationMs, + @Nullable final MapboxMap.CancelableCallback callback) { + easeCamera(update, durationMs, true, callback); + } + + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param easingInterpolator True for easing interpolator, false for linear. + */ + public final void easeCamera(@NonNull CameraUpdate update, int durationMs, boolean easingInterpolator) { + easeCamera(update, durationMs, easingInterpolator, null); + } + + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param easingInterpolator True for easing interpolator, false for linear. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + */ + public final void easeCamera(@NonNull final CameraUpdate update, + final int durationMs, + final boolean easingInterpolator, + @Nullable final MapboxMap.CancelableCallback callback) { + if (durationMs <= 0) { + throw new IllegalArgumentException("Null duration passed into easeCamera"); + } + notifyDeveloperAnimationListeners(); + transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback); + } + + /** + * Animate the camera to a new location defined within {@link CameraUpdate} using a transition + * animation that evokes powered flight. The animation will last the default amount of time. + * During the animation, a call to {@link #getCameraPosition()} returns an intermediate location + * of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void animateCamera(@NonNull CameraUpdate update) { + animateCamera(update, MapboxConstants.ANIMATION_DURATION, null); + } + + /** + * Animate the camera to a new location defined within {@link CameraUpdate} using a transition + * animation that evokes powered flight. The animation will last the default amount of time. A + * callback can be used to be notified when animating the camera stops. During the animation, a + * call to {@link #getCameraPosition()} returns an intermediate location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param callback The callback to invoke from the main thread when the animation stops. If the + * animation completes normally, onFinish() is called; otherwise, onCancel() is + * called. Do not update or animate the camera from within onCancel(). + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void animateCamera(@NonNull CameraUpdate update, @Nullable MapboxMap.CancelableCallback callback) { + animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback); + } + + /** + * Animate the camera to a new location defined within {@link CameraUpdate} using a transition + * animation that evokes powered flight. The animation will last a specified amount of time + * given in milliseconds. During the animation, a call to {@link #getCameraPosition()} returns + * an intermediate location of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void animateCamera(@NonNull CameraUpdate update, int durationMs) { + animateCamera(update, durationMs, null); + } + + /** + * Animate the camera to a new location defined within {@link CameraUpdate} using a transition + * animation that evokes powered flight. The animation will last a specified amount of time + * given in milliseconds. A callback can be used to be notified when animating the camera stops. + * During the animation, a call to {@link #getCameraPosition()} returns an intermediate location + * of the camera in flight. + * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or animate the camera from within onCancel(). If a callback + * isn't required, leave it as null. + * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. + */ + public final void animateCamera(@NonNull final CameraUpdate update, final int durationMs, + @Nullable final MapboxMap.CancelableCallback callback) { + if (durationMs <= 0) { + throw new IllegalArgumentException("Null duration passed into animateCamera"); + } + notifyDeveloperAnimationListeners(); + transform.animateCamera(MapboxMap.this, update, durationMs, callback); + } + + /** + * Scrolls the camera over the map, shifting the center of view by the specified number of pixels in the x and y + * directions. + * + * @param x Amount of pixels to scroll to in x direction + * @param y Amount of pixels to scroll to in y direction + */ + public void scrollBy(float x, float y) { + scrollBy(x, y, 0); + } + + /** + * Scrolls the camera over the map, shifting the center of view by the specified number of pixels in the x and y + * directions. + * + * @param x Amount of pixels to scroll to in x direction + * @param y Amount of pixels to scroll to in y direction + * @param duration Amount of time the scrolling should take + */ + public void scrollBy(float x, float y, long duration) { + notifyDeveloperAnimationListeners(); + nativeMapView.moveBy(x, y, duration); + } + + // + // Reset North + // + + /** + * Resets the map view to face north. + */ + public void resetNorth() { + notifyDeveloperAnimationListeners(); + transform.resetNorth(); + } + + /** + * 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) { + notifyDeveloperAnimationListeners(); + transform.setBearing(bearing, focalX, focalY, duration); + } + + /** + * Returns the measured height of the Map. + * + * @return the height of the map + */ + public float getHeight() { + return projection.getHeight(); + } + + /** + * Returns the measured width of the Map. + * + * @return the width of the map + */ + public float getWidth() { + return projection.getWidth(); + } + + // + // Offline + // + + /** + * Loads a new style from the specified offline region definition and moves the map camera to that region. + * + * @param definition the offline region definition + * @see OfflineRegionDefinition + */ + public void setOfflineRegionDefinition(@NonNull OfflineRegionDefinition definition) { + setOfflineRegionDefinition(definition, null); + } + + /** + * Loads a new style from the specified offline region definition and moves the map camera to that region. + * + * @param definition the offline region definition + * @param callback the callback to be invoked when the style has loaded + * @see OfflineRegionDefinition + */ + public void setOfflineRegionDefinition(@NonNull OfflineRegionDefinition definition, + @Nullable Style.OnStyleLoaded callback) { + double minZoom = definition.getMinZoom(); + double maxZoom = definition.getMaxZoom(); + CameraPosition cameraPosition = new CameraPosition.Builder() + .target(definition.getBounds().getCenter()) + .zoom(minZoom) + .build(); + moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + setMinZoomPreference(minZoom); + setMaxZoomPreference(maxZoom); + setStyle(new Style.Builder().fromUri(definition.getStyleURL()), callback); + } + + // + // Debug + // + + /** + * Returns whether the map debug information is currently shown. + * + * @return If true, map debug information is currently shown. + */ + public boolean isDebugActive() { + return debugActive; + } + + /** + *

+ * Changes whether the map debug information is shown. + *

+ * The default value is false. + * + * @param debugActive If true, map debug information is shown. + */ + public void setDebugActive(boolean debugActive) { + this.debugActive = debugActive; + nativeMapView.setDebug(debugActive); + } + + /** + *

+ * Cycles through the map debug options. + *

+ * The value of isDebugActive reflects whether there are + * any map debug options enabled or disabled. + * + * @see #isDebugActive() + */ + public void cycleDebugOptions() { + nativeMapView.cycleDebugOptions(); + this.debugActive = nativeMapView.getDebug(); + } + + // + // API endpoint config + // + + private void setApiBaseUrl(@NonNull MapboxMapOptions options) { + String apiBaseUrl = options.getApiBaseUrl(); + if (!TextUtils.isEmpty(apiBaseUrl)) { + nativeMapView.setApiBaseUrl(apiBaseUrl); + } + } + + // + // Styling + // + + /** + * Loads a new map style from the specified bundled style. + *

+ * This method is asynchronous and will return before the style finishes loading. + * If you wish to wait for the map to finish loading, listen to the {@link MapView.OnDidFinishLoadingStyleListener} + * callback or use the {@link #setStyle(String, Style.OnStyleLoaded)} method instead. + *

+ * 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.OnDidFailLoadingMapListener} callback + * will be triggered. + * + * @param style The bundled style + * @see Style + */ + public void setStyle(@Style.StyleUrl String style) { + this.setStyle(style, null); + } + + /** + * Loads a new map style from the specified bundled style. + *

+ * 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.OnDidFailLoadingMapListener} callback + * will be triggered. + *

+ * + * @param style The bundled style + * @param callback The callback to be invoked when the style has loaded + * @see Style + */ + public void setStyle(@Style.StyleUrl String style, final Style.OnStyleLoaded callback) { + this.setStyle(new Style.Builder().fromUri(style), callback); + } + + /** + * Loads a new map style from the specified builder. + *

+ * If the builder fails to load, the map view will become blank. An error message will be logged in the Android logcat + * and {@link MapView.OnDidFailLoadingMapListener} callback will be triggered. If you wish to wait for the map to + * finish loading, listen to the {@link MapView.OnDidFinishLoadingStyleListener} callback or use the + * {@link #setStyle(String, Style.OnStyleLoaded)} instead. + *

+ * + * @param builder The style builder + * @see Style + */ + public void setStyle(Style.Builder builder) { + this.setStyle(builder, null); + } + + /** + * Loads a new map style from the specified builder. + *

+ * If the builder fails to load, the map view will become blank. An error message will be logged in the Android logcat + * and {@link MapView.OnDidFailLoadingMapListener} callback will be triggered. + *

+ * + * @param builder The style builder + * @param callback The callback to be invoked when the style has loaded + * @see Style + */ + public void setStyle(Style.Builder builder, final Style.OnStyleLoaded callback) { + styleLoadedCallback = callback; + locationComponent.onStartLoadingMap(); + if (style != null) { + style.clear(); + } + + style = builder.build(nativeMapView); + if (!TextUtils.isEmpty(builder.getUri())) { + nativeMapView.setStyleUri(builder.getUri()); + } else if (!TextUtils.isEmpty(builder.getJson())) { + nativeMapView.setStyleJson(builder.getJson()); + } else { + // user didn't provide a `from` component, load a blank style instead + nativeMapView.setStyleJson(Style.EMPTY_JSON); + } + } + + void notifyStyleLoaded() { + if (nativeMapView.isDestroyed()) { + return; + } + + if (style != null) { + style.onDidFinishLoadingStyle(); + locationComponent.onFinishLoadingStyle(); + + // notify the listener provided with the style setter + if (styleLoadedCallback != null) { + styleLoadedCallback.onStyleLoaded(style); + } + + // notify style getters + for (Style.OnStyleLoaded styleGetter : awaitingStyleGetters) { + styleGetter.onStyleLoaded(style); + } + } else { + MapStrictMode.strictModeViolation("No style to provide."); + } + styleLoadedCallback = null; + awaitingStyleGetters.clear(); + } + + // + // Annotations + // + + /** + *

+ * Adds a marker to this map. + *

+ * The marker's icon is rendered on the map at the location {@code Marker.position}. + * If {@code Marker.title} is defined, the map shows an info box with the marker's title and snippet. + * + * @param markerOptions A marker options object that defines how to render the marker + * @return The {@code Marker} that was added to the map + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public Marker addMarker(@NonNull MarkerOptions markerOptions) { + return annotationManager.addMarker(markerOptions, this); + } + + /** + *

+ * Adds a marker to this map. + *

+ * The marker's icon is rendered on the map at the location {@code Marker.position}. + * If {@code Marker.title} is defined, the map shows an info box with the marker's title and snippet. + * + * @param markerOptions A marker options object that defines how to render the marker + * @return The {@code Marker} that was added to the map + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public Marker addMarker(@NonNull BaseMarkerOptions markerOptions) { + return annotationManager.addMarker(markerOptions, this); + } + + /** + *

+ * Adds multiple markers to this map. + *

+ * The marker's icon is rendered on the map at the location {@code Marker.position}. + * If {@code Marker.title} is defined, the map shows an info box with the marker's title and snippet. + * + * @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 + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List addMarkers(@NonNull List markerOptionsList) { + return annotationManager.addMarkers(markerOptionsList, this); + } + + /** + *

+ * Updates a marker on this map. Does nothing if the marker isn't already added. + *

+ * + * @param updatedMarker An updated marker object + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void updateMarker(@NonNull Marker updatedMarker) { + annotationManager.updateMarker(updatedMarker, this); + } + + /** + * Adds a polyline to this map. + * + * @param polylineOptions A polyline options object that defines how to render the polyline + * @return The {@code Polyine} that was added to the map + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public Polyline addPolyline(@NonNull PolylineOptions polylineOptions) { + return annotationManager.addPolyline(polylineOptions, this); + } + + /** + * Adds multiple polylines to this map. + * + * @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. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List addPolylines(@NonNull List polylineOptionsList) { + return annotationManager.addPolylines(polylineOptionsList, this); + } + + /** + * Update a polyline on this map. + * + * @param polyline An updated polyline object. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void updatePolyline(@NonNull Polyline polyline) { + annotationManager.updatePolyline(polyline); + } + + /** + * Adds a polygon to this map. + * + * @param polygonOptions A polygon options object that defines how to render the polygon. + * @return The {@code Polygon} that was added to the map. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public Polygon addPolygon(@NonNull PolygonOptions polygonOptions) { + return annotationManager.addPolygon(polygonOptions, this); + } + + /** + * Adds multiple polygons to this map. + * + * @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 + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List addPolygons(@NonNull List polygonOptionsList) { + return annotationManager.addPolygons(polygonOptionsList, this); + } + + /** + * Update a polygon on this map. + * + * @param polygon An updated polygon object + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void updatePolygon(@NonNull Polygon polygon) { + annotationManager.updatePolygon(polygon); + } + + /** + *

+ * Convenience method for removing a Marker from the map. + *

+ * Calls removeAnnotation() internally. + * + * @param marker Marker to remove + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removeMarker(@NonNull Marker marker) { + annotationManager.removeAnnotation(marker); + } + + /** + *

+ * Convenience method for removing a Polyline from the map. + *

+ * Calls removeAnnotation() internally. + * + * @param polyline Polyline to remove + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removePolyline(@NonNull Polyline polyline) { + annotationManager.removeAnnotation(polyline); + } + + /** + *

+ * Convenience method for removing a Polygon from the map. + *

+ * Calls removeAnnotation() internally. + * + * @param polygon Polygon to remove + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removePolygon(@NonNull Polygon polygon) { + annotationManager.removeAnnotation(polygon); + } + + /** + * Removes an annotation from the map. + * + * @param annotation The annotation object to remove. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removeAnnotation(@NonNull Annotation annotation) { + annotationManager.removeAnnotation(annotation); + } + + /** + * Removes an annotation from the map + * + * @param id The identifier associated to the annotation to be removed + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removeAnnotation(long id) { + annotationManager.removeAnnotation(id); + } + + /** + * Removes multiple annotations from the map. + * + * @param annotationList A list of annotation objects to remove. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removeAnnotations(@NonNull List annotationList) { + annotationManager.removeAnnotations(annotationList); + } + + /** + * Removes all annotations from the map. + * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void removeAnnotations() { + annotationManager.removeAnnotations(); + } + + /** + * Removes all markers, polylines, polygons, overlays, etc from the map. + * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void clear() { + annotationManager.removeAnnotations(); + } + + /** + * Return a annotation based on its id. + * + * @param id the id used to look up an annotation + * @return An annotation with a matched id, null is returned if no match was found + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @Nullable + public Annotation getAnnotation(long id) { + return annotationManager.getAnnotation(id); + } + + /** + * Returns a list of all the annotations on the map. + * + * @return A list of all the annotation objects. The returned object is a copy so modifying this + * list will not update the map + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List getAnnotations() { + return annotationManager.getAnnotations(); + } + + /** + * Returns a list of all the markers on the map. + * + * @return A list of all the markers objects. The returned object is a copy so modifying this + * list will not update the map. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List getMarkers() { + return annotationManager.getMarkers(); + } + + /** + * Returns a list of all the polygons on the map. + * + * @return A list of all the polygon objects. The returned object is a copy so modifying this + * list will not update the map. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List getPolygons() { + return annotationManager.getPolygons(); + } + + /** + * Returns a list of all the polylines on the map. + * + * @return A list of all the polylines objects. The returned object is a copy so modifying this + * list will not update the map. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List getPolylines() { + return annotationManager.getPolylines(); + } + + /** + * Sets a callback that's invoked when the user clicks on a marker. + * + * @param listener The callback that's invoked when the user clicks on a marker. + * To unset the callback, use null. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + 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. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + 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. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void setOnPolylineClickListener(@Nullable OnPolylineClickListener listener) { + annotationManager.setOnPolylineClickListener(listener); + } + + /** + *

+ * Selects a marker. The selected marker will have it's info window opened. + * Any other open info windows will be closed unless isAllowConcurrentMultipleOpenInfoWindows() + * is true. + *

+ * Selecting an already selected marker will have no effect. + * + * @param marker The marker to select. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void selectMarker(@NonNull Marker marker) { + if (marker == null) { + Logger.w(TAG, "marker was null, so just returning"); + return; + } + annotationManager.selectMarker(marker); + } + + /** + * Deselects any currently selected marker. All markers will have it's info window closed. + * + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void deselectMarkers() { + annotationManager.deselectMarkers(); + } + + /** + * Deselects a currently selected marker. The selected marker will have it's info window closed. + * + * @param marker the marker to deselect + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void deselectMarker(@NonNull Marker marker) { + annotationManager.deselectMarker(marker); + } + + /** + * Gets the currently selected marker. + * + * @return The currently selected marker. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @NonNull + public List getSelectedMarkers() { + return annotationManager.getSelectedMarkers(); + } + + // + // InfoWindow + // + + /** + *

+ * Sets a custom renderer for the contents of info window. + *

+ * When set your callback is invoked when an info window is about to be shown. By returning + * a custom {@link View}, the default info window will be replaced. + * + * @param infoWindowAdapter The callback to be invoked when an info window will be shown. + * To unset the callback, use null. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void setInfoWindowAdapter(@Nullable InfoWindowAdapter infoWindowAdapter) { + annotationManager.getInfoWindowManager().setInfoWindowAdapter(infoWindowAdapter); + } + + /** + * Gets the callback to be invoked when an info window will be shown. + * + * @return The callback to be invoked when an info window will be shown. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + @Nullable + public InfoWindowAdapter getInfoWindowAdapter() { + return annotationManager.getInfoWindowManager().getInfoWindowAdapter(); + } + + /** + * Changes whether the map allows concurrent multiple infowindows to be shown. + * + * @param allow If true, map allows concurrent multiple infowindows to be shown. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { + annotationManager.getInfoWindowManager().setAllowConcurrentMultipleOpenInfoWindows(allow); + } + + /** + * Returns whether the map allows concurrent multiple infowindows to be shown. + * + * @return If true, map allows concurrent multiple infowindows to be shown. + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public boolean isAllowConcurrentMultipleOpenInfoWindows() { + return annotationManager.getInfoWindowManager().isAllowConcurrentMultipleOpenInfoWindows(); + } + + // + // LatLngBounds + // + + /** + * Sets a LatLngBounds that constraints map transformations to this bounds. + *

+ * Set to null to clear current bounds, newly set bounds will override previously set bounds. + *

+ * + * @param latLngBounds the bounds to constrain the map with + */ + public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) { + nativeMapView.setLatLngBounds(latLngBounds); + } + + + /** + * Get a camera position that fits a provided bounds and the current camera tilt and bearing. + * + * @param latLngBounds the bounds to set the map with + * @return the camera position that fits the bounds + */ + @Nullable + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds) { + // we use current camera tilt value to provide expected transformations as #11993 + return getCameraForLatLngBounds(latLngBounds, new int[] {0, 0, 0, 0}); + } + + + /** + * Get a camera position that fits a provided bounds and padding and the current camera tilt and bearing. + * + * @param latLngBounds the bounds to set the map with + * @param padding the padding to apply to the bounds + * @return the camera position that fits the bounds and padding + */ + @Nullable + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, + @NonNull @Size(value = 4) int[] padding) { + // we use current camera tilt/bearing value to provide expected transformations as #11993 + return getCameraForLatLngBounds(latLngBounds, padding, transform.getRawBearing(), transform.getTilt()); + } + + + /** + * Get a camera position that fits a provided bounds, bearing and tilt. + * + * @param latLngBounds the bounds to set the map with + * @param bearing the bearing to transform the camera position with + * @param tilt to transform the camera position with + * @return the camera position that fits the bounds and given bearing and tilt + */ + @Nullable + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, + @FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, + to = MapboxConstants.MAXIMUM_DIRECTION) double bearing, + @FloatRange(from = MapboxConstants.MINIMUM_TILT, + to = MapboxConstants.MAXIMUM_TILT) double tilt) { + return getCameraForLatLngBounds(latLngBounds, new int[] {0, 0, 0, 0}, bearing, tilt); + } + + + /** + * Get a camera position that fits a provided bounds, padding, bearing and tilt. + * + * @param latLngBounds the bounds to set the map with + * @param padding the padding to apply to the bounds + * @param bearing the bearing to transform the camera position with + * @param tilt to transform the camera position with + * @return the camera position that fits the bounds, bearing and tilt + */ + @Nullable + public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, + @NonNull @Size(value = 4) int[] padding, + @FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, + to = MapboxConstants.MAXIMUM_DIRECTION) double bearing, + @FloatRange(from = MapboxConstants.MINIMUM_TILT, + to = MapboxConstants.MAXIMUM_TILT) double tilt) { + return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding, bearing, tilt); + } + + /** + * Get a camera position that fits a provided shape. + * + * @param geometry the geometry to wraps the map with + * @return the camera position that fits the geometry inside + */ + @Nullable + public CameraPosition getCameraForGeometry(@NonNull Geometry geometry) { + // we use current camera tilt value to provide expected transformations as #11993 + return getCameraForGeometry(geometry, new int[] {0, 0, 0, 0}); + } + + /** + * Get a camera position that fits a provided shape and padding. + * + * @param geometry the geometry to wraps the map with + * @param padding the padding to apply to the bounds + * @return the camera position that fits the geometry inside and padding + */ + @Nullable + public CameraPosition getCameraForGeometry(@NonNull Geometry geometry, + @NonNull @Size(value = 4) int[] padding) { + // we use current camera tilt/bearing value to provide expected transformations as #11993 + return getCameraForGeometry(geometry, padding, transform.getBearing(), transform.getTilt()); + } + + /** + * Get a camera position that fits a provided shape with a given bearing and tilt. + * + * @param geometry the geometry to wraps the map with + * @param bearing the bearing at which to compute the geometry's bounds + * @param tilt the tilt at which to compute the geometry's bounds + * @return the camera position that the geometry inside with bearing and tilt + */ + @Nullable + public CameraPosition getCameraForGeometry(@NonNull Geometry geometry, + @FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, + to = MapboxConstants.MAXIMUM_DIRECTION) double bearing, + @FloatRange(from = MapboxConstants.MINIMUM_TILT, + to = MapboxConstants.MAXIMUM_TILT) double tilt) { + return getCameraForGeometry(geometry, new int[] {0, 0, 0, 0}, bearing, tilt); + } + + /** + * Get a camera position that fits a provided shape with a given padding, bearing and tilt. + * + * @param geometry the geometry to wraps the map with + * @param padding the padding to apply to the bounds + * @param bearing the bearing at which to compute the geometry's bounds + * @param tilt the tilt at which to compute the geometry's bounds + * @return the camera position that fits the geometry inside with padding, bearing and tilt + */ + @Nullable + public CameraPosition getCameraForGeometry(@NonNull Geometry geometry, + @NonNull @Size(value = 4) int[] padding, + @FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, + to = MapboxConstants.MAXIMUM_DIRECTION) double bearing, + @FloatRange(from = MapboxConstants.MINIMUM_TILT, + to = MapboxConstants.MAXIMUM_TILT) double tilt) { + return nativeMapView.getCameraForGeometry(geometry, padding, bearing, tilt); + } + + // + // Padding + // + + /** + *

+ * Sets the distance from the edges of the map view's frame to the edges of the map + * view's logical viewport. + *

+ *

+ * When the value of this property is equal to {0,0,0,0}, viewport + * properties such as 'centerCoordinate' assume a viewport that matches the map + * view's frame. Otherwise, those properties are inset, excluding part of the + * frame from the viewport. For instance, if the only the top edge is inset, the + * map center is effectively shifted downward. + *

+ *

+ * This method sets the padding "lazily". + * This means that the padding is going to be applied with the next camera transformation. + * To apply the padding immediately use {@link CameraPosition.Builder#padding(double, double, double, double)} + * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)}. + *

+ * + * @param left The left margin in pixels. + * @param top The top margin in pixels. + * @param right The right margin in pixels. + * @param bottom The bottom margin in pixels. + * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)} + * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead. + */ + @Deprecated + public void setPadding(int left, int top, int right, int bottom) { + // TODO padding should be passed as doubles + projection.setContentPadding(new int[] {left, top, right, bottom}); + uiSettings.invalidate(); + } + + /** + * Returns the current configured content padding on map view. This might return the currently visible padding + * or the padding cached but not yet applied by {@link #setPadding(int, int, int, int)}. + * + * @return An array with length 4 in the LTRB order. + * @deprecated Use {@link CameraPosition#padding} instead. + */ + @Deprecated + @NonNull + public int[] getPadding() { + // TODO this should return double[] (semver major change) + return projection.getContentPadding(); + } + + // + // Map events + // + + /** + * Adds a callback that is invoked when camera movement has ended. + * + * @param listener the listener to notify + */ + public void addOnCameraIdleListener(@NonNull 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(@NonNull OnCameraIdleListener listener) { + cameraChangeDispatcher.removeOnCameraIdleListener(listener); + } + + /** + * Adds a callback that is invoked when camera movement was cancelled. + * + * @param listener the listener to notify + */ + public void addOnCameraMoveCancelListener(@NonNull 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(@NonNull OnCameraMoveCanceledListener listener) { + cameraChangeDispatcher.removeOnCameraMoveCancelListener(listener); + } + + /** + * Adds a callback that is invoked when camera movement has started. + * + * @param listener the listener to notify + */ + public void addOnCameraMoveStartedListener(@NonNull 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(@NonNull OnCameraMoveStartedListener listener) { + cameraChangeDispatcher.removeOnCameraMoveStartedListener(listener); + } + + /** + * Adds a callback that is invoked when camera position changes. + * + * @param listener the listener to notify + */ + public void addOnCameraMoveListener(@NonNull OnCameraMoveListener listener) { + cameraChangeDispatcher.addOnCameraMoveListener(listener); + } + + /** + * Removes a callback that is invoked when camera position changes. + * + * @param listener the listener to remove + */ + public void removeOnCameraMoveListener(@NonNull 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. + */ + public void setOnFpsChangedListener(@Nullable OnFpsChangedListener listener) { + onFpsChangedListener = listener; + nativeMapView.setOnFpsChangedListener(listener); + } + + // used by MapView + @Nullable + OnFpsChangedListener getOnFpsChangedListener() { + return onFpsChangedListener; + } + + /** + * Adds a callback that's invoked when the map is flinged. + * + * @param listener The callback that's invoked when the map is flinged. + */ + public void addOnFlingListener(@NonNull OnFlingListener listener) { + onGesturesManagerInteractionListener.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. + */ + public void removeOnFlingListener(@NonNull OnFlingListener listener) { + onGesturesManagerInteractionListener.onRemoveFlingListener(listener); + } + + /** + * Adds a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void addOnMoveListener(@NonNull OnMoveListener listener) { + onGesturesManagerInteractionListener.onAddMoveListener(listener); + } + + /** + * Removes a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void removeOnMoveListener(@NonNull OnMoveListener listener) { + onGesturesManagerInteractionListener.onRemoveMoveListener(listener); + } + + /** + * Adds a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void addOnRotateListener(@NonNull OnRotateListener listener) { + onGesturesManagerInteractionListener.onAddRotateListener(listener); + } + + /** + * Removes a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void removeOnRotateListener(@NonNull OnRotateListener listener) { + onGesturesManagerInteractionListener.onRemoveRotateListener(listener); + } + + /** + * Adds a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void addOnScaleListener(@NonNull OnScaleListener listener) { + onGesturesManagerInteractionListener.onAddScaleListener(listener); + } + + /** + * Removes a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void removeOnScaleListener(@NonNull OnScaleListener listener) { + onGesturesManagerInteractionListener.onRemoveScaleListener(listener); + } + + /** + * Adds a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void addOnShoveListener(@NonNull OnShoveListener listener) { + onGesturesManagerInteractionListener.onAddShoveListener(listener); + } + + /** + * Remove a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void removeOnShoveListener(@NonNull OnShoveListener listener) { + onGesturesManagerInteractionListener.onRemoveShoveListener(listener); + } + + /** + * Sets a custom {@link AndroidGesturesManager} to handle {@link android.view.MotionEvent}s + * registered by the {@link MapView}. + * + * @param androidGesturesManager Gestures manager that interprets gestures based on the motion events. + * @param attachDefaultListeners If true, pre-defined listeners will be attach + * to change map based on {@link AndroidGesturesManager} callbacks. + * @param setDefaultMutuallyExclusives If true, pre-defined mutually exclusive gesture sets + * will be added to the passed gestures manager. + * @see mapbox-gestures-android library + */ + public void setGesturesManager(@NonNull AndroidGesturesManager androidGesturesManager, boolean attachDefaultListeners, + boolean setDefaultMutuallyExclusives) { + onGesturesManagerInteractionListener.setGesturesManager( + androidGesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); + } + + /** + * Get current {@link AndroidGesturesManager} that handles {@link android.view.MotionEvent}s + * registered by the {@link MapView} + * + * @return Current gestures manager. + */ + @NonNull + public AndroidGesturesManager getGesturesManager() { + return onGesturesManagerInteractionListener.getGesturesManager(); + } + + /** + * Interrupts any ongoing gesture velocity animations. + */ + public void cancelAllVelocityAnimations() { + onGesturesManagerInteractionListener.cancelAllVelocityAnimations(); + } + + /** + * 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. + */ + public void addOnMapClickListener(@NonNull OnMapClickListener listener) { + onGesturesManagerInteractionListener.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. + */ + public void removeOnMapClickListener(@NonNull OnMapClickListener listener) { + onGesturesManagerInteractionListener.onRemoveMapClickListener(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. + */ + public void addOnMapLongClickListener(@NonNull OnMapLongClickListener listener) { + onGesturesManagerInteractionListener.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. + */ + public void removeOnMapLongClickListener(@NonNull OnMapLongClickListener listener) { + onGesturesManagerInteractionListener.onRemoveMapLongClickListener(listener); + } + + /** + * Sets a callback that's invoked when the user clicks on an info window. + * + * @param listener The callback that's invoked when the user clicks on an info window. + * To unset the callback, use null. + */ + public void setOnInfoWindowClickListener(@Nullable OnInfoWindowClickListener listener) { + annotationManager.getInfoWindowManager().setOnInfoWindowClickListener(listener); + } + + /** + * Return the InfoWindow click listener + * + * @return Current active InfoWindow Click Listener + */ + @Nullable + public OnInfoWindowClickListener getOnInfoWindowClickListener() { + return annotationManager.getInfoWindowManager().getOnInfoWindowClickListener(); + } + + /** + * Sets a callback that's invoked when a marker's info window is long pressed. + * + * @param listener The callback that's invoked when a marker's info window is long pressed. To unset the callback, + * use null. + */ + public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener + listener) { + annotationManager.getInfoWindowManager().setOnInfoWindowLongClickListener(listener); + } + + /** + * Return the InfoWindow long click listener + * + * @return Current active InfoWindow long Click Listener + */ + @Nullable + public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { + return annotationManager.getInfoWindowManager().getOnInfoWindowLongClickListener(); + } + + /** + * Set an callback to be invoked when an InfoWindow closes. + * + * @param listener callback invoked when an InfoWindow closes + */ + public void setOnInfoWindowCloseListener(@Nullable OnInfoWindowCloseListener listener) { + annotationManager.getInfoWindowManager().setOnInfoWindowCloseListener(listener); + } + + /** + * Return the InfoWindow close listener + * + * @return Current active InfoWindow Close Listener + */ + @Nullable + public OnInfoWindowCloseListener getOnInfoWindowCloseListener() { + return annotationManager.getInfoWindowManager().getOnInfoWindowCloseListener(); + } + + // + // Invalidate + // + + /** + * Takes a snapshot of the map. + * + * @param callback Callback method invoked when the snapshot is taken. + */ + public void snapshot(@NonNull SnapshotReadyCallback callback) { + nativeMapView.addSnapshotCallback(callback); + } + + /** + * Queries the map for rendered features. + *

+ * Returns an empty list if either the map or underlying render surface has been destroyed. + *

+ * + * @param coordinates the point to query + * @param layerIds optionally - only query these layers + * @return the list of feature + */ + @NonNull + public List queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... layerIds) { + return nativeMapView.queryRenderedFeatures(coordinates, layerIds, null); + } + + /** + * Queries the map for rendered features + *

+ * Returns an empty list if either the map or underlying render surface has been destroyed. + *

+ * + * @param coordinates the point to query + * @param filter filters the returned features with an expression + * @param layerIds optionally - only query these layers + * @return the list of feature + */ + @NonNull + public List queryRenderedFeatures(@NonNull PointF coordinates, + @Nullable Expression filter, + @Nullable String... layerIds) { + return nativeMapView.queryRenderedFeatures(coordinates, layerIds, filter); + } + + /** + * Queries the map for rendered features + *

+ * Returns an empty list if either the map or underlying render surface has been destroyed. + *

+ * + * @param coordinates the box to query + * @param layerIds optionally - only query these layers + * @return the list of feature + */ + @NonNull + public List queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String... layerIds) { + return nativeMapView.queryRenderedFeatures(coordinates, layerIds, null); + } + + /** + * Queries the map for rendered features + *

+ * Returns an empty list if either the map or underlying render surface has been destroyed. + *

+ * + * @param coordinates the box to query + * @param filter filters the returned features with an expression + * @param layerIds optionally - only query these layers + * @return the list of feature + */ + @NonNull + public List queryRenderedFeatures(@NonNull RectF coordinates, + @Nullable Expression filter, + @Nullable String... layerIds) { + return nativeMapView.queryRenderedFeatures(coordinates, layerIds, filter); + } + + // + // LocationComponent + // + + void injectLocationComponent(LocationComponent locationComponent) { + this.locationComponent = locationComponent; + } + + void injectAnnotationManager(AnnotationManager annotationManager) { + this.annotationManager = annotationManager.bind(this); + } + + /** + * Returns the {@link LocationComponent} that can be used to display user's location on the map. + *

+ * Use {@link LocationComponent#activateLocationComponent(Context, Style)} or any overload to activate the component, + * then, enable it with {@link LocationComponent#setLocationComponentEnabled(boolean)}. + *

+ * You can customize the location icon and more with {@link com.mapbox.mapboxsdk.location.LocationComponentOptions}. + * + * @return the Location Component + */ + @NonNull + public LocationComponent getLocationComponent() { + return locationComponent; + } + + // + // Interfaces + // + + /** + * Interface definition for a callback to be invoked when the map is flinged. + * + * @see MapboxMap#addOnFlingListener(OnFlingListener) + */ + public interface OnFlingListener { + /** + * Called when the map is flinged. + */ + void onFling(); + } + + /** + * Interface definition for a callback to be invoked when the map is moved. + * + * @see MapboxMap#addOnMoveListener(OnMoveListener) + */ + public interface OnMoveListener { + void onMoveBegin(@NonNull MoveGestureDetector detector); + + void onMove(@NonNull MoveGestureDetector detector); + + void onMoveEnd(@NonNull MoveGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is rotated. + * + * @see MapboxMap#addOnRotateListener(OnRotateListener) + */ + public interface OnRotateListener { + void onRotateBegin(@NonNull RotateGestureDetector detector); + + void onRotate(@NonNull RotateGestureDetector detector); + + void onRotateEnd(@NonNull RotateGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is scaled. + * + * @see MapboxMap#addOnScaleListener(OnScaleListener) + */ + public interface OnScaleListener { + void onScaleBegin(@NonNull StandardScaleGestureDetector detector); + + void onScale(@NonNull StandardScaleGestureDetector detector); + + void onScaleEnd(@NonNull StandardScaleGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is tilted. + * + * @see MapboxMap#addOnShoveListener(OnShoveListener) + */ + public interface OnShoveListener { + void onShoveBegin(@NonNull ShoveGestureDetector detector); + + void onShove(@NonNull ShoveGestureDetector detector); + + void onShoveEnd(@NonNull ShoveGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked for when the camera motion starts. + */ + public interface OnCameraMoveStartedListener { + int REASON_API_GESTURE = 1; + int REASON_DEVELOPER_ANIMATION = 2; + int REASON_API_ANIMATION = 3; + + /** + * Called when the camera starts moving after it has been idle or when the reason for camera motion has changed. + * + * @param reason the reason for the camera change + */ + void onCameraMoveStarted(int reason); + } + + /** + * Interface definition for a callback to be invoked for when the camera changes position. + */ + public interface OnCameraMoveListener { + /** + * Called repeatedly as the camera continues to move after an onCameraMoveStarted call. + * This may be called as often as once every frame and should not perform expensive operations. + */ + void onCameraMove(); + } + + /** + * Interface definition for a callback to be invoked for when the camera's motion has been stopped or when the camera + * starts moving for a new reason. + */ + public interface OnCameraMoveCanceledListener { + /** + * Called when the developer explicitly calls the cancelTransitions() method or if the reason for camera motion has + * changed before the onCameraIdle had a chance to fire after the previous animation. + * Do not update or animate the camera from within this method. + */ + void onCameraMoveCanceled(); + } + + /** + * Interface definition for a callback to be invoked for when camera movement has ended. + */ + public interface OnCameraIdleListener { + /** + * Called when camera movement has ended. + */ + void onCameraIdle(); + } + + /** + * 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) + */ + public interface OnFpsChangedListener { + /** + * Called for every frame rendered to the map view. + * + * @param fps The average number of frames rendered over the last second. + */ + void onFpsChanged(double fps); + } + + /** + * Interface definition for a callback to be invoked when a user registers an listener that is + * related to touch and click events. + */ + interface OnGesturesManagerInteractionListener { + + void onAddMapClickListener(OnMapClickListener listener); + + void onRemoveMapClickListener(OnMapClickListener listener); + + void onAddMapLongClickListener(OnMapLongClickListener listener); + + void onRemoveMapLongClickListener(OnMapLongClickListener listener); + + void onAddFlingListener(OnFlingListener listener); + + void onRemoveFlingListener(OnFlingListener listener); + + void onAddMoveListener(OnMoveListener listener); + + void onRemoveMoveListener(OnMoveListener listener); + + void onAddRotateListener(OnRotateListener listener); + + void onRemoveRotateListener(OnRotateListener listener); + + void onAddScaleListener(OnScaleListener listener); + + void onRemoveScaleListener(OnScaleListener listener); + + void onAddShoveListener(OnShoveListener listener); + + void onRemoveShoveListener(OnShoveListener listener); + + AndroidGesturesManager getGesturesManager(); + + void setGesturesManager(AndroidGesturesManager gesturesManager, boolean attachDefaultListeners, + boolean setDefaultMutuallyExclusives); + + void cancelAllVelocityAnimations(); + } + + /** + * Interface definition for a callback to be invoked when the user clicks on the map view. + * + * @see MapboxMap#addOnMapClickListener(OnMapClickListener) + */ + public interface OnMapClickListener { + /** + * Called when the user clicks on the map view. + * + * @param point The projected map coordinate the user clicked on. + * @return True if this click should be consumed and not passed further to other listeners registered afterwards, + * false otherwise. + */ + boolean onMapClick(@NonNull LatLng point); + } + + /** + * Interface definition for a callback to be invoked when the user long clicks on the map view. + * + * @see MapboxMap#addOnMapLongClickListener(OnMapLongClickListener) + */ + public interface OnMapLongClickListener { + /** + * Called when the user long clicks on the map view. + * + * @param point The projected map coordinate the user long clicked on. + * @return True if this click should be consumed and not passed further to other listeners registered afterwards, + * false otherwise. + */ + boolean onMapLongClick(@NonNull LatLng point); + } + + /** + * Interface definition for a callback to be invoked when the user clicks on a marker. + * + * @see MapboxMap#setOnMarkerClickListener(OnMarkerClickListener) + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public interface OnMarkerClickListener { + /** + * Called when the user clicks on a marker. + * + * @param marker The marker the user clicked on. + * @return If true the listener has consumed the event and the info window will not be shown. + */ + boolean onMarkerClick(@NonNull Marker marker); + } + + /** + * Interface definition for a callback to be invoked when the user clicks on a polygon. + * + * @see MapboxMap#setOnPolygonClickListener(OnPolygonClickListener) + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + 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) + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + 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) + */ + public interface OnInfoWindowClickListener { + /** + * Called when the user clicks on an info window. + * + * @param marker The marker of the info window the user clicked on. + * @return If true the listener has consumed the event and the info window will not be closed. + */ + boolean onInfoWindowClick(@NonNull Marker marker); + } + + /** + * Interface definition for a callback to be invoked when the user long presses on a marker's info window. + * + * @see MapboxMap#setOnInfoWindowClickListener(OnInfoWindowClickListener) + */ + public interface OnInfoWindowLongClickListener { + + /** + * Called when the user makes a long-press gesture on the marker's info window. + * + * @param marker The marker were the info window is attached to + */ + void onInfoWindowLongClick(@NonNull Marker marker); + } + + /** + * Interface definition for a callback to be invoked when a marker's info window is closed. + * + * @see MapboxMap#setOnInfoWindowCloseListener(OnInfoWindowCloseListener) + */ + public interface OnInfoWindowCloseListener { + + /** + * Called when the marker's info window is closed. + * + * @param marker The marker of the info window that was closed. + */ + void onInfoWindowClose(@NonNull Marker marker); + } + + /** + * Interface definition for a callback to be invoked when an info window will be shown. + * + * @see MapboxMap#setInfoWindowAdapter(InfoWindowAdapter) + * @deprecated As of 7.0.0, + * use + * Mapbox Annotation Plugin instead + */ + @Deprecated + public interface InfoWindowAdapter { + /** + * Called when an info window will be shown as a result of a marker click. + * + * @param marker The marker the user clicked on. + * @return View to be shown as a info window. If null is returned the default + * info window will be shown. + */ + @Nullable + View getInfoWindow(@NonNull Marker marker); + } + + /** + * Interface definition for a callback to be invoked when a task is complete or cancelled. + */ + public interface CancelableCallback { + /** + * Invoked when a task is cancelled. + */ + void onCancel(); + + /** + * Invoked when a task is complete. + */ + void onFinish(); + } + + /** + * Interface definition for a callback to be invoked when the snapshot has been taken. + */ + public interface SnapshotReadyCallback { + /** + * Invoked when the snapshot has been taken. + * + * @param snapshot the snapshot bitmap + */ + void onSnapshotReady(@NonNull Bitmap snapshot); + } + + /** + * Internal use. + */ + public interface OnDeveloperAnimationListener { + + /** + * Notifies listener when a developer invoked animation is about to start. + */ + void onDeveloperAnimationStarted(); + } + + // + // Used for instrumentation testing + // + @NonNull + Transform getTransform() { + return transform; + } + + private void notifyDeveloperAnimationListeners() { + for (OnDeveloperAnimationListener listener : developerAnimationStartedListeners) { + listener.onDeveloperAnimationStarted(); + } + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java new file mode 100644 index 000000000..6cd3271d1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -0,0 +1,1242 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.support.v4.content.res.ResourcesCompat; +import android.text.TextUtils; +import android.util.AttributeSet; +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.FontUtils; + +import java.util.Arrays; + +/** + * Defines configuration MapboxMapMapOptions for a MapboxMap. These options can be used when adding a + * map to your application programmatically (as opposed to via XML). If you are using a MapFragment, + * you can pass these options in using the static factory method newInstance(MapboxMapOptions). + * If you are using a MapView, you can pass these options in using the constructor + * MapView(Context, MapboxMapOptions). If you add a map using XML, then you can apply these options + * using custom XML tags. + */ +public class MapboxMapOptions implements Parcelable { + + private static final int LIGHT_GRAY = 0xFFF0E9E1; // RGB(240, 233, 225)) + 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; + + private boolean debugActive; + + private boolean compassEnabled = true; + private boolean fadeCompassFacingNorth = true; + private int compassGravity = Gravity.TOP | Gravity.END; + private int[] compassMargins; + private Drawable compassImage; + + private boolean logoEnabled = true; + private int logoGravity = Gravity.BOTTOM | Gravity.START; + private int[] logoMargins; + + @ColorInt + private int attributionTintColor = UNDEFINED_COLOR; + private boolean attributionEnabled = true; + private int attributionGravity = Gravity.BOTTOM | Gravity.START; + private int[] attributionMargins; + + private double minZoom = MapboxConstants.MINIMUM_ZOOM; + private double maxZoom = MapboxConstants.MAXIMUM_ZOOM; + + private boolean rotateGesturesEnabled = true; + private boolean scrollGesturesEnabled = true; + private boolean tiltGesturesEnabled = true; + private boolean zoomGesturesEnabled = true; + private boolean doubleTapGesturesEnabled = true; + private boolean quickZoomGesturesEnabled = true; + + private boolean prefetchesTiles = true; + private boolean zMediaOverlay = false; + + private boolean localIdeographFontFamilyEnabled = true; + private String localIdeographFontFamily; + private String[] localIdeographFontFamilies; + + private String apiBaseUri; + + private boolean textureMode; + private boolean translucentTextureSurface; + + @ColorInt + private int foregroundLoadColor; + + private float pixelRatio; + + private boolean crossSourceCollisions = true; + + /** + * Creates a new MapboxMapOptions object. + * + * @deprecated Use {@link #createFromAttributes(Context, AttributeSet)} instead. + */ + @Deprecated + public MapboxMapOptions() { + } + + private MapboxMapOptions(Parcel in) { + cameraPosition = in.readParcelable(CameraPosition.class.getClassLoader()); + debugActive = in.readByte() != 0; + + compassEnabled = in.readByte() != 0; + compassGravity = in.readInt(); + compassMargins = in.createIntArray(); + fadeCompassFacingNorth = in.readByte() != 0; + + Bitmap compassBitmap = in.readParcelable(getClass().getClassLoader()); + if (compassBitmap != null) { + compassImage = new BitmapDrawable(compassBitmap); + } + + logoEnabled = in.readByte() != 0; + logoGravity = in.readInt(); + logoMargins = in.createIntArray(); + + attributionEnabled = in.readByte() != 0; + attributionGravity = in.readInt(); + attributionMargins = in.createIntArray(); + attributionTintColor = in.readInt(); + + minZoom = in.readDouble(); + maxZoom = in.readDouble(); + + rotateGesturesEnabled = in.readByte() != 0; + scrollGesturesEnabled = in.readByte() != 0; + tiltGesturesEnabled = in.readByte() != 0; + zoomGesturesEnabled = in.readByte() != 0; + doubleTapGesturesEnabled = in.readByte() != 0; + quickZoomGesturesEnabled = in.readByte() != 0; + + apiBaseUri = in.readString(); + textureMode = in.readByte() != 0; + translucentTextureSurface = in.readByte() != 0; + prefetchesTiles = in.readByte() != 0; + zMediaOverlay = in.readByte() != 0; + localIdeographFontFamilyEnabled = in.readByte() != 0; + localIdeographFontFamily = in.readString(); + localIdeographFontFamilies = in.createStringArray(); + pixelRatio = in.readFloat(); + foregroundLoadColor = in.readInt(); + crossSourceCollisions = in.readByte() != 0; + } + + /** + * Creates a default MapboxMapsOptions from a given context. + * + * @param context Context related to a map view. + * @return the MapboxMapOptions created from attributes + */ + @NonNull + public static MapboxMapOptions createFromAttributes(@NonNull Context context) { + return createFromAttributes(context, null); + } + + /** + * Creates a MapboxMapsOptions from the attribute set. + * + * @param context Context related to a map view. + * @param attrs Attributeset containing configuration + * @return the MapboxMapOptions created from attributes + */ + @NonNull + public static MapboxMapOptions createFromAttributes(@NonNull Context context, @Nullable AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mapbox_MapView, 0, 0); + return createFromAttributes(new MapboxMapOptions(), context, typedArray); + } + + @VisibleForTesting + static MapboxMapOptions createFromAttributes(@NonNull MapboxMapOptions mapboxMapOptions, + @NonNull Context context, + @Nullable TypedArray typedArray) { + float pxlRatio = context.getResources().getDisplayMetrics().density; + try { + mapboxMapOptions.camera(new CameraPosition.Builder(typedArray).build()); + + // deprecated + mapboxMapOptions.apiBaseUrl(typedArray.getString(R.styleable.mapbox_MapView_mapbox_apiBaseUrl)); + + String baseUri = typedArray.getString(R.styleable.mapbox_MapView_mapbox_apiBaseUri); + if (!TextUtils.isEmpty(baseUri)) { + // override deprecated property if a value of the new type was provided + mapboxMapOptions.apiBaseUri(baseUri); + } + + mapboxMapOptions.zoomGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiZoomGestures, true)); + mapboxMapOptions.scrollGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiScrollGestures, true)); + mapboxMapOptions.rotateGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiRotateGestures, true)); + mapboxMapOptions.tiltGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiTiltGestures, true)); + mapboxMapOptions.doubleTapGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiDoubleTapGestures, true)); + mapboxMapOptions.quickZoomGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiQuickZoomGestures, true)); + + mapboxMapOptions.maxZoomPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoomMax, + MapboxConstants.MAXIMUM_ZOOM)); + mapboxMapOptions.minZoomPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoomMin, + MapboxConstants.MINIMUM_ZOOM)); + + mapboxMapOptions.compassEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiCompass, true)); + mapboxMapOptions.compassGravity(typedArray.getInt(R.styleable.mapbox_MapView_mapbox_uiCompassGravity, + Gravity.TOP | Gravity.END)); + mapboxMapOptions.compassMargins(new int[] { + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginLeft, + FOUR_DP * pxlRatio)), + ((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginTop, + FOUR_DP * pxlRatio)), + ((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginRight, + FOUR_DP * pxlRatio)), + ((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginBottom, + FOUR_DP * pxlRatio))}); + mapboxMapOptions.compassFadesWhenFacingNorth(typedArray.getBoolean( + R.styleable.mapbox_MapView_mapbox_uiCompassFadeFacingNorth, true)); + Drawable compassDrawable = typedArray.getDrawable( + R.styleable.mapbox_MapView_mapbox_uiCompassDrawable); + if (compassDrawable == null) { + compassDrawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.mapbox_compass_icon, null); + } + mapboxMapOptions.compassImage(compassDrawable); + + mapboxMapOptions.logoEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiLogo, true)); + mapboxMapOptions.logoGravity(typedArray.getInt(R.styleable.mapbox_MapView_mapbox_uiLogoGravity, + Gravity.BOTTOM | Gravity.START)); + mapboxMapOptions.logoMargins(new int[] { + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginLeft, + FOUR_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginTop, + FOUR_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginRight, + FOUR_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginBottom, + FOUR_DP * pxlRatio))}); + + mapboxMapOptions.attributionTintColor(typedArray.getColor( + R.styleable.mapbox_MapView_mapbox_uiAttributionTintColor, UNDEFINED_COLOR)); + mapboxMapOptions.attributionEnabled(typedArray.getBoolean( + R.styleable.mapbox_MapView_mapbox_uiAttribution, true)); + mapboxMapOptions.attributionGravity(typedArray.getInt( + R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM | Gravity.START)); + mapboxMapOptions.attributionMargins(new int[] { + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft, + NINETY_TWO_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop, + FOUR_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight, + FOUR_DP * pxlRatio)), + (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginBottom, + FOUR_DP * pxlRatio))}); + mapboxMapOptions.textureMode( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureMode, false)); + mapboxMapOptions.translucentTextureSurface( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureTranslucentSurface, false)); + mapboxMapOptions.setPrefetchesTiles( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); + mapboxMapOptions.renderSurfaceOnTop( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false)); + + mapboxMapOptions.localIdeographFontFamilyEnabled = + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true); + + int localIdeographFontFamiliesResId = + typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0); + if (localIdeographFontFamiliesResId != 0) { + String[] localIdeographFontFamilies = + context.getResources().getStringArray(localIdeographFontFamiliesResId); + mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamilies); + } else { + // did user provide xml font string? + String localIdeographFontFamily = + typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily); + if (localIdeographFontFamily == null) { + localIdeographFontFamily = MapboxConstants.DEFAULT_FONT; + } + mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamily); + } + + mapboxMapOptions.pixelRatio( + typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_pixelRatio, 0)); + mapboxMapOptions.foregroundLoadColor( + typedArray.getInt(R.styleable.mapbox_MapView_mapbox_foregroundLoadColor, LIGHT_GRAY) + ); + mapboxMapOptions.crossSourceCollisions( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_cross_source_collisions, true) + ); + } finally { + typedArray.recycle(); + } + return mapboxMapOptions; + } + + /** + * Specifies the URL used for API endpoint. + * + * @param apiBaseUrl The base of our API endpoint + * @return This + * @deprecated use {@link #apiBaseUri} instead + */ + @Deprecated + @NonNull + public MapboxMapOptions apiBaseUrl(String apiBaseUrl) { + this.apiBaseUri = apiBaseUrl; + return this; + } + + /** + * Specifies the URI used for API endpoint. + * + * @param apiBaseUri The base of our API endpoint + * @return This + */ + @NonNull + public MapboxMapOptions apiBaseUri(String apiBaseUri) { + this.apiBaseUri = apiBaseUri; + return this; + } + + /** + * Specifies a the initial camera position for the map view. + * + * @param cameraPosition Inital camera position + * @return This + */ + @NonNull + public MapboxMapOptions camera(CameraPosition cameraPosition) { + this.cameraPosition = cameraPosition; + return this; + } + + /** + * Specifies the used debug type for a map view. + * + * @param enabled True is debug is enabled + * @return This + */ + @NonNull + public MapboxMapOptions debugActive(boolean enabled) { + debugActive = enabled; + return this; + } + + /** + * Specifies the used minimum zoom level for a map view. + * + * @param minZoom Zoom level to be used + * @return This + */ + @NonNull + public MapboxMapOptions minZoomPreference(double minZoom) { + this.minZoom = minZoom; + return this; + } + + /** + * Specifies the used maximum zoom level for a map view. + * + * @param maxZoom Zoom level to be used + * @return This + */ + @NonNull + public MapboxMapOptions maxZoomPreference(double maxZoom) { + this.maxZoom = maxZoom; + return this; + } + + /** + * Specifies the visibility state of a mapbox_compass_icon for a map view. + * + * @param enabled True and mapbox_compass_icon is shown + * @return This + */ + @NonNull + public MapboxMapOptions compassEnabled(boolean enabled) { + compassEnabled = enabled; + return this; + } + + /** + * Specifies the gravity state of mapbox_compass_icon for a map view. + * + * @param gravity Android SDK Gravity. + * @return This + */ + @NonNull + public MapboxMapOptions compassGravity(int gravity) { + compassGravity = gravity; + return this; + } + + /** + * Specifies the margin state of mapbox_compass_icon for a map view + * + * @param margins 4 long array for LTRB margins + * @return This + */ + @NonNull + public MapboxMapOptions compassMargins(int[] margins) { + compassMargins = margins; + return this; + } + + /** + * Specifies if the mapbox_compass_icon fades to invisible when facing north. + *

+ * By default this value is true. + *

+ * + * @param compassFadeWhenFacingNorth true is mapbox_compass_icon fades to invisble + * @return This + */ + @NonNull + public MapboxMapOptions compassFadesWhenFacingNorth(boolean compassFadeWhenFacingNorth) { + this.fadeCompassFacingNorth = compassFadeWhenFacingNorth; + return this; + } + + /** + * Specifies the image of the CompassView. + *

+ * By default this value is R.drawable.mapbox_compass_icon. + *

+ * + * @param compass the drawable to show as image compass + * @return This + */ + @NonNull + public MapboxMapOptions compassImage(Drawable compass) { + this.compassImage = compass; + return this; + } + + /** + * Specifies the visibility state of a logo for a map view. + * + * @param enabled True and logo is shown + * @return This + */ + @NonNull + public MapboxMapOptions logoEnabled(boolean enabled) { + logoEnabled = enabled; + return this; + } + + /** + * Specifies the gravity state of logo for a map view. + * + * @param gravity Android SDK Gravity. + * @return This + */ + @NonNull + public MapboxMapOptions logoGravity(int gravity) { + logoGravity = gravity; + return this; + } + + /** + * Specifies the margin state of logo for a map view + * + * @param margins 4 long array for LTRB margins + * @return This + */ + @NonNull + public MapboxMapOptions logoMargins(int[] margins) { + logoMargins = margins; + return this; + } + + /** + * Specifies the visibility state of a attribution for a map view. + * + * @param enabled True and attribution is shown + * @return This + */ + @NonNull + public MapboxMapOptions attributionEnabled(boolean enabled) { + attributionEnabled = enabled; + return this; + } + + /** + * Specifies the gravity state of attribution for a map view. + * + * @param gravity Android SDK Gravity. + * @return This + */ + @NonNull + public MapboxMapOptions attributionGravity(int gravity) { + attributionGravity = gravity; + return this; + } + + /** + * Specifies the margin state of attribution for a map view + * + * @param margins 4 long array for LTRB margins + * @return This + */ + @NonNull + public MapboxMapOptions attributionMargins(int[] margins) { + attributionMargins = margins; + return this; + } + + /** + * Specifies the tint color of the attribution for a map view + * + * @param color integer resembling a color + * @return This + */ + @NonNull + public MapboxMapOptions attributionTintColor(@ColorInt int color) { + attributionTintColor = color; + return this; + } + + /** + * Specifies if the rotate gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions rotateGesturesEnabled(boolean enabled) { + rotateGesturesEnabled = enabled; + return this; + } + + /** + * Specifies if the scroll gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions scrollGesturesEnabled(boolean enabled) { + scrollGesturesEnabled = enabled; + return this; + } + + /** + * Specifies if the tilt gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions tiltGesturesEnabled(boolean enabled) { + tiltGesturesEnabled = enabled; + return this; + } + + /** + * Specifies if the zoom gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions zoomGesturesEnabled(boolean enabled) { + zoomGesturesEnabled = enabled; + return this; + } + + /** + * Specifies if the double tap gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions doubleTapGesturesEnabled(boolean enabled) { + doubleTapGesturesEnabled = enabled; + return this; + } + + /** + * Specifies whether the user may zoom the map by tapping twice, holding and moving the pointer up and down. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions quickZoomGesturesEnabled(boolean enabled) { + quickZoomGesturesEnabled = enabled; + return this; + } + + /** + * Enable {@link android.view.TextureView} as rendered surface. + *

+ * 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. + *

+ * + * @param textureMode True to enable texture mode + * @return This + */ + @NonNull + public MapboxMapOptions textureMode(boolean textureMode) { + this.textureMode = textureMode; + return this; + } + + @NonNull + public MapboxMapOptions translucentTextureSurface(boolean translucentTextureSurface) { + this.translucentTextureSurface = translucentTextureSurface; + return this; + } + + /** + * Set the MapView foreground color that is used when the map surface is being created. + * + * @param loadColor the color to show during map creation + * @return This + */ + @NonNull + public MapboxMapOptions foregroundLoadColor(@ColorInt int loadColor) { + this.foregroundLoadColor = loadColor; + return this; + } + + /** + * 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 + */ + @NonNull + public MapboxMapOptions setPrefetchesTiles(boolean enable) { + this.prefetchesTiles = enable; + return this; + } + + /** + * Enable cross-source symbol collision detection, defaults to true. + *

+ * If set to false, symbol layers will only run collision detection against + * other symbol layers that are part of the same source. + *

+ * + * @param crossSourceCollisions true to enable, false to disable + * @return This + */ + @NonNull + public MapboxMapOptions crossSourceCollisions(boolean crossSourceCollisions) { + this.crossSourceCollisions = crossSourceCollisions; + return this; + } + + /** + * Enable local ideograph font family, defaults to true. + * + * @param enabled true to enable, false to disable + * @return This + */ + @NonNull + public MapboxMapOptions localIdeographFontFamilyEnabled(boolean enabled) { + this.localIdeographFontFamilyEnabled = enabled; + return this; + } + + /** + * Set the font family for generating glyphs locally for ideographs in the 'CJK Unified Ideographs' + * and 'Hangul Syllables' ranges. + *

+ * The font family argument is passed to {@link android.graphics.Typeface#create(String, int)}. + * Default system fonts are defined in '/system/etc/fonts.xml' + * Default font for local ideograph font family is {@link MapboxConstants#DEFAULT_FONT}. + * + * @param fontFamily font family for local ideograph generation. + * @return This + */ + @NonNull + public MapboxMapOptions localIdeographFontFamily(String fontFamily) { + this.localIdeographFontFamily = FontUtils.extractValidFont(fontFamily); + return this; + } + + /** + * Set a font family from range of font families for generating glyphs locally for ideographs in the + * 'CJK Unified Ideographs' and 'Hangul Syllables' ranges. The first matching font + * will be selected. If no valid font found, it defaults to {@link MapboxConstants#DEFAULT_FONT}. + *

+ * The font families are checked against the default system fonts defined in + * '/system/etc/fonts.xml' Default font for local ideograph font family is + * {@link MapboxConstants#DEFAULT_FONT}. + *

+ * + * @param fontFamilies an array of font families for local ideograph generation. + * @return This + */ + @NonNull + public MapboxMapOptions localIdeographFontFamily(String... fontFamilies) { + this.localIdeographFontFamily = FontUtils.extractValidFont(fontFamilies); + return this; + } + + /** + * Set the custom pixel ratio configuration to override the default value from resources. + * This ratio will be used to initialise the map with. + * + * @param pixelRatio the custom pixel ratio of the map under construction + * @return This + */ + @NonNull + public MapboxMapOptions pixelRatio(float pixelRatio) { + this.pixelRatio = pixelRatio; + return this; + } + + /** + * Check whether tile pre-fetching is enabled. + * + * @return true if enabled + */ + public boolean getPrefetchesTiles() { + return prefetchesTiles; + } + + /** + * Check whether cross-source symbol collision detection is enabled. + * + * @return true if enabled + */ + public boolean getCrossSourceCollisions() { + return crossSourceCollisions; + } + + /** + * 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. + * @deprecated use {@link #getApiBaseUri()} instead + */ + @Deprecated + public String getApiBaseUrl() { + return apiBaseUri; + } + + /** + * Get the current configured API endpoint base URI. + * + * @return Base URI to be used API endpoint. + */ + public String getApiBaseUri() { + return apiBaseUri; + } + + /** + * Get the current configured initial camera position for a map view. + * + * @return CameraPosition to be initially used. + */ + public CameraPosition getCamera() { + return cameraPosition; + } + + /** + * Get the current configured min zoom for a map view. + * + * @return Mininum zoom level to be used. + */ + public double getMinZoomPreference() { + return minZoom; + } + + /** + * Get the current configured maximum zoom for a map view. + * + * @return Maximum zoom to be used. + */ + public double getMaxZoomPreference() { + return maxZoom; + } + + /** + * Get the current configured visibility state for mapbox_compass_icon for a map view. + * + * @return Visibility state of the mapbox_compass_icon + */ + public boolean getCompassEnabled() { + return compassEnabled; + } + + /** + * Get the current configured gravity state for mapbox_compass_icon for a map view. + * + * @return Gravity state of the mapbox_compass_icon + */ + public int getCompassGravity() { + return compassGravity; + } + + /** + * Get the current configured margins for mapbox_compass_icon for a map view. + * + * @return Margins state of the mapbox_compass_icon + */ + public int[] getCompassMargins() { + return compassMargins; + } + + /** + * Get the current configured state for fading the mapbox_compass_icon when facing north. + * + * @return True if mapbox_compass_icon fades to invisible when facing north + */ + public boolean getCompassFadeFacingNorth() { + return fadeCompassFacingNorth; + } + + /** + * Get the current configured CompassView image. + * + * @return the drawable used as compass image + */ + public Drawable getCompassImage() { + return compassImage; + } + + /** + * Get the current configured visibility state for mapbox_compass_icon for a map view. + * + * @return Visibility state of the mapbox_compass_icon + */ + public boolean getLogoEnabled() { + return logoEnabled; + } + + /** + * Get the current configured gravity state for logo for a map view. + * + * @return Gravity state of the logo + */ + public int getLogoGravity() { + return logoGravity; + } + + /** + * Get the current configured margins for logo for a map view. + * + * @return Margins state of the logo + */ + public int[] getLogoMargins() { + return logoMargins; + } + + /** + * Get the current configured rotate gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getRotateGesturesEnabled() { + return rotateGesturesEnabled; + } + + /** + * Get the current configured scroll gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getScrollGesturesEnabled() { + return scrollGesturesEnabled; + } + + /** + * Get the current configured tilt gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getTiltGesturesEnabled() { + return tiltGesturesEnabled; + } + + /** + * Get the current configured zoom gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getZoomGesturesEnabled() { + return zoomGesturesEnabled; + } + + /** + * Get the current configured double tap gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getDoubleTapGesturesEnabled() { + return doubleTapGesturesEnabled; + } + + /** + * Get whether the user may zoom the map by tapping twice, holding and moving the pointer up and down. + * + * @return True indicates gesture is enabled + */ + public boolean getQuickZoomGesturesEnabled() { + return quickZoomGesturesEnabled; + } + + /** + * Get the current configured visibility state for attribution for a map view. + * + * @return Visibility state of the attribution + */ + public boolean getAttributionEnabled() { + return attributionEnabled; + } + + /** + * Get the current configured gravity state for attribution for a map view. + * + * @return Gravity state of the logo + */ + public int getAttributionGravity() { + return attributionGravity; + } + + /** + * Get the current configured margins for attribution for a map view. + * + * @return Margins state of the logo + */ + public int[] getAttributionMargins() { + return attributionMargins; + } + + /** + * Get the current configured tint color for attribution for a map view. + * + * @return the tint color + */ + @ColorInt + public int getAttributionTintColor() { + return attributionTintColor; + } + + /** + * Get the current configured debug state for a map view. + * + * @return True indicates debug is enabled. + */ + public boolean getDebugActive() { + return debugActive; + } + + /** + * Returns true if TextureView is being used the render view. + * + * @return True if TextureView is used. + */ + public boolean getTextureMode() { + return textureMode; + } + + /** + * Returns true if TextureView supports a translucent surface + * + * @return True if translucent surface is active + */ + public boolean getTranslucentTextureSurface() { + return translucentTextureSurface; + } + + /** + * Returns the current configured foreground color that is used during map creation. + * + * @return the load color + */ + @ColorInt + public int getForegroundLoadColor() { + return foregroundLoadColor; + } + + /** + * Returns the font-family for locally overriding generation of glyphs in the + * 'CJK Unified Ideographs' and 'Hangul Syllables' ranges. + * Default font for local ideograph font family is {@link MapboxConstants#DEFAULT_FONT}. + * Returns null if local ideograph font families are disabled. + * + * @return Local ideograph font family name. + */ + @Nullable + public String getLocalIdeographFontFamily() { + return localIdeographFontFamilyEnabled ? localIdeographFontFamily : null; + } + + /** + * Returns true if local ideograph font family is enabled, defaults to true. + * + * @return True if local ideograph font family is enabled + */ + public boolean isLocalIdeographFontFamilyEnabled() { + return localIdeographFontFamilyEnabled; + } + + /** + * Return the custom configured pixel ratio, returns 0 if not configured. + * + * @return the pixel ratio used by the map under construction + */ + public float getPixelRatio() { + return pixelRatio; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public MapboxMapOptions createFromParcel(@NonNull Parcel in) { + return new MapboxMapOptions(in); + } + + public MapboxMapOptions[] newArray(int size) { + return new MapboxMapOptions[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(cameraPosition, flags); + dest.writeByte((byte) (debugActive ? 1 : 0)); + + dest.writeByte((byte) (compassEnabled ? 1 : 0)); + dest.writeInt(compassGravity); + dest.writeIntArray(compassMargins); + dest.writeByte((byte) (fadeCompassFacingNorth ? 1 : 0)); + dest.writeParcelable(compassImage != null + ? BitmapUtils.getBitmapFromDrawable(compassImage) : null, flags); + + dest.writeByte((byte) (logoEnabled ? 1 : 0)); + dest.writeInt(logoGravity); + dest.writeIntArray(logoMargins); + + dest.writeByte((byte) (attributionEnabled ? 1 : 0)); + dest.writeInt(attributionGravity); + dest.writeIntArray(attributionMargins); + dest.writeInt(attributionTintColor); + + dest.writeDouble(minZoom); + dest.writeDouble(maxZoom); + + dest.writeByte((byte) (rotateGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (scrollGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (tiltGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (quickZoomGesturesEnabled ? 1 : 0)); + + dest.writeString(apiBaseUri); + dest.writeByte((byte) (textureMode ? 1 : 0)); + dest.writeByte((byte) (translucentTextureSurface ? 1 : 0)); + dest.writeByte((byte) (prefetchesTiles ? 1 : 0)); + dest.writeByte((byte) (zMediaOverlay ? 1 : 0)); + dest.writeByte((byte) (localIdeographFontFamilyEnabled ? 1 : 0)); + dest.writeString(localIdeographFontFamily); + dest.writeStringArray(localIdeographFontFamilies); + dest.writeFloat(pixelRatio); + dest.writeInt(foregroundLoadColor); + dest.writeByte((byte) (crossSourceCollisions ? 1 : 0)); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MapboxMapOptions options = (MapboxMapOptions) o; + + if (debugActive != options.debugActive) { + return false; + } + if (compassEnabled != options.compassEnabled) { + return false; + } + if (fadeCompassFacingNorth != options.fadeCompassFacingNorth) { + return false; + } + if (compassImage != null + ? !compassImage.equals(options.compassImage) + : options.compassImage != null) { + return false; + } + if (compassGravity != options.compassGravity) { + return false; + } + if (logoEnabled != options.logoEnabled) { + return false; + } + if (logoGravity != options.logoGravity) { + return false; + } + if (attributionTintColor != options.attributionTintColor) { + return false; + } + if (attributionEnabled != options.attributionEnabled) { + return false; + } + if (attributionGravity != options.attributionGravity) { + return false; + } + if (Double.compare(options.minZoom, minZoom) != 0) { + return false; + } + if (Double.compare(options.maxZoom, maxZoom) != 0) { + return false; + } + if (rotateGesturesEnabled != options.rotateGesturesEnabled) { + return false; + } + if (scrollGesturesEnabled != options.scrollGesturesEnabled) { + return false; + } + if (tiltGesturesEnabled != options.tiltGesturesEnabled) { + return false; + } + if (zoomGesturesEnabled != options.zoomGesturesEnabled) { + return false; + } + if (doubleTapGesturesEnabled != options.doubleTapGesturesEnabled) { + return false; + } + if (quickZoomGesturesEnabled != options.quickZoomGesturesEnabled) { + return false; + } + if (cameraPosition != null ? !cameraPosition.equals(options.cameraPosition) : options.cameraPosition != null) { + return false; + } + if (!Arrays.equals(compassMargins, options.compassMargins)) { + return false; + } + if (!Arrays.equals(logoMargins, options.logoMargins)) { + return false; + } + if (!Arrays.equals(attributionMargins, options.attributionMargins)) { + return false; + } + if (apiBaseUri != null ? !apiBaseUri.equals(options.apiBaseUri) : options.apiBaseUri != null) { + return false; + } + if (prefetchesTiles != options.prefetchesTiles) { + return false; + } + if (zMediaOverlay != options.zMediaOverlay) { + return false; + } + if (localIdeographFontFamilyEnabled != options.localIdeographFontFamilyEnabled) { + return false; + } + if (!localIdeographFontFamily.equals(options.localIdeographFontFamily)) { + return false; + } + if (!Arrays.equals(localIdeographFontFamilies, options.localIdeographFontFamilies)) { + return false; + } + + if (pixelRatio != options.pixelRatio) { + return false; + } + + if (crossSourceCollisions != options.crossSourceCollisions) { + return false; + } + + return false; + } + + @Override + public int hashCode() { + int result; + long temp; + result = cameraPosition != null ? cameraPosition.hashCode() : 0; + result = 31 * result + (debugActive ? 1 : 0); + result = 31 * result + (compassEnabled ? 1 : 0); + result = 31 * result + (fadeCompassFacingNorth ? 1 : 0); + result = 31 * result + compassGravity; + result = 31 * result + (compassImage != null ? compassImage.hashCode() : 0); + result = 31 * result + Arrays.hashCode(compassMargins); + result = 31 * result + (logoEnabled ? 1 : 0); + result = 31 * result + logoGravity; + result = 31 * result + Arrays.hashCode(logoMargins); + result = 31 * result + attributionTintColor; + result = 31 * result + (attributionEnabled ? 1 : 0); + result = 31 * result + attributionGravity; + result = 31 * result + Arrays.hashCode(attributionMargins); + temp = Double.doubleToLongBits(minZoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxZoom); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (rotateGesturesEnabled ? 1 : 0); + result = 31 * result + (scrollGesturesEnabled ? 1 : 0); + result = 31 * result + (tiltGesturesEnabled ? 1 : 0); + result = 31 * result + (zoomGesturesEnabled ? 1 : 0); + result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0); + result = 31 * result + (quickZoomGesturesEnabled ? 1 : 0); + result = 31 * result + (apiBaseUri != null ? apiBaseUri.hashCode() : 0); + result = 31 * result + (textureMode ? 1 : 0); + result = 31 * result + (translucentTextureSurface ? 1 : 0); + result = 31 * result + (prefetchesTiles ? 1 : 0); + result = 31 * result + (zMediaOverlay ? 1 : 0); + result = 31 * result + (localIdeographFontFamilyEnabled ? 1 : 0); + result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0); + result = 31 * result + Arrays.hashCode(localIdeographFontFamilies); + result = 31 * result + (int) pixelRatio; + result = 31 * result + (crossSourceCollisions ? 1 : 0); + return result; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java new file mode 100644 index 000000000..b408d9f5c --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java @@ -0,0 +1,146 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.RectF; +import android.support.annotation.NonNull; +import android.support.v4.util.LongSparseArray; + +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.Marker; + +import java.util.ArrayList; +import java.util.List; + +/** + * Encapsulates {@link Marker}'s functionality. + */ +class MarkerContainer implements Markers { + + private final NativeMap nativeMapView; + private final LongSparseArray annotations; + private final IconManager iconManager; + + MarkerContainer(NativeMap nativeMapView, LongSparseArray annotations, IconManager iconManager) { + this.nativeMapView = nativeMapView; + this.annotations = annotations; + this.iconManager = iconManager; + } + + @Override + public Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) { + Marker marker = prepareMarker(markerOptions); + long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0; + marker.setMapboxMap(mapboxMap); + marker.setId(id); + annotations.put(id, marker); + return marker; + } + + @NonNull + @Override + public List addBy(@NonNull List markerOptionsList, @NonNull MapboxMap + mapboxMap) { + int count = markerOptionsList.size(); + List markers = new ArrayList<>(count); + if (nativeMapView != null && count > 0) { + BaseMarkerOptions markerOptions; + Marker marker; + for (int i = 0; i < count; i++) { + markerOptions = markerOptionsList.get(i); + marker = prepareMarker(markerOptions); + markers.add(marker); + } + + if (markers.size() > 0) { + 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; + } + + @Override + public void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) { + ensureIconLoaded(updatedMarker, mapboxMap); + nativeMapView.updateMarker(updatedMarker); + annotations.setValueAt(annotations.indexOfKey(updatedMarker.getId()), updatedMarker); + } + + @NonNull + @Override + public List obtainAll() { + List markers = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Marker) { + markers.add((Marker) annotation); + } + } + return markers; + } + + @NonNull + @Override + public List obtainAllIn(@NonNull RectF rectangle) { + RectF rect = nativeMapView.getDensityDependantRectangle(rectangle); + long[] ids = nativeMapView.queryPointAnnotations(rect); + List idsList = new ArrayList<>(ids.length); + for (long id : ids) { + idsList.add(id); + } + + List annotations = new ArrayList<>(ids.length); + List annotationList = obtainAnnotations(); + int count = annotationList.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotationList.get(i); + if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) { + annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation); + } + } + + return new ArrayList<>(annotations); + } + + @Override + public void reload() { + iconManager.reloadIcons(); + int count = annotations.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotations.get(i); + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + nativeMapView.removeAnnotation(annotation.getId()); + long newId = nativeMapView.addMarker(marker); + marker.setId(newId); + } + } + } + + private Marker prepareMarker(BaseMarkerOptions markerOptions) { + Marker marker = markerOptions.getMarker(); + Icon icon = iconManager.loadIconForMarker(marker); + marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon)); + return marker; + } + + private void ensureIconLoaded(Marker marker, @NonNull MapboxMap mapboxMap) { + iconManager.ensureIconLoaded(marker, mapboxMap); + } + + @NonNull + private List obtainAnnotations() { + List annotations = new ArrayList<>(); + for (int i = 0; i < this.annotations.size(); i++) { + annotations.add(this.annotations.get(this.annotations.keyAt(i))); + } + return annotations; + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java new file mode 100644 index 000000000..62859d58a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java @@ -0,0 +1,27 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.RectF; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; +import com.mapbox.mapboxsdk.annotations.Marker; + +import java.util.List; + +/** + * Interface that defines convenient methods for working with a {@link Marker}'s collection. + */ +interface Markers { + Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap); + + List addBy(@NonNull List markerOptionsList, @NonNull MapboxMap mapboxMap); + + void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap); + + List obtainAll(); + + @NonNull + List obtainAllIn(@NonNull RectF rectangle); + + void reload(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java new file mode 100644 index 000000000..7f3017c7a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -0,0 +1,268 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.RectF; +import android.support.annotation.IntRange; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Geometry; +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.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.light.Light; +import com.mapbox.mapboxsdk.style.sources.Source; + +import java.util.List; + +interface NativeMap { + + // + // Lifecycle API + // + + void resizeView(int width, int height); + + void onLowMemory(); + + void destroy(); + + boolean isDestroyed(); + + // + // Camera API + // + + void jumpTo(@NonNull LatLng center, double zoom, double pitch, double bearing, double[] padding); + + void easeTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration, + boolean easingInterpolator); + + void flyTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration); + + void moveBy(double deltaX, double deltaY, long duration); + + @NonNull + CameraPosition getCameraPosition(); + + CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds bounds, int[] padding, double bearing, double pitch); + + CameraPosition getCameraForGeometry(@NonNull Geometry geometry, int[] padding, double bearing, double pitch); + + void resetPosition(); + + void setLatLng(@NonNull LatLng latLng, long duration); + + LatLng getLatLng(); + + void setLatLngBounds(@Nullable LatLngBounds latLngBounds); + + void setVisibleCoordinateBounds(@NonNull LatLng[] coordinates, @NonNull RectF padding, + double direction, long duration); + + void setPitch(double pitch, long duration); + + double getPitch(); + + void setZoom(double zoom, @NonNull PointF focalPoint, long duration); + + double getZoom(); + + void setMinZoom(double zoom); + + double getMinZoom(); + + void setMaxZoom(double zoom); + + double getMaxZoom(); + + void resetZoom(); + + void rotateBy(double sx, double sy, double ex, double ey, long duration); + + void setBearing(double degrees, long duration); + + void setBearing(double degrees, double fx, double fy, long duration); + + double getBearing(); + + void resetNorth(); + + void cancelTransitions(); + + // + // Style API + // + + void setStyleUri(String url); + + @NonNull + String getStyleUri(); + + void setStyleJson(String newStyleJson); + + @NonNull + String getStyleJson(); + + boolean isFullyLoaded(); + + void addLayer(@NonNull Layer layer); + + void addLayerBelow(@NonNull Layer layer, @NonNull String below); + + void addLayerAbove(@NonNull Layer layer, @NonNull String above); + + void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index); + + @NonNull + List getLayers(); + + Layer getLayer(String layerId); + + boolean removeLayer(@NonNull String layerId); + + boolean removeLayer(@NonNull Layer layer); + + boolean removeLayerAt(@IntRange(from = 0) int index); + + void addSource(@NonNull Source source); + + @NonNull + List getSources(); + + Source getSource(@NonNull String sourceId); + + boolean removeSource(@NonNull String sourceId); + + boolean removeSource(@NonNull Source source); + + void setTransitionOptions(@NonNull TransitionOptions transitionOptions); + + @NonNull + TransitionOptions getTransitionOptions(); + + void addImages(Image[] images); + + Bitmap getImage(String name); + + void removeImage(String name); + + Light getLight(); + + // + // Content padding API + // + + void setContentPadding(double[] padding); + + double[] getContentPadding(); + + // + // Query API + // + + @NonNull + List queryRenderedFeatures(@NonNull PointF coordinates, + @Nullable String[] layerIds, + @Nullable Expression filter); + + @NonNull + List queryRenderedFeatures(@NonNull RectF coordinates, + @Nullable String[] layerIds, + @Nullable Expression filter); + + // + // Projection API + // + + double getMetersPerPixelAtLatitude(double lat); + + ProjectedMeters projectedMetersForLatLng(@NonNull LatLng latLng); + + LatLng latLngForProjectedMeters(@NonNull ProjectedMeters projectedMeters); + + @NonNull + PointF pixelForLatLng(@NonNull LatLng latLng); + + LatLng latLngForPixel(@NonNull PointF pixel); + + // + // Utils API + // + + void setOnFpsChangedListener(@NonNull MapboxMap.OnFpsChangedListener listener); + + void setDebug(boolean debug); + + boolean getDebug(); + + void cycleDebugOptions(); + + void setReachability(boolean status); + + void setApiBaseUrl(String baseUrl); + + void setPrefetchTiles(boolean enable); + + boolean getPrefetchTiles(); + + void setGestureInProgress(boolean inProgress); + + float getPixelRatio(); + + // + // Deprecated Annotations API + // + + long addMarker(Marker marker); + + @NonNull + long[] addMarkers(@NonNull List markers); + + long addPolyline(Polyline polyline); + + @NonNull + long[] addPolylines(@NonNull List polylines); + + long addPolygon(Polygon polygon); + + @NonNull + long[] addPolygons(@NonNull List polygons); + + void updateMarker(@NonNull Marker marker); + + void updatePolygon(@NonNull Polygon polygon); + + void updatePolyline(@NonNull Polyline polyline); + + void removeAnnotation(long id); + + void removeAnnotations(long[] ids); + + double getTopOffsetPixelsForAnnotationSymbol(String symbolName); + + void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels); + + void removeAnnotationIcon(String symbol); + + @NonNull + long[] queryPointAnnotations(RectF rectF); + + @NonNull + long[] queryShapeAnnotations(RectF rectF); + + @NonNull + RectF getDensityDependantRectangle(RectF rectangle); + + long getNativePtr(); + + void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback); +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java new file mode 100755 index 000000000..8496160c7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -0,0 +1,1489 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.RectF; +import android.os.Handler; +import android.support.annotation.IntRange; +import android.support.annotation.Keep; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Geometry; +import com.mapbox.mapboxsdk.LibraryLoader; +import com.mapbox.mapboxsdk.MapStrictMode; +import com.mapbox.mapboxsdk.annotations.Icon; +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.exceptions.CalledFromWorkerThreadException; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.light.Light; +import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException; +import com.mapbox.mapboxsdk.style.sources.Source; +import com.mapbox.mapboxsdk.utils.BitmapUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +// Class that wraps the native methods for convenience +final class NativeMapView implements NativeMap { + + private static final String TAG = "Mbgl-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 final MapRenderer mapRenderer; + + // Used to validate if methods are called from the correct thread + @NonNull + private final Thread thread; + + // Used for view callbacks + @Nullable + private ViewCallback viewCallback; + + // Used for map change callbacks + @Nullable + private StateCallback stateCallback; + + // Device density + private final float pixelRatio; + + // Flag to indicate destroy was called + private boolean destroyed = false; + + // Cached to enable lazily set padding. + // Whenever an animation is schedule, this value is cleared and the source of truth becomes the core transform state. + private double[] edgeInsets; + + // Holds the pointer to JNI NativeMapView + @Keep + private long nativePtr = 0; + + // Listener invoked to return a bitmap of the map + private MapboxMap.SnapshotReadyCallback snapshotReadyCallback; + + static { + LibraryLoader.load(); + } + + // + // Constructors + // + + public NativeMapView(@NonNull final Context context, final boolean crossSourceCollisions, + final ViewCallback viewCallback, final StateCallback stateCallback, + final MapRenderer mapRenderer) { + this(context, context.getResources().getDisplayMetrics().density, crossSourceCollisions, viewCallback, + stateCallback, mapRenderer); + } + + public NativeMapView(final Context context, final float pixelRatio, final boolean crossSourceCollisions, + final ViewCallback viewCallback, final StateCallback stateCallback, + final MapRenderer mapRenderer) { + this.mapRenderer = mapRenderer; + this.viewCallback = viewCallback; + this.fileSource = FileSource.getInstance(context); + this.pixelRatio = pixelRatio; + this.thread = Thread.currentThread(); + this.stateCallback = stateCallback; + nativeInitialize(this, fileSource, mapRenderer, pixelRatio, crossSourceCollisions); + } + + // + // Methods + // + + private boolean checkState(String callingMethod) { + // validate if invocation has occurred on the main thread + if (thread != Thread.currentThread()) { + throw new CalledFromWorkerThreadException( + String.format( + "Map interactions should happen on the UI thread. Method invoked from wrong thread is %s.", + callingMethod) + ); + } + + // validate if map has already been destroyed + if (destroyed && !TextUtils.isEmpty(callingMethod)) { + String message = String.format( + "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?", + callingMethod); + Logger.e(TAG, message); + + MapStrictMode.strictModeViolation(message); + } + return destroyed; + } + + @Override + public void destroy() { + destroyed = true; + viewCallback = null; + nativeDestroy(); + } + + @Override + public void resizeView(int width, int height) { + if (checkState("resizeView")) { + return; + } + width = (int) Math.ceil(width / pixelRatio); + height = (int) Math.ceil(height / pixelRatio); + + if (width < 0) { + throw new IllegalArgumentException("width cannot be negative."); + } + + if (height < 0) { + throw new IllegalArgumentException("height cannot be negative."); + } + + if (width > 65535) { + // we have seen edge cases where devices return incorrect values #6111 + Logger.e(TAG, String.format("Device returned an out of range width size, " + + "capping value at 65535 instead of %s", width) + ); + width = 65535; + } + + if (height > 65535) { + // we have seen edge cases where devices return incorrect values #6111 + Logger.e(TAG, String.format("Device returned an out of range height size, " + + "capping value at 65535 instead of %s", height) + ); + height = 65535; + } + + nativeResizeView(width, height); + } + + @Override + public void setStyleUri(String url) { + if (checkState("setStyleUri")) { + return; + } + nativeSetStyleUrl(url); + } + + @Override + @NonNull + public String getStyleUri() { + if (checkState("getStyleUri")) { + return ""; + } + return nativeGetStyleUrl(); + } + + @Override + public void setStyleJson(String newStyleJson) { + if (checkState("setStyleJson")) { + return; + } + nativeSetStyleJson(newStyleJson); + } + + @Override + @NonNull + public String getStyleJson() { + if (checkState("getStyleJson")) { + return ""; + } + return nativeGetStyleJson(); + } + + @Override + public void setLatLngBounds(LatLngBounds latLngBounds) { + if (checkState("setLatLngBounds")) { + return; + } + nativeSetLatLngBounds(latLngBounds); + } + + @Override + public void cancelTransitions() { + if (checkState("cancelTransitions")) { + return; + } + nativeCancelTransitions(); + } + + @Override + public void setGestureInProgress(boolean inProgress) { + if (checkState("setGestureInProgress")) { + return; + } + nativeSetGestureInProgress(inProgress); + } + + @Override + public void moveBy(double dx, double dy, long duration) { + if (checkState("moveBy")) { + return; + } + nativeMoveBy(dx / pixelRatio, dy / pixelRatio, duration); + } + + @Override + public void setLatLng(@NonNull LatLng latLng, long duration) { + if (checkState("setLatLng")) { + return; + } + nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), + getAnimationPaddingAndClearCachedInsets(null), duration); + } + + @Override + public LatLng getLatLng() { + if (checkState("")) { + return new LatLng(); + } + return nativeGetLatLng(); + } + + @Override + public CameraPosition getCameraForLatLngBounds(LatLngBounds bounds, int[] padding, double bearing, double tilt) { + if (checkState("getCameraForLatLngBounds")) { + return null; + } + return nativeGetCameraForLatLngBounds( + bounds, + padding[1] / pixelRatio, + padding[0] / pixelRatio, + padding[3] / pixelRatio, + padding[2] / pixelRatio, + bearing, + tilt + ); + } + + @Override + public CameraPosition getCameraForGeometry(Geometry geometry, int[] padding, double bearing, double tilt) { + if (checkState("getCameraForGeometry")) { + return null; + } + return nativeGetCameraForGeometry( + geometry, + padding[1] / pixelRatio, + padding[0] / pixelRatio, + padding[3] / pixelRatio, + padding[2] / pixelRatio, + bearing, + tilt + ); + } + + @Override + public void resetPosition() { + if (checkState("resetPosition")) { + return; + } + nativeResetPosition(); + } + + @Override + public double getPitch() { + if (checkState("getPitch")) { + return 0; + } + return nativeGetPitch(); + } + + @Override + public void setPitch(double pitch, long duration) { + if (checkState("setPitch")) { + return; + } + nativeSetPitch(pitch, duration); + } + + @Override + public void setZoom(double zoom, @NonNull PointF focalPoint, long duration) { + if (checkState("setZoom")) { + return; + } + nativeSetZoom(zoom, focalPoint.x / pixelRatio, focalPoint.y / pixelRatio, duration); + } + + @Override + public double getZoom() { + if (checkState("getZoom")) { + return 0; + } + return nativeGetZoom(); + } + + @Override + public void resetZoom() { + if (checkState("resetZoom")) { + return; + } + nativeResetZoom(); + } + + @Override + public void setMinZoom(double zoom) { + if (checkState("setMinZoom")) { + return; + } + nativeSetMinZoom(zoom); + } + + @Override + public double getMinZoom() { + if (checkState("getMinZoom")) { + return 0; + } + return nativeGetMinZoom(); + } + + @Override + public void setMaxZoom(double zoom) { + if (checkState("setMaxZoom")) { + return; + } + nativeSetMaxZoom(zoom); + } + + @Override + public double getMaxZoom() { + if (checkState("getMaxZoom")) { + return 0; + } + return nativeGetMaxZoom(); + } + + @Override + public void rotateBy(double sx, double sy, double ex, double ey, + long duration) { + if (checkState("rotateBy")) { + return; + } + nativeRotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey, duration); + } + + @Override + public void setContentPadding(double[] padding) { + if (checkState("setContentPadding")) { + return; + } + this.edgeInsets = padding; + } + + @Override + public double[] getContentPadding() { + if (checkState("getContentPadding")) { + return new double[] {0, 0, 0, 0}; + } + // if cached insets are not applied yet, return them, otherwise, get the padding from the camera + return edgeInsets != null ? edgeInsets : getCameraPosition().padding; + } + + @Override + public void setBearing(double degrees, long duration) { + if (checkState("setBearing")) { + return; + } + nativeSetBearing(degrees, duration); + } + + @Override + public void setBearing(double degrees, double fx, double fy, long duration) { + if (checkState("setBearing")) { + return; + } + nativeSetBearingXY(degrees, fx / pixelRatio, fy / pixelRatio, duration); + } + + @Override + public double getBearing() { + if (checkState("getBearing")) { + return 0; + } + return nativeGetBearing(); + } + + @Override + public void resetNorth() { + if (checkState("resetNorth")) { + return; + } + nativeResetNorth(); + } + + @Override + public long addMarker(Marker marker) { + if (checkState("addMarker")) { + return 0; + } + Marker[] markers = {marker}; + return nativeAddMarkers(markers)[0]; + } + + @Override + @NonNull + public long[] addMarkers(@NonNull List markers) { + if (checkState("addMarkers")) { + return new long[] {}; + } + return nativeAddMarkers(markers.toArray(new Marker[markers.size()])); + } + + @Override + public long addPolyline(Polyline polyline) { + if (checkState("addPolyline")) { + return 0; + } + Polyline[] polylines = {polyline}; + return nativeAddPolylines(polylines)[0]; + } + + @Override + @NonNull + public long[] addPolylines(@NonNull List polylines) { + if (checkState("addPolylines")) { + return new long[] {}; + } + return nativeAddPolylines(polylines.toArray(new Polyline[polylines.size()])); + } + + @Override + public long addPolygon(Polygon polygon) { + if (checkState("addPolygon")) { + return 0; + } + Polygon[] polygons = {polygon}; + return nativeAddPolygons(polygons)[0]; + } + + @Override + @NonNull + public long[] addPolygons(@NonNull List polygons) { + if (checkState("addPolygons")) { + return new long[] {}; + } + return nativeAddPolygons(polygons.toArray(new Polygon[polygons.size()])); + } + + @Override + public void updateMarker(@NonNull Marker marker) { + if (checkState("updateMarker")) { + return; + } + LatLng position = marker.getPosition(); + Icon icon = marker.getIcon(); + nativeUpdateMarker(marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId()); + } + + @Override + public void updatePolygon(@NonNull Polygon polygon) { + if (checkState("updatePolygon")) { + return; + } + nativeUpdatePolygon(polygon.getId(), polygon); + } + + @Override + public void updatePolyline(@NonNull Polyline polyline) { + if (checkState("updatePolyline")) { + return; + } + nativeUpdatePolyline(polyline.getId(), polyline); + } + + @Override + public void removeAnnotation(long id) { + if (checkState("removeAnnotation")) { + return; + } + long[] ids = {id}; + removeAnnotations(ids); + } + + @Override + public void removeAnnotations(long[] ids) { + if (checkState("removeAnnotations")) { + return; + } + nativeRemoveAnnotations(ids); + } + + @Override + @NonNull + public long[] queryPointAnnotations(RectF rect) { + if (checkState("queryPointAnnotations")) { + return new long[] {}; + } + return nativeQueryPointAnnotations(rect); + } + + @Override + @NonNull + public long[] queryShapeAnnotations(RectF rectF) { + if (checkState("queryShapeAnnotations")) { + return new long[] {}; + } + return nativeQueryShapeAnnotations(rectF); + } + + @Override + public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) { + if (checkState("addAnnotationIcon")) { + return; + } + nativeAddAnnotationIcon(symbol, width, height, scale, pixels); + } + + @Override + public void removeAnnotationIcon(String symbol) { + if (checkState("removeAnnotationIcon")) { + return; + } + nativeRemoveAnnotationIcon(symbol); + } + + @Override + public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) { + if (checkState("setVisibleCoordinateBounds")) { + return; + } + nativeSetVisibleCoordinateBounds(coordinates, padding, direction, duration); + } + + @Override + public void onLowMemory() { + if (checkState("onLowMemory")) { + return; + } + nativeOnLowMemory(); + } + + @Override + public void setDebug(boolean debug) { + if (checkState("setDebug")) { + return; + } + nativeSetDebug(debug); + } + + @Override + public void cycleDebugOptions() { + if (checkState("cycleDebugOptions")) { + return; + } + nativeCycleDebugOptions(); + } + + @Override + public boolean getDebug() { + if (checkState("getDebug")) { + return false; + } + return nativeGetDebug(); + } + + @Override + public boolean isFullyLoaded() { + if (checkState("isFullyLoaded")) { + return false; + } + return nativeIsFullyLoaded(); + } + + @Override + public void setReachability(boolean status) { + if (checkState("setReachability")) { + return; + } + nativeSetReachability(status); + } + + @Override + public double getMetersPerPixelAtLatitude(double lat) { + if (checkState("getMetersPerPixelAtLatitude")) { + return 0; + } + return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio; + } + + @Override + public ProjectedMeters projectedMetersForLatLng(@NonNull LatLng latLng) { + if (checkState("projectedMetersForLatLng")) { + return null; + } + return nativeProjectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude()); + } + + @Override + public LatLng latLngForProjectedMeters(@NonNull ProjectedMeters projectedMeters) { + if (checkState("latLngForProjectedMeters")) { + return new LatLng(); + } + return nativeLatLngForProjectedMeters(projectedMeters.getNorthing(), + projectedMeters.getEasting()); + } + + @Override + @NonNull + public PointF pixelForLatLng(@NonNull LatLng latLng) { + if (checkState("pixelForLatLng")) { + return new PointF(); + } + PointF pointF = nativePixelForLatLng(latLng.getLatitude(), latLng.getLongitude()); + pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio); + return pointF; + } + + @Override + public LatLng latLngForPixel(@NonNull PointF pixel) { + if (checkState("latLngForPixel")) { + return new LatLng(); + } + return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio); + } + + @Override + public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) { + if (checkState("getTopOffsetPixelsForAnnotationSymbol")) { + return 0; + } + return nativeGetTopOffsetPixelsForAnnotationSymbol(symbolName); + } + + @Override + public void jumpTo(@NonNull LatLng center, double zoom, double pitch, double angle, double[] padding) { + if (checkState("jumpTo")) { + return; + } + nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom, + getAnimationPaddingAndClearCachedInsets(padding)); + } + + @Override + public void easeTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration, + boolean easingInterpolator) { + if (checkState("easeTo")) { + return; + } + nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, + getAnimationPaddingAndClearCachedInsets(padding), easingInterpolator); + } + + @Override + public void flyTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration) { + if (checkState("flyTo")) { + return; + } + nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, + getAnimationPaddingAndClearCachedInsets(padding)); + } + + @Override + @NonNull + public CameraPosition getCameraPosition() { + if (checkState("getCameraValues")) { + return new CameraPosition.Builder().build(); + } + if (edgeInsets != null) { + return new CameraPosition.Builder(nativeGetCameraPosition()).padding(edgeInsets).build(); + } else { + return nativeGetCameraPosition(); + } + } + + @Override + public void setPrefetchTiles(boolean enable) { + if (checkState("setPrefetchTiles")) { + return; + } + nativeSetPrefetchTiles(enable); + } + + @Override + public boolean getPrefetchTiles() { + if (checkState("getPrefetchTiles")) { + return false; + } + return nativeGetPrefetchTiles(); + } + + // Runtime style Api + + @Override + public void setTransitionOptions(@NonNull TransitionOptions transitionOptions) { + nativeSetTransitionOptions(transitionOptions); + } + + @NonNull + @Override + public TransitionOptions getTransitionOptions() { + return nativeGetTransitionOptions(); + } + + @Override + @NonNull + public List getLayers() { + if (checkState("getLayers")) { + return new ArrayList<>(); + } + return Arrays.asList(nativeGetLayers()); + } + + @Override + public Layer getLayer(String layerId) { + if (checkState("getLayer")) { + return null; + } + return nativeGetLayer(layerId); + } + + @Override + public void addLayer(@NonNull Layer layer) { + if (checkState("addLayer")) { + return; + } + nativeAddLayer(layer.getNativePtr(), null); + } + + @Override + public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { + if (checkState("addLayerBelow")) { + return; + } + nativeAddLayer(layer.getNativePtr(), below); + } + + @Override + public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { + if (checkState("addLayerAbove")) { + return; + } + nativeAddLayerAbove(layer.getNativePtr(), above); + } + + @Override + public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { + if (checkState("addLayerAt")) { + return; + } + nativeAddLayerAt(layer.getNativePtr(), index); + } + + @Override + public boolean removeLayer(@NonNull String layerId) { + if (checkState("removeLayer")) { + return false; + } + + Layer layer = getLayer(layerId); + if (layer != null) { + return removeLayer(layer); + } + return false; + } + + + @Override + public boolean removeLayer(@NonNull Layer layer) { + if (checkState("removeLayer")) { + return false; + } + return nativeRemoveLayer(layer.getNativePtr()); + } + + @Override + public boolean removeLayerAt(@IntRange(from = 0) int index) { + if (checkState("removeLayerAt")) { + return false; + } + return nativeRemoveLayerAt(index); + } + + @Override + @NonNull + public List getSources() { + if (checkState("getSources")) { + return new ArrayList<>(); + } + return Arrays.asList(nativeGetSources()); + } + + @Override + public Source getSource(@NonNull String sourceId) { + if (checkState("getSource")) { + return null; + } + return nativeGetSource(sourceId); + } + + @Override + public void addSource(@NonNull Source source) { + if (checkState("addSource")) { + return; + } + nativeAddSource(source, source.getNativePtr()); + } + + @Override + public boolean removeSource(@NonNull String sourceId) { + if (checkState("removeSource")) { + return false; + } + Source source = getSource(sourceId); + if (source != null) { + return removeSource(source); + } + return false; + } + + @Override + public boolean removeSource(@NonNull Source source) { + if (checkState("removeSource")) { + return false; + } + return nativeRemoveSource(source, source.getNativePtr()); + } + + @Override + public void addImages(@NonNull Image[] images) { + if (checkState("addImages")) { + return; + } + nativeAddImages(images); + } + + @Override + public void removeImage(String name) { + if (checkState("removeImage")) { + return; + } + nativeRemoveImage(name); + } + + @Override + public Bitmap getImage(String name) { + if (checkState("getImage")) { + return null; + } + return nativeGetImage(name); + } + + // Feature querying + + @Override + @NonNull + public List queryRenderedFeatures(@NonNull PointF coordinates, + @Nullable String[] layerIds, + @Nullable Expression filter) { + if (checkState("queryRenderedFeatures")) { + return new ArrayList<>(); + } + Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio, + coordinates.y / pixelRatio, layerIds, filter != null ? filter.toArray() : null); + return features != null ? Arrays.asList(features) : new ArrayList(); + } + + @Override + @NonNull + public List queryRenderedFeatures(@NonNull RectF coordinates, + @Nullable String[] layerIds, + @Nullable Expression filter) { + if (checkState("queryRenderedFeatures")) { + return new ArrayList<>(); + } + Feature[] features = nativeQueryRenderedFeaturesForBox( + coordinates.left / pixelRatio, + coordinates.top / pixelRatio, + coordinates.right / pixelRatio, + coordinates.bottom / pixelRatio, + layerIds, + filter != null ? filter.toArray() : null); + return features != null ? Arrays.asList(features) : new ArrayList(); + } + + @Override + public void setApiBaseUrl(String baseUrl) { + if (checkState("setApiBaseUrl")) { + return; + } + fileSource.setApiBaseUrl(baseUrl); + } + + @Override + public Light getLight() { + if (checkState("getLight")) { + return null; + } + return nativeGetLight(); + } + + @Override + public float getPixelRatio() { + return pixelRatio; + } + + @NonNull + @Override + public RectF getDensityDependantRectangle(final RectF rectangle) { + return new RectF( + rectangle.left / pixelRatio, + rectangle.top / pixelRatio, + rectangle.right / pixelRatio, + rectangle.bottom / pixelRatio + ); + } + + // + // Callbacks + // + + @Keep + private void onCameraWillChange(boolean animated) { + if (stateCallback != null) { + stateCallback.onCameraWillChange(animated); + } + } + + @Keep + private void onCameraIsChanging() { + if (stateCallback != null) { + stateCallback.onCameraIsChanging(); + } + } + + @Keep + private void onCameraDidChange(boolean animated) { + if (stateCallback != null) { + stateCallback.onCameraDidChange(animated); + } + } + + @Keep + private void onWillStartLoadingMap() { + if (stateCallback != null) { + stateCallback.onWillStartLoadingMap(); + } + } + + @Keep + private void onDidFinishLoadingMap() { + if (stateCallback != null) { + stateCallback.onDidFinishLoadingMap(); + } + } + + @Keep + private void onDidFailLoadingMap(String error) { + if (stateCallback != null) { + stateCallback.onDidFailLoadingMap(error); + } + } + + @Keep + private void onWillStartRenderingFrame() { + if (stateCallback != null) { + stateCallback.onWillStartRenderingFrame(); + } + } + + @Keep + private void onDidFinishRenderingFrame(boolean fully) { + if (stateCallback != null) { + stateCallback.onDidFinishRenderingFrame(fully); + } + } + + @Keep + private void onWillStartRenderingMap() { + if (stateCallback != null) { + stateCallback.onWillStartRenderingMap(); + } + } + + @Keep + private void onDidFinishRenderingMap(boolean fully) { + if (stateCallback != null) { + stateCallback.onDidFinishRenderingMap(fully); + } + } + + @Keep + private void onDidBecomeIdle() { + if (stateCallback != null) { + stateCallback.onDidBecomeIdle(); + } + } + + @Keep + private void onDidFinishLoadingStyle() { + if (stateCallback != null) { + stateCallback.onDidFinishLoadingStyle(); + } + } + + @Keep + private void onSourceChanged(String sourceId) { + if (stateCallback != null) { + stateCallback.onSourceChanged(sourceId); + } + } + + @Keep + private void onStyleImageMissing(String imageId) { + if (stateCallback != null) { + stateCallback.onStyleImageMissing(imageId); + } + } + + @Keep + private boolean onCanRemoveUnusedStyleImage(String imageId) { + if (stateCallback != null) { + return stateCallback.onCanRemoveUnusedStyleImage(imageId); + } + + return true; + } + + @Keep + protected void onSnapshotReady(@Nullable Bitmap mapContent) { + if (checkState("OnSnapshotReady")) { + return; + } + + try { + if (snapshotReadyCallback != null && mapContent != null) { + if (viewCallback == null) { + snapshotReadyCallback.onSnapshotReady(mapContent); + } else { + Bitmap viewContent = viewCallback.getViewContent(); + if (viewContent != null) { + snapshotReadyCallback.onSnapshotReady(BitmapUtils.mergeBitmap(mapContent, viewContent)); + } + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onSnapshotReady", err); + throw err; + } + } + + // + // JNI methods + // + + @Keep + private native void nativeInitialize(NativeMapView nativeMap, + FileSource fileSource, + MapRenderer mapRenderer, + float pixelRatio, + boolean crossSourceCollisions); + + @Keep + private native void nativeDestroy(); + + @Keep + private native void nativeResizeView(int width, int height); + + @Keep + private native void nativeSetStyleUrl(String url); + + @NonNull + @Keep + private native String nativeGetStyleUrl(); + + @Keep + private native void nativeSetStyleJson(String newStyleJson); + + @NonNull + @Keep + private native String nativeGetStyleJson(); + + @Keep + private native void nativeSetLatLngBounds(LatLngBounds latLngBounds); + + @Keep + private native void nativeCancelTransitions(); + + @Keep + private native void nativeSetGestureInProgress(boolean inProgress); + + @Keep + private native void nativeMoveBy(double dx, double dy, long duration); + + @Keep + private native void nativeSetLatLng(double latitude, double longitude, double[] padding, long duration); + + @NonNull + @Keep + private native LatLng nativeGetLatLng(); + + @NonNull + @Keep + private native CameraPosition nativeGetCameraForLatLngBounds( + LatLngBounds latLngBounds, double top, double left, double bottom, double right, double bearing, double tilt); + + @NonNull + @Keep + private native CameraPosition nativeGetCameraForGeometry( + Geometry geometry, double top, double left, double bottom, double right, double bearing, double tilt); + + @Keep + private native void nativeResetPosition(); + + @Keep + private native double nativeGetPitch(); + + @Keep + private native void nativeSetPitch(double pitch, long duration); + + @Keep + private native void nativeSetZoom(double zoom, double cx, double cy, long duration); + + @Keep + private native double nativeGetZoom(); + + @Keep + private native void nativeResetZoom(); + + @Keep + private native void nativeSetMinZoom(double zoom); + + @Keep + private native double nativeGetMinZoom(); + + @Keep + private native void nativeSetMaxZoom(double zoom); + + @Keep + private native double nativeGetMaxZoom(); + + @Keep + private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration); + + @Keep + private native void nativeSetBearing(double degrees, long duration); + + @Keep + private native void nativeSetBearingXY(double degrees, double fx, double fy, long duration); + + @Keep + private native double nativeGetBearing(); + + @Keep + private native void nativeResetNorth(); + + @Keep + private native void nativeUpdateMarker(long markerId, double lat, double lon, String iconId); + + @NonNull + @Keep + private native long[] nativeAddMarkers(Marker[] markers); + + @NonNull + @Keep + private native long[] nativeAddPolylines(Polyline[] polylines); + + @NonNull + @Keep + private native long[] nativeAddPolygons(Polygon[] polygons); + + @Keep + private native void nativeRemoveAnnotations(long[] id); + + @NonNull + @Keep + private native long[] nativeQueryPointAnnotations(RectF rect); + + @NonNull + @Keep + private native long[] nativeQueryShapeAnnotations(RectF rect); + + @Keep + private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels); + + @Keep + private native void nativeRemoveAnnotationIcon(String symbol); + + @Keep + private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, + double direction, long duration); + + @Keep + private native void nativeOnLowMemory(); + + @Keep + private native void nativeSetDebug(boolean debug); + + @Keep + private native void nativeCycleDebugOptions(); + + @Keep + private native boolean nativeGetDebug(); + + @Keep + private native boolean nativeIsFullyLoaded(); + + @Keep + private native void nativeSetReachability(boolean status); + + @Keep + private native double nativeGetMetersPerPixelAtLatitude(double lat, double zoom); + + @NonNull + @Keep + private native ProjectedMeters nativeProjectedMetersForLatLng(double latitude, double longitude); + + @NonNull + @Keep + private native LatLng nativeLatLngForProjectedMeters(double northing, double easting); + + @NonNull + @Keep + private native PointF nativePixelForLatLng(double lat, double lon); + + @NonNull + @Keep + private native LatLng nativeLatLngForPixel(float x, float y); + + @Keep + private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName); + + @Keep + private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom, + double[] padding); + + @Keep + private native void nativeEaseTo(double angle, double latitude, double longitude, + long duration, double pitch, double zoom, double[] padding, + boolean easingInterpolator); + + @Keep + private native void nativeFlyTo(double angle, double latitude, double longitude, + long duration, double pitch, double zoom, double[] padding); + + @NonNull + @Keep + private native CameraPosition nativeGetCameraPosition(); + + @Keep + private native void nativeSetTransitionOptions(TransitionOptions transitionOptions); + + @NonNull + @Keep + private native TransitionOptions nativeGetTransitionOptions(); + + @Keep + private native long nativeGetTransitionDuration(); + + @Keep + private native void nativeSetTransitionDuration(long duration); + + @Keep + private native long nativeGetTransitionDelay(); + + @Keep + private native void nativeSetTransitionDelay(long delay); + + @NonNull + @Keep + private native Layer[] nativeGetLayers(); + + @NonNull + @Keep + private native Layer nativeGetLayer(String layerId); + + @Keep + private native void nativeAddLayer(long layerPtr, String before) throws CannotAddLayerException; + + @Keep + private native void nativeAddLayerAbove(long layerPtr, String above) throws CannotAddLayerException; + + @Keep + private native void nativeAddLayerAt(long layerPtr, int index) throws CannotAddLayerException; + + @Keep + private native boolean nativeRemoveLayer(long layerId); + + @Keep + private native boolean nativeRemoveLayerAt(int index); + + @NonNull + @Keep + private native Source[] nativeGetSources(); + + @NonNull + @Keep + private native Source nativeGetSource(String sourceId); + + @Keep + private native void nativeAddSource(Source source, long sourcePtr) throws CannotAddSourceException; + + @Keep + private native boolean nativeRemoveSource(Source source, long sourcePtr); + + @Keep + private native void nativeAddImage(String name, Bitmap bitmap, float pixelRatio, boolean sdf); + + @Keep + private native void nativeAddImages(Image[] images); + + @Keep + private native void nativeRemoveImage(String name); + + @NonNull + @Keep + private native Bitmap nativeGetImage(String name); + + @Keep + private native void nativeUpdatePolygon(long polygonId, Polygon polygon); + + @Keep + private native void nativeUpdatePolyline(long polylineId, Polyline polyline); + + @Keep + private native void nativeTakeSnapshot(); + + @NonNull + @Keep + private native Feature[] nativeQueryRenderedFeaturesForPoint(float x, float y, + String[] layerIds, + Object[] filter); + + @NonNull + @Keep + private native Feature[] nativeQueryRenderedFeaturesForBox(float left, float top, + float right, float bottom, + String[] layerIds, + Object[] filter); + + @NonNull + @Keep + private native Light nativeGetLight(); + + @Keep + private native void nativeSetPrefetchTiles(boolean enable); + + @Keep + private native boolean nativeGetPrefetchTiles(); + + @Override + public long getNativePtr() { + return nativePtr; + } + + // + // Snapshot + // + + @Override + public void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { + if (checkState("addSnapshotCallback")) { + return; + } + snapshotReadyCallback = callback; + nativeTakeSnapshot(); + } + + @Override + public void setOnFpsChangedListener(@Nullable final MapboxMap.OnFpsChangedListener listener) { + final Handler handler = new Handler(); + mapRenderer.queueEvent(new Runnable() { + + @Override + public void run() { + if (listener != null) { + mapRenderer.setOnFpsChangedListener(new MapboxMap.OnFpsChangedListener() { + @Override + public void onFpsChanged(final double fps) { + handler.post(new Runnable() { + + @Override + public void run() { + listener.onFpsChanged(fps); + } + + }); + } + }); + } else { + mapRenderer.setOnFpsChangedListener(null); + } + } + }); + } + + @Override + public boolean isDestroyed() { + return destroyed; + } + + private double[] getAnimationPaddingAndClearCachedInsets(double[] providedPadding) { + if (providedPadding == null) { + providedPadding = this.edgeInsets; + } + this.edgeInsets = null; + return providedPadding == null ? null : + new double[] { + providedPadding[1] / pixelRatio, + providedPadding[0] / pixelRatio, + providedPadding[3] / pixelRatio, + providedPadding[2] / pixelRatio + }; + } + + public interface ViewCallback { + @Nullable + Bitmap getViewContent(); + } + + interface StyleCallback { + void onWillStartLoadingMap(); + + void onDidFinishLoadingStyle(); + } + + interface StateCallback extends StyleCallback { + void onCameraWillChange(boolean animated); + + void onCameraIsChanging(); + + void onCameraDidChange(boolean animated); + + void onDidFinishLoadingMap(); + + void onDidFailLoadingMap(String error); + + void onWillStartRenderingFrame(); + + void onDidFinishRenderingFrame(boolean fully); + + void onWillStartRenderingMap(); + + void onDidFinishRenderingMap(boolean fully); + + void onDidBecomeIdle(); + + void onSourceChanged(String sourceId); + + void onStyleImageMissing(String imageId); + + boolean onCanRemoveUnusedStyleImage(String imageId); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java new file mode 100644 index 000000000..31b459abb --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java @@ -0,0 +1,22 @@ +package com.mapbox.mapboxsdk.maps; + +import android.support.annotation.NonNull; + +/** + * Interface definition for a callback to be invoked when the map is ready to be used. + *

+ * Once an instance of this interface is set on a {@link MapFragment} or {@link MapView} object, + * the onMapReady(MapboxMap) method is triggered when the map is ready to be used and provides an instance of + * {@link MapboxMap}. + *

+ */ +public interface OnMapReadyCallback { + + /** + * Called when the map is ready to be used. + * + * @param mapboxMap An instance of MapboxMap associated with the {@link MapFragment} or + * {@link MapView} that defines the callback. + */ + void onMapReady(@NonNull MapboxMap mapboxMap); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java new file mode 100644 index 000000000..a7e2ace06 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java @@ -0,0 +1,84 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; +import android.support.v4.util.LongSparseArray; + +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Encapsulates {@link Polygon}'s functionality. + */ +class PolygonContainer implements Polygons { + + private final NativeMap nativeMap; + private final LongSparseArray annotations; + + PolygonContainer(NativeMap nativeMap, LongSparseArray annotations) { + this.nativeMap = nativeMap; + this.annotations = annotations; + } + + @Override + public Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) { + Polygon polygon = polygonOptions.getPolygon(); + if (!polygon.getPoints().isEmpty()) { + long id = nativeMap != null ? nativeMap.addPolygon(polygon) : 0; + polygon.setId(id); + polygon.setMapboxMap(mapboxMap); + annotations.put(id, polygon); + } + return polygon; + } + + @NonNull + @Override + public List addBy(@NonNull List polygonOptionsList, @NonNull MapboxMap mapboxMap) { + int count = polygonOptionsList.size(); + + Polygon polygon; + List polygons = new ArrayList<>(count); + if (nativeMap != null && count > 0) { + for (PolygonOptions polygonOptions : polygonOptionsList) { + polygon = polygonOptions.getPolygon(); + if (!polygon.getPoints().isEmpty()) { + polygons.add(polygon); + } + } + + long[] ids = nativeMap.addPolygons(polygons); + for (int i = 0; i < ids.length; i++) { + polygon = polygons.get(i); + polygon.setMapboxMap(mapboxMap); + polygon.setId(ids[i]); + annotations.put(ids[i], polygon); + } + } + return polygons; + } + + @Override + public void update(@NonNull Polygon polygon) { + nativeMap.updatePolygon(polygon); + annotations.setValueAt(annotations.indexOfKey(polygon.getId()), polygon); + } + + @NonNull + @Override + public List obtainAll() { + List polygons = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Polygon) { + polygons.add((Polygon) annotation); + } + } + return polygons; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java new file mode 100644 index 000000000..2a0190b5b --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java @@ -0,0 +1,22 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; + +import java.util.List; + +/** + * Interface that defines convenient methods for working with a {@link Polygon}'s collection. + */ +interface Polygons { + Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap); + + List addBy(@NonNull List polygonOptionsList, @NonNull MapboxMap mapboxMap); + + void update(Polygon polygon); + + List obtainAll(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java new file mode 100644 index 000000000..e11da26e0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java @@ -0,0 +1,83 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; +import android.support.v4.util.LongSparseArray; + +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.Polyline; +import com.mapbox.mapboxsdk.annotations.PolylineOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Encapsulates {@link Polyline}'s functionality. + */ +class PolylineContainer implements Polylines { + + private final NativeMap nativeMap; + private final LongSparseArray annotations; + + PolylineContainer(NativeMap nativeMap, LongSparseArray annotations) { + this.nativeMap = nativeMap; + this.annotations = annotations; + } + + @Override + public Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) { + Polyline polyline = polylineOptions.getPolyline(); + if (!polyline.getPoints().isEmpty()) { + long id = nativeMap != null ? nativeMap.addPolyline(polyline) : 0; + polyline.setMapboxMap(mapboxMap); + polyline.setId(id); + annotations.put(id, polyline); + } + return polyline; + } + + @NonNull + @Override + public List addBy(@NonNull List polylineOptionsList, @NonNull MapboxMap mapboxMap) { + int count = polylineOptionsList.size(); + Polyline polyline; + List polylines = new ArrayList<>(count); + if (nativeMap != null && count > 0) { + for (PolylineOptions options : polylineOptionsList) { + polyline = options.getPolyline(); + if (!polyline.getPoints().isEmpty()) { + polylines.add(polyline); + } + } + + long[] ids = nativeMap.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; + } + + @Override + public void update(@NonNull Polyline polyline) { + nativeMap.updatePolyline(polyline); + annotations.setValueAt(annotations.indexOfKey(polyline.getId()), polyline); + } + + @NonNull + @Override + public List obtainAll() { + List polylines = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Polyline) { + polylines.add((Polyline) annotation); + } + } + return polylines; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java new file mode 100644 index 000000000..c9a865cdd --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java @@ -0,0 +1,22 @@ +package com.mapbox.mapboxsdk.maps; + + +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.annotations.Polyline; +import com.mapbox.mapboxsdk.annotations.PolylineOptions; + +import java.util.List; + +/** + * Interface that defines convenient methods for working with a {@link Polyline}'s collection. + */ +interface Polylines { + Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap); + + List addBy(@NonNull List polylineOptionsList, @NonNull MapboxMap mapboxMap); + + void update(Polyline polyline); + + List obtainAll(); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java new file mode 100644 index 000000000..76395f956 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -0,0 +1,283 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.PointF; +import android.support.annotation.FloatRange; +import android.support.annotation.NonNull; + +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.constants.GeometryConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.geometry.VisibleRegion; + +import java.util.ArrayList; +import java.util.List; + +/** + * A projection is used to translate between on screen location and geographic coordinates on + * the surface of the Earth. Screen location is in screen pixels (not display pixels) + * with respect to the top left corner of the map (and not necessarily of the whole screen). + */ +public class Projection { + + @NonNull + private final NativeMap nativeMapView; + @NonNull + private final MapView mapView; + + Projection(@NonNull NativeMap nativeMapView, @NonNull MapView mapView) { + this.nativeMapView = nativeMapView; + this.mapView = mapView; + } + + void setContentPadding(int[] contentPadding) { + double[] output = new double[contentPadding.length]; + for (int i = 0; i < contentPadding.length; i++) { + output[i] = contentPadding[i]; + } + nativeMapView.setContentPadding(output); + } + + int[] getContentPadding() { + double[] padding = nativeMapView.getCameraPosition().padding; + return new int[] {(int) padding[0], (int) padding[1], (int) padding[2], (int) padding[3]}; + } + + /** + * @deprecated unused + */ + @Deprecated + public void invalidateContentPadding() { + } + + /** + * Returns the spherical Mercator projected meters for a LatLng. + */ + @NonNull + public ProjectedMeters getProjectedMetersForLatLng(@NonNull LatLng latLng) { + return nativeMapView.projectedMetersForLatLng(latLng); + } + + /** + * Returns the LatLng for a spherical Mercator projected meters. + */ + @NonNull + public LatLng getLatLngForProjectedMeters(@NonNull ProjectedMeters projectedMeters) { + return nativeMapView.latLngForProjectedMeters(projectedMeters); + } + + /** + *

+ * Returns the distance spanned by one pixel at the specified latitude and current zoom level. + *

+ * The distance between pixels decreases as the latitude approaches the poles. + * This relationship parallels the relationship between longitudinal coordinates at different latitudes. + * + * @param latitude The latitude for which to return the value. + * @return The distance measured in meters. + */ + public double getMetersPerPixelAtLatitude(@FloatRange(from = -90, to = 90) double latitude) { + return nativeMapView.getMetersPerPixelAtLatitude(latitude); + } + + /** + * Returns the geographic location that corresponds to a screen location. + * The screen location is specified in screen pixels (not display pixels) relative to the + * top left of the map (not the top left of the whole screen). + * + * @param point A Point on the screen in screen pixels. + * @return The LatLng corresponding to the point on the screen, or null if the ray through + * the given screen point does not intersect the ground plane. + */ + @NonNull + public LatLng fromScreenLocation(@NonNull PointF point) { + return nativeMapView.latLngForPixel(point); + } + + /** + * Gets a projection of the viewing frustum for converting between screen coordinates and + * geo-latitude/longitude coordinates. + *

+ * This method ignores the content padding. + * + * @return The projection of the viewing frustum in its current state. + */ + @NonNull + public VisibleRegion getVisibleRegion() { + return getVisibleRegion(true); + } + + /** + * Gets a projection of the viewing frustum for converting between screen coordinates and + * geo-latitude/longitude coordinates. + * + * @param ignorePadding True if the padding should be ignored, + * false if the returned region should be reduced by the padding. + * @return The projection of the viewing frustum in its current state. + */ + @NonNull + public VisibleRegion getVisibleRegion(boolean ignorePadding) { + float left; + float right; + float top; + float bottom; + + if (ignorePadding) { + left = 0; + right = mapView.getWidth(); + top = 0; + bottom = mapView.getHeight(); + } else { + int[] contentPadding = getContentPadding(); + left = contentPadding[0]; + right = mapView.getWidth() - contentPadding[2]; + top = contentPadding[1]; + bottom = mapView.getHeight() - contentPadding[3]; + } + + LatLng center = fromScreenLocation(new PointF(left + (right - left) / 2, top + (bottom - top) / 2)); + + 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)); + + List latLngs = new ArrayList<>(); + latLngs.add(topRight); + latLngs.add(bottomRight); + latLngs.add(bottomLeft); + latLngs.add(topLeft); + + double maxEastLonSpan = 0; + double maxWestLonSpan = 0; + + double east = 0; + double west = 0; + double north = GeometryConstants.MIN_LATITUDE; + double south = GeometryConstants.MAX_LATITUDE; + + for (LatLng latLng : latLngs) { + double bearing = bearing(center, latLng); + + if (bearing >= 0) { + double span = getLongitudeSpan(latLng.getLongitude(), center.getLongitude()); + if (span > maxEastLonSpan) { + maxEastLonSpan = span; + east = latLng.getLongitude(); + } + } else { + double span = getLongitudeSpan(center.getLongitude(), latLng.getLongitude()); + if (span > maxWestLonSpan) { + maxWestLonSpan = span; + west = latLng.getLongitude(); + } + } + + if (north < latLng.getLatitude()) { + north = latLng.getLatitude(); + } + if (south > latLng.getLatitude()) { + south = latLng.getLatitude(); + } + } + + if (east < west) { + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from(north, east + GeometryConstants.LONGITUDE_SPAN, south, west)); + } + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from(north, east, south, west)); + } + + /** + * Takes two {@link Point}s and finds the geographic bearing between them. + * + * @param latLng1 the first point used for calculating the bearing + * @param latLng2 the second point used for calculating the bearing + * @return bearing in decimal degrees + * @see Turf Bearing documentation + */ + static double bearing(@NonNull LatLng latLng1, @NonNull LatLng latLng2) { + + double lon1 = degreesToRadians(latLng1.getLongitude()); + double lon2 = degreesToRadians(latLng2.getLongitude()); + double lat1 = degreesToRadians(latLng1.getLatitude()); + double lat2 = degreesToRadians(latLng2.getLatitude()); + + double value1 = Math.sin(lon2 - lon1) * Math.cos(lat2); + double value2 = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) + * Math.cos(lat2) * Math.cos(lon2 - lon1); + + return radiansToDegrees(Math.atan2(value1, value2)); + } + + /** + * Converts an angle in degrees to radians. + * + * @param degrees angle between 0 and 360 degrees + * @return angle in radians + */ + static double degreesToRadians(double degrees) { + double radians = degrees % 360; + return radians * Math.PI / 180; + } + + /** + * Converts an angle in radians to degrees. + * + * @param radians angle in radians + * @return degrees between 0 and 360 degrees + */ + static double radiansToDegrees(double radians) { + double degrees = radians % (2 * Math.PI); + return degrees * 180 / Math.PI; + } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this LatLngBounds + * + * @return Span distance + */ + static double getLongitudeSpan(double east, double west) { + double longSpan = Math.abs(east - west); + if (east > west) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; + } + + /** + * Returns a screen location that corresponds to a geographical coordinate (LatLng). + * The screen location is in screen pixels (not display pixels) relative to the top left + * of the map (not of the whole screen). + * + * @param location A LatLng on the map to convert to a screen location. + * @return A Point representing the screen location in screen pixels. + */ + @NonNull + public PointF toScreenLocation(@NonNull LatLng location) { + return nativeMapView.pixelForLatLng(location); + } + + float getHeight() { + return mapView.getHeight(); + } + + float getWidth() { + return mapView.getWidth(); + } + + /** + * Calculates a zoom level based on minimum scale and current scale from MapView + * + * @param minScale The minimum scale to calculate the zoom level. + * @return zoom level that fits the MapView. + */ + public double calculateZoom(float minScale) { + return nativeMapView.getZoom() + Math.log(minScale) / Math.log(2); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java new file mode 100644 index 000000000..9c2b97b6a --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java @@ -0,0 +1,41 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.RectF; +import android.support.annotation.NonNull; +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 NativeMap nativeMapView; + private final LongSparseArray annotations; + + ShapeAnnotationContainer(NativeMap nativeMapView, LongSparseArray annotations) { + this.nativeMapView = nativeMapView; + this.annotations = annotations; + } + + @NonNull + @Override + public List obtainAllIn(@NonNull RectF rectangle) { + RectF rect = nativeMapView.getDensityDependantRectangle(rectangle); + long[] annotationIds = nativeMapView.queryShapeAnnotations(rect); + return getAnnotationsFromIds(annotationIds); + } + + @NonNull + private List getAnnotationsFromIds(long[] annotationIds) { + List shapeAnnotations = new ArrayList<>(); + for (long annotationId : annotationIds) { + Annotation annotation = annotations.get(annotationId); + if (annotation != null) { + shapeAnnotations.add(annotation); + } + } + return shapeAnnotations; + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java new file mode 100644 index 000000000..f9b2ca10d --- /dev/null +++ b/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 obtainAllIn(RectF rectF); + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java new file mode 100644 index 000000000..b21186050 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -0,0 +1,1150 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.support.annotation.IntRange; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.StringDef; +import android.util.DisplayMetrics; +import android.util.Pair; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.light.Light; +import com.mapbox.mapboxsdk.style.sources.Source; +import com.mapbox.mapboxsdk.utils.BitmapUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The proxy object for current map style. + *

+ * To create new instances of this object, create a new instance using a {@link Builder} and load the style with + * MapboxMap. This object is returned from {@link MapboxMap#getStyle()} once the style + * has been loaded by underlying map. + *

+ */ +@SuppressWarnings("unchecked") +public class Style { + + static final String EMPTY_JSON = "{\"version\": 8,\"sources\": {},\"layers\": []}"; + + private final NativeMap nativeMap; + private final HashMap sources = new HashMap<>(); + private final HashMap layers = new HashMap<>(); + private final HashMap images = new HashMap<>(); + private final Builder builder; + private boolean fullyLoaded; + + /** + * Private constructor to build a style object. + * + * @param builder the builder used for creating this style + * @param nativeMap the map object used to load this style + */ + private Style(@NonNull Builder builder, @NonNull NativeMap nativeMap) { + this.builder = builder; + this.nativeMap = nativeMap; + } + + /** + * Returns the current style url. + * + * @return the style url + * @deprecated use {@link #getUri()} instead + */ + @NonNull + @Deprecated + public String getUrl() { + validateState("getUrl"); + return nativeMap.getStyleUri(); + } + + /** + * Returns the current style uri. + * + * @return the style uri + */ + @NonNull + public String getUri() { + validateState("getUri"); + return nativeMap.getStyleUri(); + } + + /** + * Returns the current style json. + * + * @return the style json + */ + @NonNull + public String getJson() { + validateState("getJson"); + return nativeMap.getStyleJson(); + } + + // + // Source + // + + /** + * Retrieve all the sources in the style + * + * @return all the sources in the current style + */ + @NonNull + public List getSources() { + validateState("getSources"); + return nativeMap.getSources(); + } + + /** + * Adds the source to the map. The source must be newly created and not added to the map before + * + * @param source the source to add + */ + public void addSource(@NonNull Source source) { + validateState("addSource"); + nativeMap.addSource(source); + sources.put(source.getId(), source); + } + + /** + * Retrieve a source by id + * + * @param id the source's id + * @return the source if present in the current style + */ + @Nullable + public Source getSource(String id) { + validateState("getSource"); + Source source = sources.get(id); + if (source == null) { + source = nativeMap.getSource(id); + } + return source; + } + + /** + * Tries to cast the Source to T, throws ClassCastException if it's another type. + * + * @param sourceId the id used to look up a layer + * @param the generic type of a Source + * @return the casted Source, null if another type + */ + @Nullable + public T getSourceAs(@NonNull String sourceId) { + validateState("getSourceAs"); + // noinspection unchecked + if (sources.containsKey(sourceId)) { + return (T) sources.get(sourceId); + } + return (T) nativeMap.getSource(sourceId); + } + + /** + * Removes the source from the style. + * + * @param sourceId the source to remove + * @return the source handle or null if the source was not present + */ + public boolean removeSource(@NonNull String sourceId) { + validateState("removeSource"); + sources.remove(sourceId); + return nativeMap.removeSource(sourceId); + } + + /** + * Removes the source, preserving the reference for re-use + * + * @param source the source to remove + * @return the source + */ + public boolean removeSource(@NonNull Source source) { + validateState("removeSource"); + sources.remove(source.getId()); + return nativeMap.removeSource(source); + } + + // + // Layer + // + + /** + * Adds the layer to the map. The layer must be newly created and not added to the map before + * + * @param layer the layer to add + */ + public void addLayer(@NonNull Layer layer) { + validateState("addLayer"); + nativeMap.addLayer(layer); + layers.put(layer.getId(), layer); + } + + /** + * Adds the layer to the map. The layer must be newly created and not added to the map before + * + * @param layer the layer to add + * @param below the layer id to add this layer before + */ + public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { + validateState("addLayerBelow"); + nativeMap.addLayerBelow(layer, below); + layers.put(layer.getId(), layer); + } + + /** + * Adds the layer to the map. The layer must be newly created and not added to the map before + * + * @param layer the layer to add + * @param above the layer id to add this layer above + */ + public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { + validateState("addLayerAbove"); + nativeMap.addLayerAbove(layer, above); + layers.put(layer.getId(), layer); + } + + /** + * Adds the layer to the map at the specified index. The layer must be newly + * created and not added to the map before + * + * @param layer the layer to add + * @param index the index to insert the layer at + */ + public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { + validateState("addLayerAbove"); + nativeMap.addLayerAt(layer, index); + layers.put(layer.getId(), layer); + } + + /** + * Get the layer by id + * + * @param id the layer's id + * @return the layer, if present in the style + */ + @Nullable + public Layer getLayer(@NonNull String id) { + validateState("getLayer"); + Layer layer = layers.get(id); + if (layer == null) { + layer = nativeMap.getLayer(id); + } + return layer; + } + + /** + * Tries to cast the Layer to T, throws ClassCastException if it's another type. + * + * @param layerId the layer id used to look up a layer + * @param the generic attribute of a Layer + * @return the casted Layer, null if another type + */ + @Nullable + public T getLayerAs(@NonNull String layerId) { + validateState("getLayerAs"); + // noinspection unchecked + return (T) nativeMap.getLayer(layerId); + } + + /** + * Retrieve all the layers in the style + * + * @return all the layers in the current style + */ + @NonNull + public List getLayers() { + validateState("getLayers"); + return nativeMap.getLayers(); + } + + /** + * Removes the layer. Any references to the layer become invalid and should not be used anymore + * + * @param layerId the layer to remove + * @return the removed layer or null if not found + */ + public boolean removeLayer(@NonNull String layerId) { + validateState("removeLayer"); + layers.remove(layerId); + return nativeMap.removeLayer(layerId); + } + + /** + * Removes the layer. The reference is re-usable after this and can be re-added + * + * @param layer the layer to remove + * @return the layer + */ + public boolean removeLayer(@NonNull Layer layer) { + validateState("removeLayer"); + layers.remove(layer.getId()); + return nativeMap.removeLayer(layer); + } + + /** + * Removes the layer. Any other references to the layer become invalid and should not be used anymore + * + * @param index the layer index + * @return the removed layer or null if not found + */ + public boolean removeLayerAt(@IntRange(from = 0) int index) { + validateState("removeLayerAt"); + return nativeMap.removeLayerAt(index); + } + + // + // Image + // + + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + */ + public void addImage(@NonNull String name, @NonNull Bitmap image) { + addImage(name, image, false); + } + + /** + * Adds an drawable to be converted into a bitmap to be used in the map's style + * + * @param name the name of the image + * @param drawable the drawable instance to convert + */ + public void addImage(@NonNull String name, @NonNull Drawable drawable) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImage(name, bitmap, false); + } + + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + */ + public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { + validateState("addImage"); + nativeMap.addImages(new Image[]{toImage(new Builder.ImageWrapper(name, bitmap, sdf))}); + } + + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + */ + public void addImageAsync(@NonNull String name, @NonNull Bitmap image) { + addImageAsync(name, image, false); + } + + /** + * Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style. + * + * @param name the name of the image + * @param drawable the drawable instance to convert + */ + public void addImageAsync(@NonNull String name, @NonNull Drawable drawable) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImageAsync(name, bitmap, false); + } + + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + */ + public void addImageAsync(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { + validateState("addImage"); + new BitmapImageConversionTask(nativeMap).execute(new Builder.ImageWrapper(name, bitmap, sdf)); + } + + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + */ + public void addImages(@NonNull HashMap images) { + addImages(images, false); + } + + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + */ + public void addImages(@NonNull HashMap images, boolean sdf) { + validateState("addImage"); + Image[] convertedImages = new Image[images.size()]; + int index = 0; + for (Builder.ImageWrapper imageWrapper : Builder.ImageWrapper.convertToImageArray(images, sdf)) { + convertedImages[index] = toImage(imageWrapper); + index++; + } + + nativeMap.addImages(convertedImages); + } + + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + */ + public void addImagesAsync(@NonNull HashMap images) { + addImagesAsync(images, false); + } + + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + */ + public void addImagesAsync(@NonNull HashMap images, boolean sdf) { + validateState("addImages"); + new BitmapImageConversionTask(nativeMap).execute(Builder.ImageWrapper.convertToImageArray(images, sdf)); + } + + /** + * Removes an image from the map's style. + * + * @param name the name of the image to remove + */ + public void removeImage(@NonNull String name) { + validateState("removeImage"); + nativeMap.removeImage(name); + } + + /** + * Get an image from the map's style using an id. + * + * @param id the id of the image + * @return the image bitmap + */ + @Nullable + public Bitmap getImage(@NonNull String id) { + validateState("getImage"); + return nativeMap.getImage(id); + } + + // + // Transition + // + + /** + *

+ * Set the transition options for style changes. + *

+ * If not set, any changes take effect without animation, besides symbols, + * which will fade in/out with a default duration after symbol collision detection. + *

+ * To disable symbols fade in/out animation, + * pass transition options with {@link TransitionOptions#enablePlacementTransitions} equal to false. + *

+ * Both {@link TransitionOptions#duration} and {@link TransitionOptions#delay} + * will also change the behavior of the symbols fade in/out animation if the placement transition is enabled. + * + * @param transitionOptions the transition options + */ + public void setTransition(@NonNull TransitionOptions transitionOptions) { + validateState("setTransition"); + nativeMap.setTransitionOptions(transitionOptions); + } + + /** + *

+ * Get the transition options for style changes. + *

+ * By default, any changes take effect without animation, besides symbols, + * which will fade in/out with a default duration after symbol collision detection. + *

+ * To disable symbols fade in/out animation, + * pass transition options with {@link TransitionOptions#enablePlacementTransitions} equal to false + * into {@link #setTransition(TransitionOptions)}. + *

+ * Both {@link TransitionOptions#duration} and {@link TransitionOptions#delay} + * will also change the behavior of the symbols fade in/out animation if the placement transition is enabled. + * + * @return TransitionOptions the transition options + */ + @NonNull + public TransitionOptions getTransition() { + validateState("getTransition"); + return nativeMap.getTransitionOptions(); + } + + // + // Light + // + + /** + * Get the light source used to change lighting conditions on extruded fill layers. + * + * @return the global light source + */ + @Nullable + public Light getLight() { + validateState("getLight"); + return nativeMap.getLight(); + } + + // + // State + // + + /** + * Called when the underlying map will start loading a new style or the map is destroyed. + * This method will clean up this style by setting the java sources and layers + * in a detached state and removing them from core. + */ + void clear() { + fullyLoaded = false; + for (Layer layer : layers.values()) { + if (layer != null) { + layer.setDetached(); + } + } + + for (Source source : sources.values()) { + if (source != null) { + source.setDetached(); + } + } + + for (Map.Entry bitmapEntry : images.entrySet()) { + nativeMap.removeImage(bitmapEntry.getKey()); + bitmapEntry.getValue().recycle(); + } + + sources.clear(); + layers.clear(); + images.clear(); + } + + /** + * Called when the underlying map has finished loading this style. + * This method will add all components added to the builder that were defined with the 'with' prefix. + */ + void onDidFinishLoadingStyle() { + if (!fullyLoaded) { + fullyLoaded = true; + for (Source source : builder.sources) { + addSource(source); + } + + for (Builder.LayerWrapper layerWrapper : builder.layers) { + if (layerWrapper instanceof Builder.LayerAtWrapper) { + addLayerAt(layerWrapper.layer, ((Builder.LayerAtWrapper) layerWrapper).index); + } else if (layerWrapper instanceof Builder.LayerAboveWrapper) { + addLayerAbove(layerWrapper.layer, ((Builder.LayerAboveWrapper) layerWrapper).aboveLayer); + } else if (layerWrapper instanceof Builder.LayerBelowWrapper) { + addLayerBelow(layerWrapper.layer, ((Builder.LayerBelowWrapper) layerWrapper).belowLayer); + } else { + // just add layer to map, but below annotations + addLayerBelow(layerWrapper.layer, MapboxConstants.LAYER_ID_ANNOTATIONS); + } + } + + for (Builder.ImageWrapper image : builder.images) { + addImage(image.id, image.bitmap, image.sdf); + } + + if (builder.transitionOptions != null) { + setTransition(builder.transitionOptions); + } + } + } + + /** + * Returns true if the style is fully loaded. Returns false if style hasn't been fully loaded or a new style is + * underway of being loaded. + * + * @return True if fully loaded, false otherwise + */ + public boolean isFullyLoaded() { + return fullyLoaded; + } + + /** + * Validates the style state, throw an IllegalArgumentException on invalid state. + * + * @param methodCall the calling method name + */ + private void validateState(String methodCall) { + if (!fullyLoaded) { + throw new IllegalStateException( + String.format("Calling %s when a newer style is loading/has loaded.", methodCall) + ); + } + } + + // + // Builder + // + + /** + * Builder for composing a style object. + */ + public static class Builder { + + private final List sources = new ArrayList<>(); + private final List layers = new ArrayList<>(); + private final List images = new ArrayList<>(); + + private TransitionOptions transitionOptions; + private String styleUri; + private String styleJson; + + /** + *

+ * Will loads a new map style asynchronous from the specified URL. + *

+ * {@code url} can take the following forms: + *
    + *
  • {@code Style#StyleUrl}: load one of the bundled styles in {@link Style}.
  • + *
  • {@code mapbox://styles// + \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java new file mode 100644 index 000000000..5ce71ceac --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java @@ -0,0 +1,59 @@ +package com.mapbox.mapboxsdk; + +import android.content.SharedPreferences; +import android.text.format.DateUtils; + +import org.junit.Test; + +import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_PREFERENCE_SKU_TOKEN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AccountsManagerTest { + @Test + public void testIsExpired() { + long now = AccountsManager.getNow(); + + long defaultValue = 0L; + long tooOld = now - DateUtils.HOUR_IN_MILLIS - 1; + long futureValue = now + 1; + long immediatePast = now - 1; + + assertTrue(AccountsManager.isExpired(now, defaultValue)); + assertTrue(AccountsManager.isExpired(now, tooOld)); + + assertFalse(AccountsManager.isExpired(now, futureValue)); + assertFalse(AccountsManager.isExpired(now, immediatePast)); + } + + @Test + public void checksSkuTokenExternalManagement() { + SharedPreferences mockedSharedPreferences = mock(SharedPreferences.class); + when(mockedSharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, "")).thenReturn("external-sku-token"); + boolean isNotManaged = false; + AccountsManager theAccountsManager = new AccountsManager(mockedSharedPreferences, isNotManaged); + + String skuToken = theAccountsManager.getSkuToken(); + + assertEquals("external-sku-token", skuToken); + } + + @Test + public void checksSkuTokenInternalManagement() { + SharedPreferences mockedSharedPreferences = mock(SharedPreferences.class, RETURNS_DEEP_STUBS); + when(mockedSharedPreferences.getString("com.mapbox.mapboxsdk.accounts.userid", "")) + .thenReturn("any-user-id"); + boolean isManaged = true; + AccountsManager theAccountsManager = new AccountsManager(mockedSharedPreferences, isManaged); + + String skuToken = theAccountsManager.getSkuToken(); + + assertFalse(skuToken.isEmpty()); + assertTrue(skuToken.startsWith("100")); + assertTrue(skuToken.endsWith("any-user-id")); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java new file mode 100644 index 000000000..966c75631 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java @@ -0,0 +1,48 @@ +package com.mapbox.mapboxsdk; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.lang.reflect.Field; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MapboxInjector { + + private static final String FIELD_INSTANCE = "INSTANCE"; + private static final String FIELD_ACCOUNTS = "accounts"; + + public static void inject(@NonNull Context context, @NonNull String accessToken) { + inject(context, accessToken, null); + } + + public static void inject(@NonNull Context context, @NonNull String accessToken, @Nullable String skuToken) { + Mapbox mapbox = new Mapbox(context, accessToken); + try { + Field instance = Mapbox.class.getDeclaredField(FIELD_INSTANCE); + instance.setAccessible(true); + instance.set(mapbox, mapbox); + + Field accounts = Mapbox.class.getDeclaredField(FIELD_ACCOUNTS); + accounts.setAccessible(true); + + AccountsManager manager = mock(AccountsManager.class); + when(manager.getSkuToken()).thenReturn(skuToken); + accounts.set(mapbox, manager); + } catch (Exception exception) { + throw new AssertionError(); + } + } + + public static void clear() { + try { + Field field = Mapbox.class.getDeclaredField(FIELD_INSTANCE); + field.setAccessible(true); + field.set(field, null); + } catch (Exception exception) { + throw new AssertionError(); + } + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java new file mode 100644 index 000000000..a4b573672 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java @@ -0,0 +1,109 @@ +package com.mapbox.mapboxsdk; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.DisplayMetrics; + +import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; +import com.mapbox.mapboxsdk.maps.MapView; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertSame; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MapboxTest { + + private Context context; + private Context appContext; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void before() { + context = mock(Context.class); + appContext = mock(Context.class); + when(context.getApplicationContext()).thenReturn(appContext); + } + + @Test + public void testGetAccessToken() { + final String accessToken = "pk.0000000001"; + MapboxInjector.inject(context, accessToken); + assertSame(accessToken, Mapbox.getAccessToken()); + } + + @Test + public void testApplicationContext() { + MapboxInjector.inject(context, "pk.0000000001"); + assertNotNull(Mapbox.getApplicationContext()); + assertNotEquals(context, appContext); + assertEquals(appContext, appContext); + } + + @Test + public void testPkTokenValid() { + assertTrue(Mapbox.isAccessTokenValid("pk.0000000001")); + } + + @Test + public void testSkTokenValid() { + assertTrue(Mapbox.isAccessTokenValid("sk.0000000001")); + } + + @Test + public void testEmptyToken() { + assertFalse(Mapbox.isAccessTokenValid("")); + } + + @Test + public void testNullToken() { + assertFalse(Mapbox.isAccessTokenValid(null)); + } + + @Test + public void testBlaBlaToken() { + assertFalse(Mapbox.isAccessTokenValid("blabla")); + } + + @Test + public void testNoInstance() { + DisplayMetrics displayMetrics = mock(DisplayMetrics.class); + Resources resources = mock(Resources.class); + when(resources.getDisplayMetrics()).thenReturn(displayMetrics); + when(context.getResources()).thenReturn(resources); + TypedArray typedArray = mock(TypedArray.class); + when(context.obtainStyledAttributes(nullable(AttributeSet.class), any(int[].class), anyInt(), anyInt())) + .thenReturn(typedArray); + + expectedException.expect(MapboxConfigurationException.class); + expectedException.expectMessage( + "\nUsing MapView requires calling Mapbox.getInstance(Context context, String accessToken) before " + + "inflating or creating the view. The access token parameter is required when using a Mapbox service." + + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens." + ); + new MapView(context); + } + + @After + public void after() { + MapboxInjector.clear(); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java new file mode 100644 index 000000000..0c61b01be --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java @@ -0,0 +1,93 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class AnnotationTest { + + @InjectMocks + private MapboxMap mapboxMap = mock(MapboxMap.class); + private Annotation annotation; + @NonNull + private Annotation compare = new Annotation() { + @Override + public long getId() { + return 1; + } + }; + + @Before + public void beforeTest() { + annotation = new Annotation() { + // empty child + }; + } + + @Test + public void testSanity() { + assertNotNull("markerOptions should not be null", annotation); + } + + @Test + public void testRemove() { + annotation.setId(1); + annotation.setMapboxMap(mapboxMap); + annotation.remove(); + verify(mapboxMap, times(1)).removeAnnotation(annotation); + } + + @Test + public void testRemoveUnboundMapboxMap() { + annotation.setId(1); + annotation.remove(); + verify(mapboxMap, times(0)).removeAnnotation(annotation); + } + + @Test + public void testCompareToEqual() { + annotation.setId(1); + assertEquals("conparable equal", 0, annotation.compareTo(compare)); + } + + @Test + public void testCompareToHigher() { + annotation.setId(3); + assertEquals("conparable higher", -1, annotation.compareTo(compare)); + } + + @Test + public void testCompareTolower() { + annotation.setId(0); + assertEquals("conparable lower", 1, annotation.compareTo(compare)); + } + + @Test + public void testEquals() { + Annotation holder = null; + assertFalse(annotation.equals(holder)); + holder = annotation; + assertTrue(annotation.equals(holder)); + assertFalse(annotation.equals(new Object())); + } + + @Test + public void testHashcode() { + int id = 1; + annotation.setId(id); + assertSame("hashcode should match", annotation.hashCode(), id); + } + +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java new file mode 100644 index 000000000..e56ca559d --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java @@ -0,0 +1,56 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Bitmap; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotSame; +import static org.mockito.Mockito.when; + +public class IconTest { + + @Mock + Bitmap bitmap; + + @Before + public void beforeTest() { + MockitoAnnotations.initMocks(this); + when(bitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888); + } + + @Test + public void testId() { + String id = "test"; + Icon icon = IconFactory.recreate(id, Bitmap.createBitmap(0, 0, Bitmap.Config.ALPHA_8)); + assertEquals("id should match", id, icon.getId()); + } + + @Test + public void testBitmap() { + Icon icon = IconFactory.recreate("test", bitmap); + assertEquals("bitmap should match", bitmap, icon.getBitmap()); + } + + @Test + public void testEquals() { + Icon icon1 = IconFactory.recreate("test", bitmap); + Icon icon2 = IconFactory.recreate("test", bitmap); + assertEquals("icons should not match", icon1, icon2); + } + + @Test + public void testEqualsObject() { + Icon icon = IconFactory.recreate("test", Bitmap.createBitmap(0, 0, Bitmap.Config.ALPHA_8)); + assertNotSame("icon should not match", new Object(), icon); + } + + @Test + public void testHashcode() { + Icon icon = IconFactory.recreate("test", bitmap); + long expectedHashcode = 31 * bitmap.hashCode() + "test".hashCode(); + assertEquals("hashcode should match", expectedHashcode, icon.hashCode()); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java new file mode 100644 index 000000000..94b629860 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java @@ -0,0 +1,86 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.PointF; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + +import org.junit.Test; +import org.mockito.InjectMocks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class InfoWindowTest { + + @InjectMocks + MapView mMapView = mock(MapView.class); + + @InjectMocks + MapboxMap mMapboxMap = mock(MapboxMap.class); + + @Test + public void testSanity() { + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap); + assertNotNull("infoWindow should exist", infoWindow); + } + + @Test + public void testBoundMarker() { + MarkerOptions markerOptions = new MarkerOptions(); + Marker marker = markerOptions.position(new LatLng()).getMarker(); + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap).setBoundMarker(marker); + assertEquals("marker should match", marker, infoWindow.getBoundMarker()); + } + + @Test + public void testClose() { + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap); + infoWindow.close(); + assertEquals("infowindow should not be visible", false, infoWindow.isVisible()); + } + + + @Test + public void testOpen() { + LatLng latLng = new LatLng(0, 0); + Projection projection = mock(Projection.class); + when(mMapboxMap.getProjection()).thenReturn(projection); + when(projection.toScreenLocation(latLng)).thenReturn(new PointF(0, 0)); + + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap); + infoWindow.open(mMapView, new MarkerOptions().position(new LatLng()).getMarker(), latLng, 0, 0); + assertEquals("infowindow should not be visible", true, infoWindow.isVisible()); + } + + @Test + public void testOpenClose() { + LatLng latLng = new LatLng(0, 0); + Projection projection = mock(Projection.class); + when(mMapboxMap.getProjection()).thenReturn(projection); + when(projection.toScreenLocation(latLng)).thenReturn(new PointF(0, 0)); + + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap); + infoWindow.open(mMapView, new MarkerOptions().position(new LatLng()).getMarker(), latLng, 0, 0); + infoWindow.close(); + assertEquals("infowindow should not be visible", false, infoWindow.isVisible()); + } + + + @Test + public void testUpdate() { + LatLng latLng = new LatLng(0, 0); + Projection projection = mock(Projection.class); + when(mMapboxMap.getProjection()).thenReturn(projection); + when(projection.toScreenLocation(latLng)).thenReturn(new PointF(0, 0)); + + InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap); + infoWindow.open(mMapView, new MarkerOptions().position(latLng).getMarker(), latLng, 0, 0); + infoWindow.update(); + } + +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java new file mode 100644 index 000000000..fa571e06b --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java @@ -0,0 +1,160 @@ +package com.mapbox.mapboxsdk.annotations; + +import android.graphics.Bitmap; +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.utils.MockParcel; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; + +public class MarkerTest { + + @Test + public void testSanity() { + MarkerOptions markerOptions = new MarkerOptions(); + assertNotNull("markerOptions should not be null", markerOptions); + } + + @Test + public void testMarker() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + assertNotNull("marker should not be null", markerOptions.getMarker()); + } + + @Test(expected = InvalidMarkerPositionException.class) + public void testInvalidMarker() { + new MarkerOptions().getMarker(); + } + + @Test + public void testPosition() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(10, 12)); + Marker marker = markerOptions.getMarker(); + assertEquals(marker.getPosition(), new LatLng(10, 12)); + assertEquals(markerOptions.getPosition(), new LatLng(10, 12)); + } + + @Test + public void testTitle() { + MarkerOptions markerOptions = new MarkerOptions().title("Mapbox").position(new LatLng()); + Marker marker = markerOptions.getMarker(); + assertEquals(marker.getTitle(), "Mapbox"); + assertEquals(markerOptions.getTitle(), "Mapbox"); + } + + @Test + public void testSnippet() { + MarkerOptions markerOptions = new MarkerOptions().snippet("Mapbox").position(new LatLng()); + Marker marker = markerOptions.getMarker(); + assertEquals(marker.getSnippet(), "Mapbox"); + } + + @Test + public void testBuilder() { + Marker marker = new MarkerOptions().title("title").snippet("snippet").position(new LatLng(10, 12)).getMarker(); + assertEquals(marker.getSnippet(), "snippet"); + + assertEquals(marker.getPosition(), new LatLng(10, 12)); + } + + @Test + public void testIcon() { + Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_4444); + Icon icon = IconFactory.recreate("test", bitmap); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()).icon(icon); + Marker marker = markerOptions.getMarker(); + assertEquals("Icon should match", icon, marker.getIcon()); + assertEquals("Icon should match", icon, markerOptions.getIcon()); + } + + @Test + public void testHashCode() { + Marker marker = new MarkerOptions().position(new LatLng()).getMarker(); + assertEquals("hash code should match", marker.hashCode(), 0); + } + + @Test + public void testHashCodeBuilder() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(10, 12)); + assertEquals("hash code should match", markerOptions.hashCode(), 579999617); + } + + @Test + public void testEquals() { + Marker markerOne = new MarkerOptions().position(new LatLng(0, 0)).getMarker(); + Marker markerTwo = new MarkerOptions().position(new LatLng(0, 0)).getMarker(); + assertEquals(markerOne, markerTwo); + } + + @Test + public void testEqualityDifferentLocation() { + MarkerOptions marker = new MarkerOptions().position(new LatLng(0, 0)); + MarkerOptions other = new MarkerOptions().position(new LatLng(1, 0)); + assertNotEquals("Should not match", other, marker); + } + + + @Test + public void testEqualityDifferentSnippet() { + MarkerOptions marker = new MarkerOptions().snippet("s"); + MarkerOptions other = new MarkerOptions(); + assertNotEquals("Should not match", other, marker); + } + + @Test + public void testEqualityDifferentIcon() { + MarkerOptions marker = new MarkerOptions().icon(mock(Icon.class)); + MarkerOptions other = new MarkerOptions(); + assertNotEquals("Should not match", other, marker); + } + + @Test + public void testEqualityDifferentTitle() { + MarkerOptions marker = new MarkerOptions().title("t"); + MarkerOptions other = new MarkerOptions(); + assertNotEquals("Should not match", other, marker); + } + + @Test + public void testEqualsItself() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(0, 0)); + Marker marker = markerOptions.getMarker(); + assertEquals("Marker should match", marker, marker); + assertEquals("MarkerOptions should match", markerOptions, markerOptions); + } + + @Test + public void testNotEquals() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(0, 0)); + Marker marker = markerOptions.getMarker(); + assertNotEquals("MarkerOptions should match", markerOptions, new Object()); + assertNotEquals("Marker should match", marker, new Object()); + } + + @Test + public void testEqualityBuilder() { + MarkerOptions markerOne = new MarkerOptions().position(new LatLng(0, 0)); + MarkerOptions markerTwo = new MarkerOptions().position(new LatLng(0, 0)); + assertEquals(markerOne, markerTwo); + } + + @Test + public void testToString() { + Marker marker = new MarkerOptions().position(new LatLng(0, 0)).getMarker(); + assertEquals(marker.toString(), "Marker [position[" + "LatLng [latitude=0.0, longitude=0.0, altitude=0.0]" + "]]"); + } + + @Test + public void testParcelable() { + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()).title("t").snippet("s"); + Parcelable parcelable = MockParcel.obtain(markerOptions); + assertEquals("Parcel should match original object", parcelable, markerOptions); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java new file mode 100644 index 000000000..3933c6888 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java @@ -0,0 +1,75 @@ +package com.mapbox.mapboxsdk.annotations; + +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class PolygonTest { + + @Test + public void testSanity() { + PolygonOptions polygonOptions = new PolygonOptions(); + assertNotNull("polygonOptions should not be null", polygonOptions); + } + + @Test + public void testPolygon() { + Polygon polygon = new PolygonOptions().getPolygon(); + assertNotNull("polyline should not be null", polygon); + } + + @Test + public void testAlpha() { + Polygon polygon = new PolygonOptions().alpha(0.5f).getPolygon(); + assertEquals(0.5f, polygon.getAlpha(), 0.0f); + } + + @Test + public void testStrokeColor() { + Polygon polygon = new PolygonOptions().strokeColor(1).getPolygon(); + assertEquals(1, polygon.getStrokeColor()); + } + + @Test + public void testFillColor() { + Polygon polygon = new PolygonOptions().fillColor(1).getPolygon(); + assertEquals(1, polygon.getFillColor()); + } + + @Test + public void testLatLng() { + Polygon polygon = new PolygonOptions().add(new LatLng(0, 0)).getPolygon(); + assertNotNull("points should not be null", polygon.getPoints()); + assertEquals(new LatLng(0, 0), polygon.getPoints().get(0)); + } + + @Test + public void testAddAllLatLng() { + List coordinates = new ArrayList<>(); + coordinates.add(new LatLng(0, 0)); + Polygon polygon = new PolygonOptions().addAll(coordinates).getPolygon(); + assertNotNull(polygon.getPoints()); + assertEquals(new LatLng(0, 0), polygon.getPoints().get(0)); + } + + @Test + public void testBuilder() { + PolylineOptions polylineOptions = new PolylineOptions(); + polylineOptions.width(1.0f); + polylineOptions.color(2); + polylineOptions.add(new LatLng(0, 0)); + + Polyline polyline = polylineOptions.getPolyline(); + assertEquals(1.0f, polyline.getWidth(), 0); + assertEquals(2, polyline.getColor()); + assertNotNull("Points should not be null", polyline.getPoints()); + assertEquals(new LatLng(0, 0), polyline.getPoints().get(0)); + } + +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java new file mode 100644 index 000000000..54bb0e8cf --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java @@ -0,0 +1,75 @@ +package com.mapbox.mapboxsdk.annotations; + +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class PolylineTest { + + @Test + public void testSanity() { + PolylineOptions polylineOptions = new PolylineOptions(); + assertNotNull("polylineOptions should not be null", polylineOptions); + } + + @Test + public void testPolyline() { + Polyline polyline = new PolylineOptions().getPolyline(); + assertNotNull("polyline should not be null", polyline); + } + + @Test + public void testAlpha() { + Polyline polyline = new PolylineOptions().alpha(0.2f).getPolyline(); + assertEquals(0.2f, polyline.getAlpha(), 0.0f); + } + + @Test + public void testWidth() { + Polyline polyline = new PolylineOptions().width(1).getPolyline(); + assertEquals(1.0f, polyline.getWidth(), 0); + } + + @Test + public void testColor() { + Polyline polyline = new PolylineOptions().color(1).getPolyline(); + assertEquals(1, polyline.getColor()); + } + + @Test + public void testAddLatLng() { + Polyline polyline = new PolylineOptions().add(new LatLng(0, 0)).getPolyline(); + assertNotNull("Points should not be null", polyline.getPoints()); + assertEquals(new LatLng(0, 0), polyline.getPoints().get(0)); + } + + @Test + public void testAddAllLatLng() { + List coordinates = new ArrayList<>(); + coordinates.add(new LatLng(0, 0)); + Polyline polyline = new PolylineOptions().addAll(coordinates).getPolyline(); + assertNotNull(polyline.getPoints()); + assertEquals(new LatLng(0, 0), polyline.getPoints().get(0)); + } + + @Test + public void testBuilder() { + PolylineOptions polylineOptions = new PolylineOptions(); + polylineOptions.width(1.0f); + polylineOptions.color(2); + polylineOptions.add(new LatLng(0, 0)); + + Polyline polyline = polylineOptions.getPolyline(); + assertEquals(1.0f, polyline.getWidth(), 0); + assertEquals(2, polyline.getColor()); + assertNotNull("Points should not be null", polyline.getPoints()); + assertEquals(new LatLng(0, 0), polyline.getPoints().get(0)); + } + +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java new file mode 100644 index 000000000..b72e85270 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java @@ -0,0 +1,322 @@ +package com.mapbox.mapboxsdk.attribution; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.Set; + +import static junit.framework.Assert.assertEquals; + +@RunWith(RobolectricTestRunner.class) +public class AttributionParseTest { + + private static final String STREETS_ATTRIBUTION = "© Mapbox © OpenStreetMap Improve this map\n"; + private static final String SATELLITE_ATTRIBUTION = "© Mapbox © OpenStreetMap Improve this map © DigitalGlobe\n"; + + @Test + public void testParseAttributionStringSatellite() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(SATELLITE_ATTRIBUTION) + .build(); + + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 4, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL mapbox should match", "https://www.mapbox.com/about/maps/", attribution.getUrl()); + assertEquals("Title mapbox should match", "© Mapbox", attribution.getTitle()); + break; + case 1: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "© OpenStreetMap", attribution.getTitle()); + break; + case 2: + assertEquals("URL improve map should match", "https://apps.mapbox.com/feedback/", attribution.getUrl()); + assertEquals("Title improve map should match", "Improve This Map", attribution.getTitle()); + break; + case 3: + assertEquals("URL digital globe should match", "https://www.digitalglobe.com/", attribution.getUrl()); + assertEquals("Title digital globe should match", "© DigitalGlobe", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testParseAttributionStringStreets() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .build(); + + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 3, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL mapbox should match", "https://www.mapbox.com/about/maps/", attribution.getUrl()); + assertEquals("Title mapbox should match", "© Mapbox", attribution.getTitle()); + break; + case 1: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "© OpenStreetMap", attribution.getTitle()); + break; + case 2: + assertEquals("URL improve map should match", "https://apps.mapbox.com/feedback/", attribution.getUrl()); + assertEquals("Title improve map should match", "Improve This Map", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testParseAttributionWithoutMapbox() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .withMapboxAttribution(false) + .build(); + + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 2, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "© OpenStreetMap", attribution.getTitle()); + break; + case 1: + assertEquals("URL improve map should match", "https://apps.mapbox.com/feedback/", attribution.getUrl()); + assertEquals("Title improve map should match", "Improve This Map", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testParseAttributionArrayString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(new String[] {STREETS_ATTRIBUTION, "", SATELLITE_ATTRIBUTION}) + .build(); + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 4, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL mapbox should match", "https://www.mapbox.com/about/maps/", attribution.getUrl()); + assertEquals("Title mapbox should match", "© Mapbox", attribution.getTitle()); + break; + case 1: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "© OpenStreetMap", attribution.getTitle()); + break; + case 2: + assertEquals("URL improve map should match", "https://apps.mapbox.com/feedback/", attribution.getUrl()); + assertEquals("Title improve map should match", "Improve This Map", attribution.getTitle()); + break; + case 3: + assertEquals("URL digital globe should match", "https://www.digitalglobe.com/", attribution.getUrl()); + assertEquals("Title digital globe should match", "© DigitalGlobe", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testHideImproveThisMapAttributionArrayString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(SATELLITE_ATTRIBUTION) + .withImproveMap(false) + .build(); + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 3, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL mapbox should match", "https://www.mapbox.com/about/maps/", attribution.getUrl()); + assertEquals("Title mapbox should match", "© Mapbox", attribution.getTitle()); + break; + case 1: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "© OpenStreetMap", attribution.getTitle()); + break; + case 2: + assertEquals("URL digital globe should match", "https://www.digitalglobe.com/", attribution.getUrl()); + assertEquals("Title digital globe should match", "© DigitalGlobe", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testParseHideCopyrightAttributionArrayString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION, "", SATELLITE_ATTRIBUTION) + .withCopyrightSign(false) + .build(); + Set attributionList = attributionParser.getAttributions(); + assertEquals("Size of list should match", 4, attributionList.size()); + + int counter = 0; + for (Attribution attribution : attributionList) { + switch (counter) { + case 0: + assertEquals("URL mapbox should match", "https://www.mapbox.com/about/maps/", attribution.getUrl()); + assertEquals("Title mapbox should match", "Mapbox", attribution.getTitle()); + break; + case 1: + assertEquals("URL openstreetmap should match", "http://www.openstreetmap.org/about/", attribution.getUrl()); + assertEquals("Title openstreetmap should match", "OpenStreetMap", attribution.getTitle()); + break; + case 2: + assertEquals("URL improve map should match", "https://apps.mapbox.com/feedback/", attribution.getUrl()); + assertEquals("Title improve map should match", "Improve This Map", attribution.getTitle()); + break; + case 3: + assertEquals("URL digital globe should match", "https://www.digitalglobe.com/", attribution.getUrl()); + assertEquals("Title digital globe should match", "DigitalGlobe", attribution.getTitle()); + break; + } + counter++; + } + } + + @Test + public void testOutputWithoutCopyRightString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .withCopyrightSign(false) + .withImproveMap(false) + .build(); + + assertEquals( + "Attribution string should match", + "© Mapbox / OpenStreetMap", + attributionParser.createAttributionString() + ); + } + + + @Test + public void testOutputWithCopyRightString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .withImproveMap(false) + .build(); + + assertEquals( + "Attribution string should match", + "© Mapbox / © OpenStreetMap", + attributionParser.createAttributionString() + ); + } + + @Test + public void testOutputWithoutCopyRightWithoutMapboxString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .withCopyrightSign(false) + .withImproveMap(false) + .withMapboxAttribution(false) + .build(); + + assertEquals( + "Attribution string should match", + "© OpenStreetMap", + attributionParser.createAttributionString() + ); + } + + @Test + public void testOutputWithCopyRightWithoutMapboxString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION) + .withImproveMap(false) + .withMapboxAttribution(false) + .build(); + + assertEquals( + "Attribution string should match", + "© OpenStreetMap", + attributionParser.createAttributionString() + ); + } + + @Test + public void testOutputSatelliteString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION, SATELLITE_ATTRIBUTION, "blabla", "") + .withImproveMap(false) + .withCopyrightSign(false) + .withMapboxAttribution(false) + .build(); + + assertEquals( + "Attribution string should match", + "© OpenStreetMap / DigitalGlobe", + attributionParser.createAttributionString() + ); + } + + @Test + public void testShortOpenStreetMapString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION, SATELLITE_ATTRIBUTION, "blabla", "") + .withImproveMap(false) + .withCopyrightSign(false) + .withMapboxAttribution(false) + .build(); + + assertEquals( + "Attribution string should match", + "© OSM / DigitalGlobe", + attributionParser.createAttributionString(true) + ); + } + + @Test + public void testShortOpenStreetMapWithoutCopyrightString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION, SATELLITE_ATTRIBUTION, "blabla", "") + .withImproveMap(false) + .withCopyrightSign(false) + .build(); + + assertEquals( + "Attribution string should match", + "© Mapbox / OSM / DigitalGlobe", + attributionParser.createAttributionString(true) + ); + } + + @Test + public void testWithImproveThisMapString() throws Exception { + AttributionParser attributionParser = new AttributionParser.Options(RuntimeEnvironment.application) + .withAttributionData(STREETS_ATTRIBUTION, "blabla", "") + .withImproveMap(true) + .withCopyrightSign(false) + .build(); + + assertEquals( + "Attribution string should match", + "© Mapbox / OSM / Improve This Map", + attributionParser.createAttributionString(true) + ); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java new file mode 100644 index 000000000..6974705fa --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java @@ -0,0 +1,120 @@ +package com.mapbox.mapboxsdk.camera; + +import android.content.res.TypedArray; +import android.os.Parcel; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +public class CameraPositionTest { + + private static final double DELTA = 1e-15; + + @Test + public void testSanity() { + LatLng latLng = new LatLng(1, 2); + CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0}); + assertNotNull("cameraPosition should not be null", cameraPosition); + } + + @Test + public void testDefaultTypedArrayBuilder() { + TypedArray typedArray = null; + CameraPosition cameraPosition = new CameraPosition.Builder(typedArray).build(); + assertEquals("bearing should match", -1, cameraPosition.bearing, DELTA); + assertNull("latlng should be null", cameraPosition.target); + assertEquals("tilt should match", -1, cameraPosition.tilt, DELTA); + assertEquals("zoom should match", -1, cameraPosition.zoom, DELTA); + assertNull("padding should be null", cameraPosition.padding); + } + + @Test + public void testTypedArrayBuilder() { + float bearing = 180; + float zoom = 12; + float latitude = 10; + float longitude = 11; + float tilt = 44; + + TypedArray typedArray = mock(TypedArray.class); + when(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraBearing, 0.0f)).thenReturn(bearing); + when(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLat, 0.0f)).thenReturn(latitude); + when(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLng, 0.0f)).thenReturn(longitude); + when(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoom, 0.0f)).thenReturn(zoom); + when(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTilt, 0.0f)).thenReturn(tilt); + doNothing().when(typedArray).recycle(); + + CameraPosition cameraPosition = new CameraPosition.Builder(typedArray).build(); + assertEquals("bearing should match", bearing, cameraPosition.bearing, DELTA); + assertEquals("latlng should match", new LatLng(latitude, longitude), cameraPosition.target); + assertEquals("tilt should match", tilt, cameraPosition.tilt, DELTA); + assertEquals("zoom should match", zoom, cameraPosition.zoom, DELTA); + } + + @Test + public void testToString() { + LatLng latLng = new LatLng(1, 2); + CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0}); + assertEquals("toString should match", "Target: LatLng [latitude=1.0, longitude=2.0, altitude=0.0], Zoom:3.0, " + + "Bearing:5.0, Tilt:4.0, Padding:[0.0, 500.0, 0.0, 0.0]", cameraPosition.toString()); + } + + @Test + public void testHashcode() { + LatLng latLng = new LatLng(1, 2); + CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0}); + assertEquals("hashCode should match", -420915327, cameraPosition.hashCode()); + } + + @Test + public void testZoomUpdateBuilder() { + float zoomLevel = 5; + CameraPosition.Builder builder = new CameraPosition.Builder( + (CameraUpdateFactory.ZoomUpdate) CameraUpdateFactory.zoomTo(zoomLevel)); + assertEquals("zoom should match", zoomLevel, builder.build().zoom, 0); + } + + @Test + public void testEquals() { + LatLng latLng = new LatLng(1, 2); + CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0}); + CameraPosition cameraPositionBearing = new CameraPosition(latLng, 3, 4, 9, new double[] {0, 500, 0, 0}); + CameraPosition cameraPositionTilt = new CameraPosition(latLng, 3, 9, 5, new double[] {0, 500, 0, 0}); + CameraPosition cameraPositionZoom = new CameraPosition(latLng, 9, 4, 5, new double[] {0, 500, 0, 0}); + CameraPosition cameraPositionTarget = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 500, 0, 0}); + CameraPosition cameraPositionPadding = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 501, 0, 0}); + + assertEquals("cameraPosition should match itself", cameraPosition, cameraPosition); + assertNotEquals("cameraPosition should not match null", null, cameraPosition); + assertNotEquals("cameraPosition should not match object", new Object(), cameraPosition); + assertNotEquals("cameraPosition should not match for bearing", cameraPositionBearing, cameraPosition); + assertNotEquals("cameraPosition should not match for tilt", cameraPositionTilt, cameraPosition); + assertNotEquals("cameraPosition should not match for zoom", cameraPositionZoom, cameraPosition); + assertNotEquals("cameraPosition should not match for target", cameraPositionTarget, cameraPosition); + assertNotEquals("cameraPosition should not match for padding", cameraPositionPadding, cameraPosition); + } + + @Test + public void testParcelable() { + CameraPosition cameraPosition1 = new CameraPosition(new LatLng(1, 2), 3, 4, 5, new double[] {0, 500, 0, 0}); + Parcel parcel = Parcel.obtain(); + cameraPosition1.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel); + assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java new file mode 100644 index 000000000..cb654aa55 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java @@ -0,0 +1,6 @@ +package com.mapbox.mapboxsdk.constants; + +public class AppConstant { + + public static final int STYLE_VERSION = 9; +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java new file mode 100644 index 000000000..6c44c29e3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -0,0 +1,813 @@ +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; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.assertNotNull; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class LatLngBoundsTest { + + private static final double DELTA = 1e-15; + + private LatLngBounds latLngBounds; + private static final LatLng LAT_LNG_NULL_ISLAND = new LatLng(0, 0); + private static final LatLng LAT_LNG_NOT_NULL_ISLAND = new LatLng(2, 2); + + @Before + public void beforeTest() { + latLngBounds = new LatLngBounds.Builder() + .include(LAT_LNG_NULL_ISLAND) + .include(LAT_LNG_NOT_NULL_ISLAND) + .build(); + } + + @Test + public void testSanity() { + LatLngBounds.Builder latLngBoundsBuilder = new LatLngBounds.Builder(); + latLngBoundsBuilder.include(LAT_LNG_NULL_ISLAND).include(LAT_LNG_NOT_NULL_ISLAND); + assertNotNull("latLng should not be null", latLngBoundsBuilder.build()); + } + + @Test(expected = InvalidLatLngBoundsException.class) + public void noLatLngs() { + new LatLngBounds.Builder().build(); + } + + @Test(expected = InvalidLatLngBoundsException.class) + public void oneLatLngs() { + new LatLngBounds.Builder().include(LAT_LNG_NULL_ISLAND).build(); + } + + @Test + public void latitiudeSpan() { + assertEquals("Span should be the same", 2, latLngBounds.getLatitudeSpan(), DELTA); + } + + @Test + public void longitudeSpan() { + assertEquals("Span should be the same", 2, latLngBounds.getLongitudeSpan(), DELTA); + } + + @Test + public void coordinateSpan() { + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", new LatLngSpan(2, 2), latLngSpan); + } + + @Test + public void dateLineSpanBuilder1() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", new LatLngSpan(20, 340), + latLngSpan); + } + + @Test + public void dateLineSpanBuilder2() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(-10, -170)) + .include(new LatLng(10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", new LatLngSpan(20, 340), + latLngSpan); + } + + @Test + public void dateLineSpanFrom1() { + latLngBounds = LatLngBounds.from(10, -170, -10, -190); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanFrom2() { + latLngBounds = LatLngBounds.from(10, 170, -10, -170); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", new LatLngSpan(20, 340), + latLngSpan); + } + + @Test + public void zeroLongitudeSpan() { + latLngBounds = LatLngBounds.from(10, 10, -10, 10); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 0), + latLngSpan); + } + + @Test + public void nearDateLineCenter1() { + latLngBounds = LatLngBounds.from(10, -175, -10, -195); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -185), center); + } + + @Test + public void nearDateLineCenter2() { + latLngBounds = LatLngBounds.from(10, 195, -10, 175); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 185), center); + } + + @Test + public void nearDateLineCenter3() { + latLngBounds = LatLngBounds.from(10, -170, -10, -190); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -180), center); + } + + @Test + public void nearDateLineCenter4() { + latLngBounds = LatLngBounds.from(10, 180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + @Test + public void nearDateLineCenter5() { + latLngBounds = LatLngBounds.from(10, 180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + @Test + public void centerForBoundsWithSameLongitude() { + latLngBounds = LatLngBounds.from(10, 10, -10, 10); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 10), center); + } + + @Test + public void centerForBoundsWithSameLatitude() { + latLngBounds = LatLngBounds.from(10, 10, 10, -10); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(10, 0), center); + } + + @Test + public void center() { + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(1, 1), center); + } + + @Test + public void notEmptySpan() { + latLngBounds = new LatLngBounds.Builder() + .include(LAT_LNG_NOT_NULL_ISLAND) + .include(LAT_LNG_NULL_ISLAND) + .build(); + assertFalse("Should not be empty", latLngBounds.isEmptySpan()); + } + + @Test + public void includeSameLatLngs() { + latLngBounds = new LatLngBounds.Builder() + .include(LAT_LNG_NOT_NULL_ISLAND) + .include(LAT_LNG_NOT_NULL_ISLAND) + .include(LAT_LNG_NULL_ISLAND) + .include(LAT_LNG_NULL_ISLAND) + .build(); + assertEquals(latLngBounds.getNorthEast(), LAT_LNG_NOT_NULL_ISLAND); + assertEquals(latLngBounds.getSouthWest(), LAT_LNG_NULL_ISLAND); + } + + @Test + public void toLatLngs() { + latLngBounds = new LatLngBounds.Builder() + .include(LAT_LNG_NOT_NULL_ISLAND) + .include(LAT_LNG_NULL_ISLAND) + .build(); + + assertArrayEquals("LatLngs should match", + new LatLng[] {LAT_LNG_NOT_NULL_ISLAND, LAT_LNG_NULL_ISLAND}, + latLngBounds.toLatLngs()); + } + + @Test + public void include() { + assertTrue("LatLng should be included", latLngBounds.contains(new LatLng(1, 1))); + } + + @Test + public void includes() { + List points = new ArrayList<>(); + points.add(LAT_LNG_NULL_ISLAND); + points.add(LAT_LNG_NOT_NULL_ISLAND); + + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .includes(points) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(LAT_LNG_NULL_ISLAND) + .include(LAT_LNG_NOT_NULL_ISLAND) + .build(); + + assertEquals("LatLngBounds should match", latLngBounds1, latLngBounds2); + } + + @Test + public void includesOrderDoesNotMatter() { + LatLngBounds sameLongitudeFirst = new LatLngBounds.Builder() + .include(new LatLng(50, 10)) // southWest + .include(new LatLng(60, 10)) + .include(new LatLng(60, 20)) // northEast + .include(new LatLng(50, 20)) + .include(new LatLng(50, 10)) // southWest again + .build(); + + LatLngBounds sameLatitudeFirst = new LatLngBounds.Builder() + .include(new LatLng(50, 20)) + .include(new LatLng(50, 10)) // southWest + .include(new LatLng(60, 10)) + .include(new LatLng(60, 20)) // northEast + .include(new LatLng(50, 20)) + .build(); + + assertEquals(sameLatitudeFirst, sameLongitudeFirst); + } + + @Test + public void includesOverDateline1() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, -175)) + .include(new LatLng(0, -190)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngSpan); + } + + @Test + public void includesOverDateline2() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(-10, 175)) + .include(new LatLng(0, 190)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void includesOverDateline3() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -190)) + .include(new LatLng(-10, -170)) + .include(new LatLng(0, -180)) + .include(new LatLng(5, -180)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void containsNot() { + assertFalse("LatLng should not be included", + latLngBounds.contains(new LatLng(3, 1))); + } + + @Test + public void containsBoundsInWorld() { + assertTrue("LatLngBounds should be contained in the world", + LatLngBounds.world().contains(latLngBounds)); + } + + @Test + public void worldSpan() { + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LATITUDE_SPAN, LatLngBounds.world().getLatitudeSpan(), DELTA); + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LONGITUDE_SPAN, LatLngBounds.world().getLongitudeSpan(), DELTA); + } + + @Test + public void emptySpan() { + LatLngBounds latLngBounds = LatLngBounds.from( + GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE, + GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE); + assertTrue("LatLngBounds empty span", latLngBounds.isEmptySpan()); + } + + @Test + public void containsBounds() { + LatLngBounds inner = new LatLngBounds.Builder() + .include(new LatLng(-5, -5)) + .include(new LatLng(5, 5)) + .build(); + LatLngBounds outer = new LatLngBounds.Builder() + .include(new LatLng(-10, -10)) + .include(new LatLng(10, 10)) + .build(); + assertTrue(outer.contains(inner)); + assertFalse(inner.contains(outer)); + } + + @Test + public void testHashCode() { + assertEquals(2147483647, latLngBounds.hashCode(), -1946419200); + } + + @Test + public void equality() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(LAT_LNG_NULL_ISLAND) + .include(LAT_LNG_NOT_NULL_ISLAND) + .build(); + assertEquals("equality should match", this.latLngBounds, latLngBounds); + assertEquals("not equal to a different object type", + this.latLngBounds.equals(LAT_LNG_NOT_NULL_ISLAND), false); + } + + @Test + public void testToString() { + assertEquals(latLngBounds.toString(), "N:2.0; E:2.0; S:0.0; W:0.0"); + } + + @Test + public void intersect() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(1, 1)) + .include(LAT_LNG_NULL_ISLAND) + .build(); + assertEquals("intersect should match", latLngBounds, + latLngBounds.intersect(this.latLngBounds.getLatNorth(), + this.latLngBounds.getLonEast(), + this.latLngBounds.getLatSouth(), + this.latLngBounds.getLonWest())); + } + + @Test + public void intersectNot() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 10)) + .include(new LatLng(9, 8)) + .build(); + assertNull(latLngBounds.intersect(this.latLngBounds)); + } + + @Test + public void intersectNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .intersect(200, 200, 0, 0); + } + + @Test + public void intersectSouthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(0, 0, -10, -10) + .intersect(0, 0, -200, -200); + } + + @Test + public void intersectSouthLessThanNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latNorth cannot be less than latSouth"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .intersect(0, 200, 20, 0); + } + + @Test + public void intersectEastLessThanWestCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("lonEast cannot be less than lonWest"); + LatLngBounds intersectLatLngBounds = + LatLngBounds.from(10, -10, 0, 0) + .intersect(0, 200, 20, 0); + } + + public void intersectEastDoesNotWrapCheck() { + + LatLngBounds latLngBounds1 = LatLngBounds.from(10, 210, 0, 0); + LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0); + + LatLngBounds intersectLatLngBounds = LatLngBounds.from(10, 200, 0, 0); + + assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds); + assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds); + } + + @Test + public void intersectDoesNotWestWrapCheck() { + LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, -210); + LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200); + + LatLngBounds intersectLatLngBounds = LatLngBounds.from(0, 0, -10, -200); + + assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds); + assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds); + } + + @Test + public void innerUnion() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(1, 1)) + .include(LAT_LNG_NULL_ISLAND) + .build(); + assertEquals("union should match", latLngBounds, latLngBounds.intersect(this.latLngBounds)); + } + + @Test + public void outerUnion() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 10)) + .include(new LatLng(9, 8)) + .build(); + assertEquals("outer union should match", + latLngBounds.union(this.latLngBounds), + new LatLngBounds.Builder() + .include(new LatLng(10, 10)) + .include(LAT_LNG_NULL_ISLAND) + .build()); + } + + @Test + public void unionOverDateLine() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 190)) + .include(new LatLng(-10, 200)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, 200)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine2() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 165)) + .include(new LatLng(-10, 200)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, 200)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine3() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 195)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 190)) + .include(new LatLng(-10, 200)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, 200)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine4() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, -160)) + .include(new LatLng(0, -200)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, -170)) + .include(new LatLng(-10, -175)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, -200)) + .include(new LatLng(-10, -160)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLine5() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 200)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, 170)) + .include(new LatLng(-10, 175)) + .build(); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, 200)) + .build()); + + assertEquals(union1, union2); + } + + @Test + public void unionOverDateLineReturnLongerThanWorldLonSpan() { + LatLngBounds latLngBounds1 = LatLngBounds.from(10, 200, -10, -10); + LatLngBounds latLngBounds2 = LatLngBounds.from(10, 10, -10, -200); + + LatLngBounds union1 = latLngBounds1.union(latLngBounds2); + LatLngBounds union2 = latLngBounds2.union(latLngBounds1); + + assertEquals(union1, union2); + assertEquals(union1, LatLngBounds.from(10, 200, -10, -200)); + } + + @Test + public void unionNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds unionLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .union(200, 200, 0, 0); + } + + @Test + public void unionSouthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds unionLatLngBounds = + LatLngBounds.from(0, 0, -10, -10) + .union(0, 0, -200, -200); + } + + @Test + public void unionSouthLessThanNorthCheck() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latNorth cannot be less than latSouth"); + + LatLngBounds unionLatLngBounds = + LatLngBounds.from(10, 10, 0, 0) + .union(0, 200, 20, 0); + } + + + @Test + public void unionEastDoesNotWrapCheck() { + + LatLngBounds latLngBounds1 = LatLngBounds.from(10, 10, 0, 0); + LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0); + LatLngBounds unionLatLngBounds = LatLngBounds.from(90, 200, 0, 0); + + assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds); + assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds); + } + + @Test + public void unionWestDoesNotWrapCheck() { + LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, -10); + LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200); + + LatLngBounds unionLatLngBounds = LatLngBounds.from(0, 0, -90, -200); + + assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds); + assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds); + } + + @Test + public void northWest() { + double minLat = 5; + double minLon = 6; + double maxLat = 20; + double maxLon = 21; + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(minLat, minLon)) + .include(new LatLng(maxLat, maxLon)) + .build(); + + assertEquals("NorthWest should match", latLngBounds.getNorthWest(), new LatLng(maxLat, minLon)); + } + + @Test + public void southWest() { + double minLat = 5; + double minLon = 6; + double maxLat = 20; + double maxLon = 21; + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(minLat, minLon)) + .include(new LatLng(maxLat, maxLon)) + .build(); + + assertEquals("SouthWest should match", latLngBounds.getSouthWest(), new LatLng(minLat, minLon)); + } + + @Test + public void northEast() { + double minLat = 5; + double minLon = 6; + double maxLat = 20; + double maxLon = 21; + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(minLat, minLon)) + .include(new LatLng(maxLat, maxLon)) + .build(); + + assertEquals("NorthEast should match", latLngBounds.getNorthEast(), new LatLng(maxLat, maxLon)); + } + + @Test + public void southEast() { + double minLat = 5; + double minLon = 6; + double maxLat = 20; + double maxLon = 21; + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(minLat, minLon)) + .include(new LatLng(maxLat, maxLon)) + .build(); + + assertEquals("SouthEast should match", latLngBounds.getSouthEast(), new LatLng(minLat, maxLon)); + } + + @Test + public void testParcelable() { + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 10)) + .include(new LatLng(9, 8)) + .build(); + 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_WRAP_LONGITUDE, bounds.getLonWest(), DELTA); + assertEquals(GeometryConstants.MIN_MERCATOR_LATITUDE, bounds.getLatSouth(), DELTA); + assertEquals(GeometryConstants.MAX_WRAP_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); + + } + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testConstructorChecksNorthLatitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must not be NaN"); + LatLngBounds.from(Double.NaN, 0, -20, -20); + } + + @Test + public void testConstructorChecksEastLongitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be NaN"); + LatLngBounds.from(0, Double.NaN, -20, -20); + } + + @Test + public void testConstructorChecksNorthLatitudeGreaterThan90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds.from(95, 0, -20, -20); + } + + @Test + public void testConstructorChecksNorthLatitudeLessThanThanNegative90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds.from(-95, 0, -20, -20); + } + + @Test + public void testConstructorChecksEastLongitudeInfinity() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be infinite"); + LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); + } + + @Test + public void testConstructorChecksSouthLatitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must not be NaN"); + LatLngBounds.from(20, 20, Double.NaN, 0); + } + + @Test + public void testConstructorChecksWesttLongitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be NaN"); + LatLngBounds.from(20, 20, 0, Double.NaN); + } + + @Test + public void testConstructorChecksSouthLatitudeGreaterThan90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds.from(20, 20, 95, 0); + } + + @Test + public void testConstructorChecksSouthLatitudeLessThanThanNegative90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + LatLngBounds.from(20, 20, -95, 0); + } + + @Test + public void testConstructorChecksWestLongitudeInfinity() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be infinite"); + LatLngBounds.from(20, 20, 0, Double.POSITIVE_INFINITY); + } + + @Test + public void testConstructorCheckLatSouthGreaterLatNorth() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latNorth cannot be less than latSouth"); + LatLngBounds.from(0, 20, 20, 0); + } + + @Test + public void testConstructorCheckLonWestGreaterLonEast() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("lonEast cannot be less than lonWest"); + LatLngBounds.from(20, 0, 0, 20); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java new file mode 100644 index 000000000..12297247c --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java @@ -0,0 +1,65 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.utils.MockParcel; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class LatLngSpanTest { + + private static final double DELTA = 1e-15; + private static final LatLng LAT_LNG_NULL_ISLAND = new LatLng(0, 0); + + @Test + public void testSanity() { + LatLngSpan latLngSpan = new LatLngSpan(0.0, 0.0); + assertNotNull("latLngSpan should not be null", latLngSpan); + } + + @Test + public void testEquality() { + LatLngSpan latLngSpan = new LatLngSpan(0.0, 0.0); + assertEquals("latLngSpan is not equal to a LatLng", latLngSpan.equals(LAT_LNG_NULL_ISLAND), false); + } + + @Test + public void testLatitudeConstructor() { + double latitude = 1.23; + LatLngSpan latLngSpan = new LatLngSpan(latitude, 0.0); + assertEquals("latitude in constructor", latLngSpan.getLatitudeSpan(), latitude, DELTA); + } + + @Test + public void testLongitudeConstructor() { + double longitude = 1.23; + LatLngSpan latLngSpan = new LatLngSpan(0.0, longitude); + assertEquals("latitude in constructor", latLngSpan.getLongitudeSpan(), longitude, DELTA); + } + + @Test + public void testLatitudeMethod() { + double latitude = 1.23; + LatLngSpan latLngSpan = new LatLngSpan(0.0, 0.0); + latLngSpan.setLatitudeSpan(latitude); + assertEquals("latitude in constructor", latLngSpan.getLatitudeSpan(), latitude, DELTA); + } + + @Test + public void testLongitudeMethod() { + double longitude = 1.23; + LatLngSpan latLngSpan = new LatLngSpan(0.0, 0.0); + latLngSpan.setLongitudeSpan(longitude); + assertEquals("latitude in constructor", latLngSpan.getLongitudeSpan(), longitude, DELTA); + } + + @Test + public void testParcelable() { + LatLngSpan object = new LatLngSpan(1, 2); + Parcelable parcel = MockParcel.obtain(object); + assertEquals("parcel should match initial object", object, parcel); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java new file mode 100644 index 000000000..862c56a52 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java @@ -0,0 +1,286 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.location.Location; +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.utils.MockParcel; + +import org.junit.Test; +import org.junit.Rule; +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; + +public class LatLngTest { + + private static final double DELTA = 1e-15; + + @Test + public void testSanity() { + LatLng latLng = new LatLng(0.0, 0.0); + assertNotNull("latLng should not be null", latLng); + } + + @Test + public void testLatitudeEmptyConstructor() { + LatLng latLng = new LatLng(); + assertEquals("latitude default value", latLng.getLatitude(), 0, DELTA); + } + + @Test + public void testLongitudeEmptyConstructor() { + LatLng latLng = new LatLng(); + assertEquals("longitude default value", latLng.getLongitude(), 0, DELTA); + } + + @Test + public void testAltitudeEmptyConstructor() { + LatLng latLng1 = new LatLng(); + assertEquals("altitude default value", latLng1.getAltitude(), 0.0, DELTA); + } + + @Test + public void testLatitudeConstructor() { + double latitude = 1.2; + LatLng latLng = new LatLng(latitude, 3.4); + assertEquals("latitude should match", latLng.getLatitude(), latitude, DELTA); + } + + @Test + public void testLongitudeConstructor() { + double longitude = 3.4; + LatLng latLng = new LatLng(1.2, longitude); + assertEquals("longitude should match", latLng.getLongitude(), longitude, DELTA); + } + + @Test + public void testAltitudeConstructor() { + LatLng latLng1 = new LatLng(1.2, 3.4); + assertEquals("altitude default value", latLng1.getAltitude(), 0.0, DELTA); + + double altitude = 5.6; + LatLng latLng2 = new LatLng(1.2, 3.4, altitude); + assertEquals("altitude default value", latLng2.getAltitude(), altitude, DELTA); + } + + @Test + public void testLatitudeSetter() { + LatLng latLng = new LatLng(1.2, 3.4); + latLng.setLatitude(3); + assertEquals("latitude should match", 3, latLng.getLatitude(), DELTA); + } + + @Test + public void testLongitudeSetter() { + LatLng latLng = new LatLng(1.2, 3.4); + latLng.setLongitude(3); + assertEquals("longitude should match", 3, latLng.getLongitude(), DELTA); + } + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testConstructorChecksLatitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must not be NaN"); + new LatLng(Double.NaN, 0); + } + + @Test + public void testConstructorChecksLongitudeNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be NaN"); + new LatLng(0, Double.NaN); + } + + @Test + public void testConstructorChecksLatitudeGreaterThan90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + new LatLng(95, 0); + } + + @Test + public void testConstructorChecksLatitudeLessThanThanNegative90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + new LatLng(-95, 0); + } + + @Test + public void testConstructorChecksLongitudeInfinity() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be infinite"); + new LatLng(0, Double.POSITIVE_INFINITY); + } + + @Test + public void testLatitudeSetterChecksNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must not be NaN"); + new LatLng().setLatitude(Double.NaN); + } + + @Test + public void testLongitudeSetterChecksNaN() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be NaN"); + new LatLng().setLongitude(Double.NaN); + } + + @Test + public void testLatitudeSetterChecksGreaterThan90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + new LatLng().setLatitude(95); + } + + @Test + public void testLatitudeSetterChecksLessThanThanNegative90() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("latitude must be between -90 and 90"); + new LatLng().setLatitude(-95); + } + + @Test + public void testLongitudeSetterChecksInfinity() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("longitude must not be infinite"); + new LatLng().setLongitude(Double.NEGATIVE_INFINITY); + } + + @Test + public void testAltitudeSetter() { + LatLng latLng = new LatLng(1.2, 3.4); + latLng.setAltitude(3); + assertEquals("altitude should match", 3, latLng.getAltitude(), DELTA); + } + + @Test + public void testLatLngConstructor() { + LatLng latLng1 = new LatLng(1.2, 3.4); + LatLng latLng2 = new LatLng(latLng1); + assertEquals("latLng should match", latLng1, latLng2); + } + + @Test + public void testDistanceTo() { + LatLng latLng1 = new LatLng(0.0, 0.0); + LatLng latLng2 = new LatLng(1.0, 1.0); + assertEquals("distances should match", + latLng1.distanceTo(latLng2), + 157298.7453847275, DELTA); + } + + @Test + public void testDistanceToSamePoint() { + LatLng latLng1 = new LatLng(40.71199035644531, -74.0081); + LatLng latLng2 = new LatLng(40.71199035644531, -74.0081); + double distance = latLng1.distanceTo(latLng2); + assertEquals("distance should match", 0.0, distance, DELTA); + } + + // Regression test for #14216 + @Test + public void testDistanceToClosePointNotNaN() { + LatLng latLng = new LatLng(40.00599, -105.29261); + LatLng other = new LatLng(40.005990000000025, -105.29260999999997); + double distance = latLng.distanceTo(other); + assertNotEquals(distance, Double.NaN); + } + + @Test + public void testLocationProvider() { + double latitude = 1.2; + double longitude = 3.4; + double altitude = 5.6; + + // Mock the location class + Location locationMocked = mock(Location.class); + when(locationMocked.getLatitude()).thenReturn(latitude); + when(locationMocked.getLongitude()).thenReturn(longitude); + when(locationMocked.getAltitude()).thenReturn(altitude); + + // Test the constructor + LatLng latLng = new LatLng(locationMocked); + assertEquals("latitude should match", latLng.getLatitude(), latitude, DELTA); + assertEquals("longitude should match", latLng.getLongitude(), longitude, DELTA); + assertEquals("altitude should match", latLng.getAltitude(), altitude, DELTA); + } + + @Test + public void testHashCode() { + double latitude = 1.2; + double longitude = 3.4; + double altitude = 5.6; + LatLng latLng = new LatLng(latitude, longitude, altitude); + assertEquals("hash code should match", latLng.hashCode(), -151519232); + } + + @Test + public void testToString() { + double latitude = 1.2; + double longitude = 3.4; + double altitude = 5.6; + LatLng latLng = new LatLng(latitude, longitude, altitude); + assertEquals("string should match", + latLng.toString(), + "LatLng [latitude=1.2, longitude=3.4, altitude=5.6]"); + } + + @Test + public void testEqualsOther() { + double latitude = 1.2; + double longitude = 3.4; + double altitude = 5.6; + LatLng latLng1 = new LatLng(latitude, longitude, altitude); + LatLng latLng2 = new LatLng(latitude, longitude, altitude); + assertEquals("LatLng should match", latLng1, latLng2); + } + + @Test + public void testEqualsItself() { + LatLng latLng = new LatLng(1, 2, 3); + assertEquals("LatLng should match", latLng, latLng); + } + + @Test + public void testNotEquals() { + LatLng latLng = new LatLng(1, 2); + assertNotEquals("LatLng should match", latLng, new Object()); + } + + @Test + public void testParcelable() { + LatLng latLng = new LatLng(45.0, -185.0); + Parcelable parcel = MockParcel.obtain(latLng); + assertEquals("parcel should match initial object", latLng, parcel); + } + + @Test + public void testWrapped() { + 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 + public void testUnnecessaryWrapped() { + LatLng latLng = new LatLng(45.0, 50.0).wrap(); + assertEquals("longitude wrapped value", latLng.getLongitude(), 50.0, DELTA); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java new file mode 100644 index 000000000..00fd125a1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.utils.MockParcel; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class ProjectedMetersTest { + + private static final LatLng LAT_LNG_NULL_ISLAND = new LatLng(0, 0); + + @Test + public void testSanity() { + ProjectedMeters projectedMeters = new ProjectedMeters(0.0, 0.0); + assertNotNull("projectedMeters should not be null", projectedMeters); + } + + @Test + public void testEquality() { + ProjectedMeters projectedMeters = new ProjectedMeters(0.0, 0.0); + assertEquals("projectedMeters is not equal to a LatLng", projectedMeters.equals(LAT_LNG_NULL_ISLAND), false); + assertEquals("projectedMeters is equal to itself", projectedMeters.equals(projectedMeters), true); + } + + @Test + public void testNorthing() { + ProjectedMeters projectedMeters = new ProjectedMeters(1.0, 0.0); + assertEquals("northing should be 1", 1, projectedMeters.getNorthing(), 0); + } + + @Test + public void testEasting() { + ProjectedMeters projectedMeters = new ProjectedMeters(0.0, 1.0); + assertEquals("easting should be 1", 1, projectedMeters.getEasting(), 0); + } + + @Test + public void testConstructor() { + ProjectedMeters projectedMeters1 = new ProjectedMeters(1, 2); + ProjectedMeters projectedMeters2 = new ProjectedMeters(projectedMeters1); + assertEquals("projectedmeters should match", projectedMeters1, projectedMeters2); + } + + @Test + public void testHashcode() { + ProjectedMeters meters = new ProjectedMeters(1, 2); + assertEquals("hashcode should match", -1048576, meters.hashCode()); + } + + @Test + public void testToString() { + ProjectedMeters meters = new ProjectedMeters(1, 1); + assertEquals("toString should match", "ProjectedMeters [northing=1.0, easting=1.0]", meters.toString()); + } + + @Test + public void testParcelable() { + ProjectedMeters meters = new ProjectedMeters(1, 1); + Parcelable parcel = MockParcel.obtain(meters); + assertEquals("parcel should match initial object", meters, parcel); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java new file mode 100644 index 000000000..12b779de5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java @@ -0,0 +1,95 @@ +package com.mapbox.mapboxsdk.geometry; + +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.utils.MockParcel; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class VisibleRegionTest { + + private static final LatLng FAR_LEFT = new LatLng(52, -12); + private static final LatLng NEAR_LEFT = new LatLng(34, -12); + private static final LatLng FAR_RIGHT = new LatLng(52, 26); + private static final LatLng NEAR_RIGHT = new LatLng(34, 26); + private static final LatLngBounds BOUNDS = + new LatLngBounds.Builder().include(FAR_LEFT).include(FAR_RIGHT).include(NEAR_LEFT).include(NEAR_RIGHT).build(); + + @Test + public void testSanity() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertNotNull("region should not be null", region); + } + + @Test + public void testEquality() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("visibleRegion is not equal to a LatLng", region.equals(FAR_LEFT), false); + assertEquals("visibleRegion is equal to itself", region.equals(region), true); + } + + @Test + public void testFarLeftConstructor() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("LatLng should match", region.farLeft, FAR_LEFT); + } + + @Test + public void testNearLeftConstructor() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("LatLng should match", region.nearLeft, NEAR_LEFT); + } + + @Test + public void testFarRightConstructor() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("LatLng should match", region.farRight, FAR_RIGHT); + } + + @Test + public void testNearRightConstructor() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("LatLng should match", region.nearRight, NEAR_RIGHT); + } + + @Test + public void testLatLngBoundsConstructor() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("LatLngBounds should match", region.latLngBounds, BOUNDS); + } + + @Test + public void testEquals() { + VisibleRegion regionLeft = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + VisibleRegion regionRight = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("VisibleRegions should match", regionLeft, regionRight); + } + + @Test + public void testHashcode() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("hashcode should match", -923534102, region.hashCode()); + } + + @Test + public void testToString() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + assertEquals("string should match", + "[farLeft [LatLng [latitude=52.0, longitude=-12.0, altitude=0.0]], " + + "farRight [LatLng [latitude=52.0, longitude=26.0, altitude=0.0]], " + + "nearLeft [LatLng [latitude=34.0, longitude=-12.0, altitude=0.0]], " + + "nearRight [LatLng [latitude=34.0, longitude=26.0, altitude=0.0]], " + + "latLngBounds [N:52.0; E:26.0; S:34.0; W:-12.0]]", + region.toString()); + } + + @Test + public void testParcelable() { + VisibleRegion region = new VisibleRegion(FAR_LEFT, FAR_RIGHT, NEAR_LEFT, NEAR_RIGHT, BOUNDS); + Parcelable parcel = MockParcel.obtain(region); + assertEquals("parcel should match initial object", region, parcel); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java new file mode 100644 index 000000000..bebd82811 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java @@ -0,0 +1,89 @@ +package com.mapbox.mapboxsdk.location; + +import android.hardware.Sensor; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.view.WindowManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static com.mapbox.mapboxsdk.location.LocationComponentCompassEngine.SENSOR_DELAY_MICROS; +import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CompassEngineTest { + + private LocationComponentCompassEngine compassEngine; + + @Mock + private WindowManager windowManager; + + @Mock + private SensorManager sensorManager; + + @Mock + private Sensor compassSensor; + + @Mock + private CompassListener compassListener; + + @Before + public void setUp() throws Exception { + when(sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)).thenReturn(compassSensor); + compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); + } + + @Test + public void lastKnownCompassBearingAccuracyDefault() { + assertEquals("Last accuracy should match", compassEngine.getLastAccuracySensorStatus(), 0); + } + + @Test + public void lastKnownCompassAccuracyStatusValue() { + Sensor sensor = mock(Sensor.class); + compassEngine.onAccuracyChanged(sensor, 2); + assertEquals("Last accuracy should match", compassEngine.getLastAccuracySensorStatus(), 2); + } + + @Test + public void whenGyroscopeIsNull_fallbackToGravity() { + SensorManager sensorManager = mock(SensorManager.class); + when(sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)).thenReturn(null); + new LocationComponentCompassEngine(windowManager, sensorManager); + + verify(sensorManager, times(1)).getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + } + + @Test + public void whenGyroscopeIsNull_fallbackToMagneticField() { + SensorManager sensorManager = mock(SensorManager.class); + when(sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)).thenReturn(null); + new LocationComponentCompassEngine(windowManager, sensorManager); + + verify(sensorManager, times(1)).getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + } + + @Test + public void listener_registerOnAdd() { + compassEngine.addCompassListener(compassListener); + verify(sensorManager) + .registerListener(any(SensorEventListener.class), eq(compassSensor), eq(SENSOR_DELAY_MICROS)); + } + + @Test + public void listener_unregisterOnRemove() { + compassEngine.addCompassListener(compassListener); + compassEngine.removeCompassListener(compassListener); + verify(sensorManager).unregisterListener(any(SensorEventListener.class), eq(compassSensor)); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt new file mode 100644 index 000000000..1b927d213 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -0,0 +1,532 @@ +package com.mapbox.mapboxsdk.location + +import android.animation.Animator +import android.location.Location +import android.util.SparseArray +import android.view.animation.LinearInterpolator +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION +import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION +import com.mapbox.mapboxsdk.location.MapboxAnimator.* +import com.mapbox.mapboxsdk.location.modes.CameraMode +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Projection +import io.mockk.* +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class LocationAnimatorCoordinatorTest { + + private lateinit var locationAnimatorCoordinator: LocationAnimatorCoordinator + private val cameraPosition: CameraPosition = CameraPosition.DEFAULT + + private val animatorProvider: MapboxAnimatorProvider = mockk() + private val animatorSetProvider: MapboxAnimatorSetProvider = mockk() + + private val projection: Projection = mockk() + + @Before + fun setUp() { + locationAnimatorCoordinator = LocationAnimatorCoordinator(projection, animatorSetProvider, animatorProvider) + configureAnimatorProvider() + every { projection.getMetersPerPixelAtLatitude(any()) } answers { 1.0 } + every { animatorSetProvider.startAnimation(any(), any(), any()) } answers {} + locationAnimatorCoordinator.updateAnimatorListenerHolders(getListenerHoldersSet( + ANIMATOR_LAYER_LATLNG, + ANIMATOR_CAMERA_LATLNG, + ANIMATOR_LAYER_GPS_BEARING, + ANIMATOR_LAYER_COMPASS_BEARING, + ANIMATOR_CAMERA_GPS_BEARING, + ANIMATOR_CAMERA_COMPASS_BEARING, + ANIMATOR_LAYER_ACCURACY, + ANIMATOR_ZOOM, + ANIMATOR_TILT + )) + } + + private fun configureAnimatorProvider() { + // workaround https://github.com/mockk/mockk/issues/229#issuecomment-457816131 + registerInstanceFactory { AnimationsValueChangeListener {} } + registerInstanceFactory { AnimationsValueChangeListener {} } + val previousFloatSlot = slot() + val targetFloatSlot = slot() + val listenerSlot = slot>() + val maxFpsSlot = slot() + every { + animatorProvider.floatAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), capture(maxFpsSlot)) + } answers { + MapboxFloatAnimator(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, maxFpsSlot.captured) + } + + val previousLatLngSlot = slot() + val targetLatLngSlot = slot() + every { + animatorProvider.latLngAnimator(capture(previousLatLngSlot), capture(targetLatLngSlot), capture(listenerSlot), capture(maxFpsSlot)) + } answers { + MapboxLatLngAnimator(previousLatLngSlot.captured, targetLatLngSlot.captured, listenerSlot.captured, maxFpsSlot.captured) + } + + val callback = slot() + every { + animatorProvider.cameraAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), capture(callback)) + } answers { + MapboxCameraAnimatorAdapter(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, callback.captured) + } + every { + animatorProvider.cameraAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), null) + } answers { + MapboxCameraAnimatorAdapter(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, null) + } + } + + @Test + fun feedNewLocation_animatorsAreCreated() { + locationAnimatorCoordinator.feedNewLocation(Location(""), cameraPosition, false) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING] != null) + } + + @Test + fun feedNewLocation_animatorValue() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 35f + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val cameraLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG]?.target as LatLng + assertEquals(cameraLatLngTarget.latitude, cameraLatLngTarget.latitude) + + val layerLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG]?.target as LatLng + assertEquals(layerLatLngTarget.latitude, layerLatLngTarget.latitude) + + val cameraBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING]?.target as Float + assertEquals(location.bearing, cameraBearingTarget) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(location.bearing, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_1() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 0f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns 270f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(360f, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_2() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 90f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns 280f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(450f, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_3() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 300f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns 450f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(-60f, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_4() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 350f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns 10f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(-10f, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_5() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 90f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns -280f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(90f, layerBearingTarget) + } + + @Test + fun feedNewLocation_animatorValue_correctRotation_6() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 270f + + val animator = mockk(relaxed = true) + every { animator.animatedValue } returns -350f + locationAnimatorCoordinator.animatorArray.put(ANIMATOR_LAYER_GPS_BEARING, animator) + + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(-90f, layerBearingTarget) + } + + @Test + fun feedNewLocation_isNorth_animatorsAreCreated() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 35f + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING] != null) + } + + @Test + fun feedNewLocation_isNorth_animatorValue() { + val location = Location("") + location.latitude = 51.0 + location.longitude = 17.0 + location.bearing = 35f + locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, true) + + val cameraLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG]?.target as LatLng + assertEquals(cameraLatLngTarget.latitude, cameraLatLngTarget.latitude) + + val layerLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG]?.target as LatLng + assertEquals(layerLatLngTarget.latitude, layerLatLngTarget.latitude) + + val cameraBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING]?.target as Float + assertEquals(0f, cameraBearingTarget) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(location.bearing, layerBearingTarget) + } + + @Test + fun feedNewCompassBearing_animatorsAreCreated() { + locationAnimatorCoordinator.feedNewCompassBearing(77f, cameraPosition) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING] != null) + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING] != null) + } + + @Test + fun feedNewCompassBearing_animatorValue() { + val bearing = 77f + locationAnimatorCoordinator.feedNewCompassBearing(bearing, cameraPosition) + + val cameraBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING]?.target as Float + assertEquals(bearing, cameraBearingTarget) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING]?.target as Float + assertEquals(bearing, layerBearingTarget) + } + + @Test + fun feedNewAccuracyRadius_animatorsCreated() { + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, false) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY] != null) + } + + @Test + fun feedNewAccuracyRadius_animatorValue() { + val accuracy = 150f + locationAnimatorCoordinator.feedNewAccuracyRadius(accuracy, false) + + val layerAccuracy = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.target as Float + assertEquals(layerAccuracy, accuracy) + } + + @Test + fun feedNewAccuracyRadius_noAnimation_animatorsCreated() { + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, true) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY] != null) + } + + @Test + fun feedNewAccuracyRadius_noAnimation_animatorValue() { + val accuracy = 150f + locationAnimatorCoordinator.feedNewAccuracyRadius(accuracy, true) + + val layerAccuracy = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.target as Float + assertEquals(layerAccuracy, accuracy) + } + + @Test + fun feedNewZoomLevel_animatorsCreated() { + locationAnimatorCoordinator.feedNewZoomLevel( + 15.0, + cameraPosition, + DEFAULT_TRACKING_ZOOM_ANIM_DURATION, + null + ) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_ZOOM] != null) + } + + @Test + fun feedNewZoomLevel_animatorValue() { + val zoom = 15.0f + locationAnimatorCoordinator.feedNewZoomLevel( + zoom.toDouble(), + cameraPosition, + DEFAULT_TRACKING_ZOOM_ANIM_DURATION, + null + ) + + val animator = locationAnimatorCoordinator.animatorArray[ANIMATOR_ZOOM] + assertEquals(zoom, animator.target) + verify { animatorSetProvider.startAnimation(eq(listOf(animator)), any(), DEFAULT_TRACKING_ZOOM_ANIM_DURATION) } + } + + @Test + fun feedNewTiltLevel_animatorsCreated() { + locationAnimatorCoordinator.feedNewTilt( + 30.0, + cameraPosition, + DEFAULT_TRACKING_TILT_ANIM_DURATION, + null + ) + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_TILT] != null) + } + + @Test + fun feedNewTiltLevel_animatorValue() { + val tilt = 30.0f + locationAnimatorCoordinator.feedNewTilt( + tilt.toDouble(), + cameraPosition, + DEFAULT_TRACKING_TILT_ANIM_DURATION, + null + ) + + val animator = locationAnimatorCoordinator.animatorArray[ANIMATOR_TILT] + assertEquals(tilt, animator.target) + verify { animatorSetProvider.startAnimation(eq(listOf(animator)), any(), DEFAULT_TRACKING_TILT_ANIM_DURATION) } + } + + @Test + fun cancelAllAnimators() { + locationAnimatorCoordinator.feedNewLocation(Location(""), cameraPosition, true) + locationAnimatorCoordinator.cancelAllAnimations() + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG] == null) + } + + @Test + fun cancelZoomAnimators() { + locationAnimatorCoordinator.feedNewZoomLevel( + 15.0, + cameraPosition, + DEFAULT_TRACKING_ZOOM_ANIM_DURATION, + null + ) + locationAnimatorCoordinator.cancelZoomAnimation() + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_ZOOM] == null) + } + + @Test + fun cancelTiltAnimation() { + locationAnimatorCoordinator.feedNewTilt( + 30.0, + cameraPosition, + DEFAULT_TRACKING_TILT_ANIM_DURATION, + null + ) + + locationAnimatorCoordinator.cancelTiltAnimation() + + assertTrue(locationAnimatorCoordinator.animatorArray[ANIMATOR_TILT] == null) + } + + @Test + fun resetAllCameraAnimations_empty() { + locationAnimatorCoordinator.resetAllCameraAnimations(cameraPosition, false) + assertTrue(locationAnimatorCoordinator.animatorArray.size() == 0) + } + + @Test + fun resetAllLayerAnimations_empty() { + locationAnimatorCoordinator.resetAllLayerAnimations() + assertTrue(locationAnimatorCoordinator.animatorArray.size() == 0) + } + + @Test + fun addNewListener() { + val listener = Mockito.mock(AnimationsValueChangeListener::class.java) + val holder = AnimatorListenerHolder(RenderMode.NORMAL, listener) + val set = HashSet().also { + it.add(holder) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set) + + assertTrue(locationAnimatorCoordinator.listeners.contains(listener)) + } + + @Test + fun updateListeners() { + val listener = Mockito.mock(AnimationsValueChangeListener::class.java) + val holder = AnimatorListenerHolder(RenderMode.NORMAL, listener) + val set = HashSet().also { + it.add(holder) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set) + + val listener2 = Mockito.mock(AnimationsValueChangeListener::class.java) + val holder2 = AnimatorListenerHolder(RenderMode.NORMAL, listener2) + val listener3 = Mockito.mock(AnimationsValueChangeListener::class.java) + val holder3 = AnimatorListenerHolder(CameraMode.TRACKING_GPS, listener3) + val set2 = HashSet().also { + it.add(holder2) + it.add(holder3) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set2) + + assertTrue(locationAnimatorCoordinator.listeners.size() == 2) + assertTrue(locationAnimatorCoordinator.listeners.contains(listener2)) + assertTrue(locationAnimatorCoordinator.listeners.contains(listener3)) + } + + @Test + fun feedNewCompassBearing_withAnimation() { + locationAnimatorCoordinator.setCompassAnimationEnabled(true) + locationAnimatorCoordinator.feedNewCompassBearing(77f, cameraPosition) + + val animators = mutableListOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING]) + + verify(exactly = 1) { animatorSetProvider.startAnimation(eq(animators), ofType(LinearInterpolator::class), eq(LocationComponentConstants.COMPASS_UPDATE_RATE_MS)) } + } + + @Test + fun feedNewCompassBearing_withoutAnimation() { + locationAnimatorCoordinator.setCompassAnimationEnabled(false) + locationAnimatorCoordinator.feedNewCompassBearing(77f, cameraPosition) + + val animators = mutableListOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING]) + + verify(exactly = 1) { animatorSetProvider.startAnimation(eq(animators), ofType(LinearInterpolator::class), eq(0)) } + } + + @Test + fun feedNewAccuracy_withAnimation() { + locationAnimatorCoordinator.setAccuracyAnimationEnabled(true) + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, false) + + val animators = mutableListOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]) + + verify(exactly = 1) { animatorSetProvider.startAnimation(eq(animators), ofType(LinearInterpolator::class), eq(LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION)) } + } + + @Test + fun feedNewAccuracy_withoutAnimation() { + locationAnimatorCoordinator.setAccuracyAnimationEnabled(false) + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, false) + + val animators = mutableListOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]) + + verify(exactly = 1) { animatorSetProvider.startAnimation(eq(animators), ofType(LinearInterpolator::class), eq(0)) } + } + + @Test + fun maxFps_setter() { + locationAnimatorCoordinator.setMaxAnimationFps(5) + assertEquals(5, locationAnimatorCoordinator.maxAnimationFps) + } + + @Test + fun maxFps_moreThanZeroRequired() { + locationAnimatorCoordinator.setMaxAnimationFps(0) + assertEquals(Int.MAX_VALUE, locationAnimatorCoordinator.maxAnimationFps) + locationAnimatorCoordinator.setMaxAnimationFps(-1) + assertEquals(Int.MAX_VALUE, locationAnimatorCoordinator.maxAnimationFps) + } + + @Test + fun maxFps_givenToAnimator() { + locationAnimatorCoordinator.setMaxAnimationFps(5) + locationAnimatorCoordinator.feedNewLocation(Location(""), cameraPosition, false) + verify { animatorProvider.latLngAnimator(any(), any(), any(), 5) } + verify { animatorProvider.floatAnimator(any(), any(), any(), 5) } + } + + private fun getListenerHoldersSet(vararg animatorTypes: Int): Set { + return HashSet().also { + for (type in animatorTypes) { + it.add(AnimatorListenerHolder(type, mockk())) + } + } + } +} + +private fun SparseArray.contains(listener: AnimationsValueChangeListener<*>?): Boolean { + for (i in 0 until this.size()) { + val element = this.get(this.keyAt(i)) + if (element == listener) { + return true + } + } + return false +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java new file mode 100644 index 000000000..d1b8642c3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java @@ -0,0 +1,1001 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.PointF; +import android.location.Location; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdate; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.mapboxsdk.maps.Transform; +import com.mapbox.mapboxsdk.maps.UiSettings; + +import junit.framework.Assert; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_LATLNG; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.NONE; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.NONE_COMPASS; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.NONE_GPS; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.TRACKING; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.TRACKING_COMPASS; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.TRACKING_GPS; +import static com.mapbox.mapboxsdk.location.modes.CameraMode.TRACKING_GPS_NORTH; +import static junit.framework.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class LocationCameraControllerTest { + + @Test + public void setCameraMode_mapTransitionsAreCancelled() { + MapboxMap mapboxMap = mock(MapboxMap.class); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(TRACKING_GPS); + + verify(mapboxMap).cancelTransitions(); + } + + @Test + public void setCameraMode_gestureThresholdIsAdjusted() { + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(moveGestureDetector); + LocationComponentOptions options = mock(LocationComponentOptions.class); + float moveThreshold = 5f; + when(options.trackingInitialMoveThreshold()).thenReturn(moveThreshold); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + camera.setCameraMode(TRACKING_GPS); + + verify(moveGestureDetector).setMoveThreshold(moveThreshold); + } + + @Test + public void setCameraMode_gestureThresholdNotAdjustedWhenDisabled() { + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(moveGestureDetector); + LocationComponentOptions options = mock(LocationComponentOptions.class); + float moveThreshold = 5f; + when(options.trackingInitialMoveThreshold()).thenReturn(moveThreshold); + when(options.trackingGesturesManagement()).thenReturn(false); + camera.initializeOptions(options); + + camera.setCameraMode(TRACKING_GPS); + + verify(moveGestureDetector, times(0)).setMoveThreshold(moveThreshold); + verify(moveGestureDetector, times(0)).setMoveThreshold(0f); + } + + @Test + public void setCameraMode_gestureThresholdIsResetWhenNotTracking() { + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(moveGestureDetector); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + camera.setCameraMode(NONE); + + verify(moveGestureDetector, times(2)).setMoveThreshold(0f); // one for initialization + } + + @Test + public void setCameraMode_notTrackingAdjustsFocalPoint() { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(TRACKING_GPS); + camera.setCameraMode(NONE); + + verify(mapboxMap.getUiSettings()).setFocalPoint(null); + } + + @Test + public void setCameraMode_trackingChangeListenerCameraDismissedIsCalled() { + OnCameraTrackingChangedListener internalTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + LocationCameraController camera = buildCamera(internalTrackingChangedListener); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(TRACKING_GPS); + camera.setCameraMode(NONE); + + verify(internalTrackingChangedListener).onCameraTrackingDismissed(); + } + + @Test + public void setCameraMode_internalCameraTrackingChangeListenerIsCalled() { + OnCameraTrackingChangedListener internalTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + LocationCameraController camera = buildCamera(internalTrackingChangedListener); + camera.initializeOptions(mock(LocationComponentOptions.class)); + int cameraMode = NONE; + + camera.setCameraMode(cameraMode); + + verify(internalTrackingChangedListener).onCameraTrackingChanged(cameraMode); + } + + @Test + public void setCameraMode_doNotNotifyAboutDuplicates_NONE() { + OnCameraTrackingChangedListener internalTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + LocationCameraController camera = buildCamera(internalTrackingChangedListener); + camera.initializeOptions(mock(LocationComponentOptions.class)); + int cameraMode = NONE; + + camera.setCameraMode(cameraMode); + camera.setCameraMode(cameraMode); + + verify(internalTrackingChangedListener, times(1)).onCameraTrackingChanged(cameraMode); + } + + @Test + public void setCameraMode_doNotNotifyAboutDuplicates_TRACKING_GPS() { + OnCameraTrackingChangedListener internalTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + LocationCameraController camera = buildCamera(internalTrackingChangedListener); + camera.initializeOptions(mock(LocationComponentOptions.class)); + int cameraMode = TRACKING_GPS; + + camera.setCameraMode(cameraMode); + camera.setCameraMode(cameraMode); + + verify(internalTrackingChangedListener, times(1)).onCameraTrackingChanged(cameraMode); + } + + @Test + public void setCameraMode_cancelTransitionsWhenSet() { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + when(mapboxMap.getProjection()).thenReturn(mock(Projection.class)); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(NONE_COMPASS); + verify(mapboxMap, times(1)).cancelTransitions(); + + camera.setCameraMode(NONE_GPS); + verify(mapboxMap, times(2)).cancelTransitions(); + + camera.setCameraMode(TRACKING); + verify(mapboxMap, times(3)).cancelTransitions(); + + camera.setCameraMode(TRACKING_COMPASS); + verify(mapboxMap, times(4)).cancelTransitions(); + + camera.setCameraMode(TRACKING_GPS); + verify(mapboxMap, times(5)).cancelTransitions(); + + camera.setCameraMode(TRACKING_GPS_NORTH); + verify(mapboxMap, times(6)).cancelTransitions(); + } + + @Test + public void setCameraMode_dontCancelTransitionsWhenNoneSet() { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + when(mapboxMap.getProjection()).thenReturn(mock(Projection.class)); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(NONE); + verify(mapboxMap, never()).cancelTransitions(); + } + + @Test + public void onNewLatLngValue_cameraModeTrackingUpdatesLatLng() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING); + LatLng latLng = mock(LatLng.class); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewLatLngValue_cameraModeTrackingGpsNorthUpdatesLatLng() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_GPS_NORTH); + LatLng latLng = mock(LatLng.class); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewLatLngValue_cameraModeTrackingGpsUpdatesLatLng() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_GPS); + LatLng latLng = mock(LatLng.class); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewLatLngValue_cameraModeTrackingCompassUpdatesLatLng() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_COMPASS); + LatLng latLng = mock(LatLng.class); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewLatLngValue_cameraModeNoneIgnored() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(NONE); + + assertNull(getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners())); + verify(transform, times(0)).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewLatLngValue_focalPointIsAdjusted() { + MapboxMap mapboxMap = mock(MapboxMap.class); + UiSettings uiSettings = mock(UiSettings.class); + when(mapboxMap.getUiSettings()).thenReturn(uiSettings); + Projection projection = mock(Projection.class); + PointF pointF = mock(PointF.class); + when(projection.toScreenLocation(any(LatLng.class))).thenReturn(pointF); + when(mapboxMap.getProjection()).thenReturn(projection); + LocationCameraController camera = buildCamera(mapboxMap); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + camera.setCameraMode(TRACKING); + LatLng latLng = mock(LatLng.class); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + + verify(uiSettings).setFocalPoint(pointF); + } + + @Test + public void onNewGpsBearingValue_cameraModeTrackingGpsUpdatesBearing() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_GPS); + float gpsBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(gpsBearing); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewGpsBearingValue_cameraModeNoneGpsUpdatesBearing() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(NONE_GPS); + float gpsBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(gpsBearing); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewGpsBearingValue_cameraModeTrackingNorthUpdatesBearing() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(mapboxMap, transform); + CameraPosition cameraPosition = new CameraPosition.Builder().bearing(7d).build(); + when(mapboxMap.getCameraPosition()).thenReturn(cameraPosition); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_GPS_NORTH); + float gpsBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(gpsBearing); + + verify(transform).moveCamera(eq(mapboxMap), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewGpsBearingValue_cameraModeTrackingNorthBearingZeroIgnored() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(mapboxMap, transform); + CameraPosition cameraPosition = new CameraPosition.Builder().bearing(0d).build(); + when(mapboxMap.getCameraPosition()).thenReturn(cameraPosition); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_GPS_NORTH); + float gpsBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(gpsBearing); + + verify(transform, times(0)).moveCamera(eq(mapboxMap), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewGpsBearingValue_cameraModeNoneIgnored() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(NONE); + + assertNull(getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners())); + verify(transform, times(0)).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewCompassBearingValue_cameraModeTrackingCompassUpdatesBearing() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING_COMPASS); + float compassBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_COMPASS_BEARING, camera.getAnimationListeners()) + .onNewAnimationValue(compassBearing); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewCompassBearingValue_cameraModeNoneCompassUpdatesBearing() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(NONE_COMPASS); + float compassBearing = 5f; + + getAnimationListener(ANIMATOR_CAMERA_COMPASS_BEARING, camera.getAnimationListeners()) + .onNewAnimationValue(compassBearing); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewCompassBearingValue_cameraModeNoneIgnored() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(NONE); + + assertNull(getAnimationListener(ANIMATOR_CAMERA_COMPASS_BEARING, camera.getAnimationListeners())); + verify(transform, times(0)).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNewZoomValue_cameraIsUpdated() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING); + float zoom = 5f; + + getAnimationListener(ANIMATOR_ZOOM, camera.getAnimationListeners()).onNewAnimationValue(zoom); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void onNeTiltValue_cameraIsUpdated() { + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + camera.setCameraMode(TRACKING); + float tilt = 5f; + + getAnimationListener(ANIMATOR_TILT, camera.getAnimationListeners()).onNewAnimationValue(tilt); + + verify(transform).moveCamera(any(MapboxMap.class), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void gesturesManagement_enabled() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + verify(mapboxMap).setGesturesManager(internalGesturesManager, true, true); + } + + @Test + public void gesturesManagement_disabled() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(false); + camera.initializeOptions(options); + + verify(mapboxMap).setGesturesManager(initialGesturesManager, true, true); + } + + @Test + public void gesturesManagement_optionNotChangedInitial() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(false); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(initialGesturesManager, true, true); + } + + @Test + public void gesturesManagement_optionNotChangedInternal() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(internalGesturesManager, true, true); + } + + @Test + public void onMove_notCancellingTransitionWhileNone() { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(NONE); + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(0)).cancelTransitions(); + verify(moveGestureDetector, times(0)).interrupt(); + + // testing subsequent calls + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(0)).cancelTransitions(); + verify(moveGestureDetector, times(0)).interrupt(); + } + + @Test + public void onMove_cancellingTransitionWhileGps() { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(TRACKING); + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(1)).cancelTransitions(); + verify(moveGestureDetector, times(1)).interrupt(); + + // testing subsequent calls + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(1)).cancelTransitions(); + verify(moveGestureDetector, times(1)).interrupt(); + } + + @Test + public void onMove_cancellingTransitionWhileBearing() { + MapboxMap mapboxMap = mock(MapboxMap.class); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + LocationCameraController camera = buildCamera(mapboxMap); + camera.initializeOptions(mock(LocationComponentOptions.class)); + + camera.setCameraMode(NONE_COMPASS); + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(1)).cancelTransitions(); + verify(moveGestureDetector, times(1)).interrupt(); + + // testing subsequent calls + camera.onMoveListener.onMove(moveGestureDetector); + verify(mapboxMap, times(1)).cancelTransitions(); + verify(moveGestureDetector, times(1)).interrupt(); + } + + @Test + public void transition_locationIsNull() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + + camera.setCameraMode(TRACKING, null, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + Assert.assertEquals(TRACKING, camera.getCameraMode()); + verify(listener).onLocationCameraTransitionFinished(TRACKING); + verify(transform, times(0)) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_notTracking() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + camera.setCameraMode(NONE, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + verify(listener, times(1)).onLocationCameraTransitionFinished(NONE); + verify(transform, times(0)) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_trackingChanged() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + listener.onLocationCameraTransitionFinished(TRACKING); + return null; + } + }).when(transform).animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + verify(listener).onLocationCameraTransitionFinished(TRACKING); + verify(transform) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_trackingNotChanged() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + listener.onLocationCameraTransitionFinished(TRACKING_GPS_NORTH); + return null; + } + }).when(transform).animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + + camera.setCameraMode(TRACKING_GPS_NORTH, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + verify(listener, times(1)).onLocationCameraTransitionFinished(TRACKING_GPS_NORTH); + verify(transform, times(1)) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_canceled() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + listener.onLocationCameraTransitionCanceled(TRACKING); + return null; + } + }).when(transform).animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + verify(listener).onLocationCameraTransitionCanceled(TRACKING); + verify(transform) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_mapboxCallbackFinished() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + when(location.getLatitude()).thenReturn(1.0); + when(location.getLongitude()).thenReturn(1.0); + when(location.getBearing()).thenReturn(30f); + when(location.getAltitude()).thenReturn(0.0); + + ArgumentCaptor callbackCaptor + = ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)); + verify(transform).animateCamera( + eq(mapboxMap), + eq(CameraUpdateFactory.newCameraPosition(builder.build())), + eq((int) TRANSITION_ANIMATION_DURATION_MS), + callbackCaptor.capture()); + + Assert.assertTrue(camera.isTransitioning()); + + callbackCaptor.getValue().onFinish(); + + Assert.assertFalse(camera.isTransitioning()); + + verify(listener).onLocationCameraTransitionFinished(TRACKING); + } + + @Test + public void transition_mapboxCallbackFinishedImmediately() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + when(location.getLatitude()).thenReturn(1.0); + when(location.getLongitude()).thenReturn(1.0); + when(location.getBearing()).thenReturn(30f); + when(location.getAltitude()).thenReturn(0.0); + + ArgumentCaptor callbackCaptor + = ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)); + verify(transform).moveCamera( + eq(mapboxMap), + eq(CameraUpdateFactory.newCameraPosition(builder.build())), + callbackCaptor.capture()); + + Assert.assertTrue(camera.isTransitioning()); + + callbackCaptor.getValue().onFinish(); + + Assert.assertFalse(camera.isTransitioning()); + + verify(listener).onLocationCameraTransitionFinished(TRACKING); + } + + @Test + public void transition_mapboxCallbackCanceled() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + when(location.getLatitude()).thenReturn(1.0); + when(location.getLongitude()).thenReturn(1.0); + when(location.getBearing()).thenReturn(30f); + when(location.getAltitude()).thenReturn(0.0); + + ArgumentCaptor callbackCaptor + = ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)); + verify(transform).animateCamera( + eq(mapboxMap), + eq(CameraUpdateFactory.newCameraPosition(builder.build())), + eq((int) TRANSITION_ANIMATION_DURATION_MS), + callbackCaptor.capture()); + + Assert.assertTrue(camera.isTransitioning()); + + callbackCaptor.getValue().onCancel(); + + Assert.assertFalse(camera.isTransitioning()); + + verify(listener).onLocationCameraTransitionCanceled(TRACKING); + } + + @Test + public void transition_mapboxAnimateBearing() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + when(location.getLatitude()).thenReturn(1.0); + when(location.getLongitude()).thenReturn(1.0); + when(location.getBearing()).thenReturn(30f); + when(location.getAltitude()).thenReturn(0.0); + + camera.setCameraMode(TRACKING_GPS, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)).bearing(30); + verify(transform).animateCamera( + eq(mapboxMap), + eq(CameraUpdateFactory.newCameraPosition(builder.build())), + eq((int) TRANSITION_ANIMATION_DURATION_MS), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_mapboxAnimateNorth() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + when(location.getLatitude()).thenReturn(1.0); + when(location.getLongitude()).thenReturn(1.0); + when(location.getBearing()).thenReturn(30f); + when(location.getAltitude()).thenReturn(0.0); + + camera.setCameraMode(TRACKING_GPS_NORTH, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)).bearing(0); + verify(transform).animateCamera( + eq(mapboxMap), + eq(CameraUpdateFactory.newCameraPosition(builder.build())), + eq((int) TRANSITION_ANIMATION_DURATION_MS), + any(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_animatorValuesDuringTransition() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + ArgumentCaptor callbackCaptor + = ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class); + + camera.setCameraMode(TRACKING_GPS, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + verify(transform).animateCamera( + eq(mapboxMap), + any(CameraUpdate.class), + eq((int) TRANSITION_ANIMATION_DURATION_MS), + callbackCaptor.capture()); + + LatLng latLng = new LatLng(10, 10); + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(10f); + getAnimationListener(ANIMATOR_TILT, camera.getAnimationListeners()).onNewAnimationValue(10f); + getAnimationListener(ANIMATOR_ZOOM, camera.getAnimationListeners()).onNewAnimationValue(10f); + + verify(transform, times(0)).moveCamera(eq(mapboxMap), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + + callbackCaptor.getValue().onFinish(); + + getAnimationListener(ANIMATOR_CAMERA_LATLNG, camera.getAnimationListeners()).onNewAnimationValue(latLng); + getAnimationListener(ANIMATOR_CAMERA_GPS_BEARING, camera.getAnimationListeners()).onNewAnimationValue(10f); + getAnimationListener(ANIMATOR_TILT, camera.getAnimationListeners()).onNewAnimationValue(10f); + getAnimationListener(ANIMATOR_ZOOM, camera.getAnimationListeners()).onNewAnimationValue(10f); + + verify(transform, times(4)).moveCamera(eq(mapboxMap), any(CameraUpdate.class), + nullable(MapboxMap.CancelableCallback.class)); + } + + @Test + public void transition_customAnimation() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + Location location = mock(Location.class); + CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition( + new CameraPosition.Builder() + .target(new LatLng(location)) + .zoom(14.0) + .bearing(13.0) + .tilt(45.0) + .build() + ); + + camera.setCameraMode(TRACKING, location, 1200, 14.0, 13.0, 45.0, null); + verify(transform) + .animateCamera(eq(mapboxMap), eq(cameraUpdate), eq(1200), any(MapboxMap.CancelableCallback.class)); + } + + private LocationCameraController buildCamera(OnCameraTrackingChangedListener onCameraTrackingChangedListener) { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + Transform transform = mock(Transform.class); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private LocationCameraController buildCamera(MoveGestureDetector moveGestureDetector) { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + Transform transform = mock(Transform.class); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private LocationCameraController buildCamera(MapboxMap mapboxMap) { + Transform transform = mock(Transform.class); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private LocationCameraController buildCamera(Transform transform) { + MapboxMap mapboxMap = mock(MapboxMap.class); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private LocationCameraController buildCamera(MapboxMap mapboxMap, Transform transform) { + when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private LocationCameraController buildCamera(MapboxMap mapboxMap, AndroidGesturesManager initialGesturesManager, + AndroidGesturesManager internalGesturesManager) { + Transform transform = mock(Transform.class); + MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); + OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); + OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); + return new LocationCameraController(mapboxMap, transform, moveGestureDetector, + onCameraTrackingChangedListener, onCameraMoveInvalidateListener, initialGesturesManager, internalGesturesManager); + } + + private MapboxAnimator.AnimationsValueChangeListener getAnimationListener( + @MapboxAnimator.Type int animatorType, + Set holders) { + for (AnimatorListenerHolder holder : holders) { + @MapboxAnimator.Type int type = holder.getAnimatorType(); + if (type == animatorType) { + return holder.getListener(); + } + } + + return null; + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java new file mode 100644 index 000000000..2660c819d --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java @@ -0,0 +1,119 @@ +package com.mapbox.mapboxsdk.location; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.maps.Style; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.MockitoRule; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class LocationComponentActivationOptionsTest { + + @Mock + private Context context; + @Mock + private TypedArray array; + @Mock + private Resources resources; + @Mock + private Style style; + + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @NonNull + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + when(context.obtainStyledAttributes(R.style.mapbox_LocationComponent, R.styleable.mapbox_LocationComponent)) + .thenReturn(array); + when(array.getResourceId(R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawable, -1)) + .thenReturn(R.drawable.mapbox_user_icon); + when(context.getResources()).thenReturn(resources); + } + + @Test + public void sanity() throws Exception { + when(style.isFullyLoaded()).thenReturn(true); + + LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) + .accuracyAlpha(0.5f) + .build(); + assertNotNull(locationComponentOptions); + + LocationComponentActivationOptions locationComponentActivationOptions = + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(true) + .build(); + assertNotNull(locationComponentActivationOptions); + } + + @Test + public void includingBothStyleResAndComponentOptions_causesExceptionToBeThrown() throws Exception { + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("You've provided both a style resource and a LocationComponentOptions" + + " object to the LocationComponentActivationOptions builder. You can't use both and " + + "you must choose one of the two to style the LocationComponent."); + + LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) + .accuracyAlpha(0.5f) + .build(); + + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .styleRes(R.style.mapbox_LocationComponent) + .build(); + } + + @Test + public void nullContext_causesExceptionToBeThrown() throws Exception { + thrown.expect(NullPointerException.class); + thrown.expectMessage("Context in LocationComponentActivationOptions is null."); + + LocationComponentActivationOptions.builder(null, style) + .build(); + } + + @Test + public void nullStyle_causesExceptionToBeThrown() throws Exception { + thrown.expect(NullPointerException.class); + thrown.expectMessage("Style in LocationComponentActivationOptions is null. Make sure the Style object isn't null." + + " Wait for the map to fully load before passing the Style object to LocationComponentActivationOptions."); + + LocationComponentActivationOptions.builder(context, null) + .build(); + } + + @Test + public void locationComponent_exceptionThrownWithDefaultLocationEngineButNotFullyLoadedStyle() throws Exception { + + when(style.isFullyLoaded()).thenReturn(false); + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Style in LocationComponentActivationOptions isn't fully loaded. Wait for the " + + "map to fully load before passing the Style object to " + + "LocationComponentActivationOptions."); + + LocationComponentActivationOptions.builder(context, style) + .build(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java new file mode 100644 index 000000000..b1e1f14cb --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java @@ -0,0 +1,81 @@ +package com.mapbox.mapboxsdk.location; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; + +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.R; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class LocationComponentOptionsTest { + + @Mock + private Context context; + @Mock + private TypedArray array; + @Mock + private Resources resources; + + @NonNull + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + when(context.obtainStyledAttributes(R.style.mapbox_LocationComponent, R.styleable.mapbox_LocationComponent)) + .thenReturn(array); + when(array.getResourceId(R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawable, -1)) + .thenReturn(R.drawable.mapbox_user_icon); + when(context.getResources()).thenReturn(resources); + } + + @Test + public void sanity() throws Exception { + LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) + .accuracyAlpha(0.5f) + .build(); + assertNotNull(locationComponentOptions); + } + + @Test + public void passingOutOfRangeAccuracyAlpha_throwsException() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Accuracy alpha value must be between 0.0 and " + + "1.0."); + LocationComponentOptions.builder(context) + .accuracyAlpha(2f) + .build(); + } + + @Test + public void negativeElevation_causesExceptionToBeThrown() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Invalid shadow size -500.0. Must be >= 0"); + LocationComponentOptions.builder(context) + .elevation(-500) + .build(); + } + + @Test + public void passingBothLayerPositionOptions_throwsException() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("You cannot set both layerAbove and layerBelow options." + + "Choose one or the other."); + LocationComponentOptions.builder(context) + .layerAbove("above") + .layerBelow("below") + .build(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt new file mode 100644 index 000000000..c8a75b670 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManagerTest.kt @@ -0,0 +1,130 @@ +package com.mapbox.mapboxsdk.location + +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.style.layers.Layer +import io.mockk.mockk +import io.mockk.verify +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class LocationComponentPositionManagerTest { + + private lateinit var style: Style + private lateinit var layer: Layer + + @Before + fun setup() { + style = mockk(relaxed = true) + layer = mockk(relaxed = true) + } + + @Test + fun update_noChange_null() { + val positionManager = LocationComponentPositionManager(style, null, null) + val requiresUpdate = positionManager.update(null, null) + assertFalse(requiresUpdate) + } + + @Test + fun update_noChange_above() { + val positionManager = LocationComponentPositionManager(style, "above", null) + val requiresUpdate = positionManager.update("above", null) + assertFalse(requiresUpdate) + } + + @Test + fun update_noChange_below() { + val positionManager = LocationComponentPositionManager(style, null, "below") + val requiresUpdate = positionManager.update(null, "below") + assertFalse(requiresUpdate) + } + + @Test + fun update_fromNull_above() { + val positionManager = LocationComponentPositionManager(style, null, null) + val requiresUpdate = positionManager.update("above", null) + assertTrue(requiresUpdate) + } + + @Test + fun update_fromNull_below() { + val positionManager = LocationComponentPositionManager(style, null, null) + val requiresUpdate = positionManager.update(null, "below") + assertTrue(requiresUpdate) + } + + @Test + fun update_toNull_above() { + val positionManager = LocationComponentPositionManager(style, "above", null) + val requiresUpdate = positionManager.update(null, null) + assertTrue(requiresUpdate) + } + + @Test + fun update_toNull_below() { + val positionManager = LocationComponentPositionManager(style, null, "below") + val requiresUpdate = positionManager.update(null, null) + assertTrue(requiresUpdate) + } + + @Test + fun update_fromValue_above() { + val positionManager = LocationComponentPositionManager(style, "above1", null) + val requiresUpdate = positionManager.update("above2", null) + assertTrue(requiresUpdate) + } + + @Test + fun update_fromValue_below() { + val positionManager = LocationComponentPositionManager(style, null, "below1") + val requiresUpdate = positionManager.update(null, "below2") + assertTrue(requiresUpdate) + } + + @Test + fun addLayer_noModifier() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.addLayerToMap(layer) + + verify { style.addLayer(layer) } + } + + @Test + fun addLayer_above() { + val positionManager = LocationComponentPositionManager(style, "above", null) + positionManager.addLayerToMap(layer) + + verify { style.addLayerAbove(layer, "above") } + } + + @Test + fun addLayer_below() { + val positionManager = LocationComponentPositionManager(style, null, "below") + positionManager.addLayerToMap(layer) + + verify { style.addLayerBelow(layer, "below") } + } + + @Test + fun addLayer_afterUpdate_above() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.update("above", null) + positionManager.addLayerToMap(layer) + + verify { style.addLayerAbove(layer, "above") } + } + + @Test + fun addLayer_afterUpdate_below() { + val positionManager = LocationComponentPositionManager(style, null, null) + positionManager.update(null, "below") + positionManager.addLayerToMap(layer) + + verify { style.addLayerBelow(layer, "below") } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt new file mode 100644 index 000000000..2994c29d5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -0,0 +1,453 @@ +package com.mapbox.mapboxsdk.location + +import android.content.Context +import android.content.res.Resources +import android.content.res.TypedArray +import android.location.Location +import android.os.Looper +import com.mapbox.android.core.location.LocationEngine +import com.mapbox.android.core.location.LocationEngineRequest +import com.mapbox.mapboxsdk.R +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS +import com.mapbox.mapboxsdk.location.modes.CameraMode +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.maps.Transform +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.MockitoAnnotations +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class LocationComponentTest { + private lateinit var locationComponent: LocationComponent + + @Mock + private lateinit var locationComponentOptions: LocationComponentOptions + + @Mock + private lateinit var mapboxMap: MapboxMap + + @Mock + private lateinit var transform: Transform + + @Mock + private lateinit var context: Context + + @Mock + private lateinit var locationEngine: LocationEngine + + @Mock + private lateinit var locationEngineRequest: LocationEngineRequest + + @Mock + private lateinit var currentListener: LocationComponent.CurrentLocationEngineCallback + + @Mock + private lateinit var lastListener: LocationComponent.LastLocationEngineCallback + + @Mock + private lateinit var compassEngine: CompassEngine + + @Mock + private lateinit var locationLayerController: LocationLayerController + + @Mock + private lateinit var locationCameraController: LocationCameraController + + @Mock + private lateinit var locationAnimatorCoordinator: LocationAnimatorCoordinator + + @Mock + private lateinit var staleStateManager: StaleStateManager + + @Mock + private lateinit var locationEngineProvider: LocationComponent.InternalLocationEngineProvider + + @Mock + private lateinit var style: Style + + private lateinit var developerAnimationListeners: List + + @Before + fun before() { + MockitoAnnotations.initMocks(this) + developerAnimationListeners = mutableListOf() + locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider) + doReturn(locationEngine).`when`(locationEngineProvider).getBestLocationEngine(context, false) + doReturn(style).`when`(mapboxMap).style + } + + @Test + fun activateWithRequestTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + + Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest) + + doReturn(mock(TypedArray::class.java)).`when`(context) + .obtainStyledAttributes(R.style.mapbox_LocationComponent, R.styleable.mapbox_LocationComponent) + + val resources = mock(Resources::class.java) + + doReturn(resources).`when`(context).resources + doReturn(0f).`when`(resources) + .getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold) + doReturn(0f).`when`(resources) + .getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold) + locationComponent.activateLocationComponent(context, mock(Style::class.java), true, locationEngineRequest) + Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest) + } + + @Test + fun activateWithDefaultLocationEngineRequestAndOptionsTestDefaultLocationEngine() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), true, locationEngineRequest, locationComponentOptions) + Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest) + Assert.assertNotNull(locationComponent.locationEngine) + } + + @Test + fun activateWithDefaultLocationEngineRequestAndOptionsTestCustomLocationEngine() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), false, locationEngineRequest, locationComponentOptions) + Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest) + Assert.assertNull(locationComponent.locationEngine) + } + + @Test + fun locationUpdatesWhenEnabledDisableTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + verify(locationEngine, times(0)).removeLocationUpdates(currentListener) + verify(locationEngine, times(0)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java)) + + locationComponent.onStart() + verify(locationEngine, times(0)).removeLocationUpdates(currentListener) + verify(locationEngine, times(0)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java)) + + locationComponent.isLocationComponentEnabled = true + verify(locationEngine).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java)) + + locationComponent.isLocationComponentEnabled = false + verify(locationEngine).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java)) + verify(locationEngine).removeLocationUpdates(currentListener) + } + + @Test + fun locationUpdatesWhenStartedStoppedTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + + locationComponent.onStop() + verify(locationEngine).removeLocationUpdates(currentListener) + + locationComponent.onStart() + verify(locationEngine, times(2)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java)) + } + + @Test + fun locationUpdatesWhenNewRequestTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + + val newRequest = mock(LocationEngineRequest::class.java) + locationComponent.locationEngineRequest = newRequest + verify(locationEngine).removeLocationUpdates(currentListener) + verify(locationEngine).requestLocationUpdates(eq(newRequest), eq(currentListener), any(Looper::class.java)) + } + + @Test + fun lastLocationUpdateOnStartTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + + verify(locationEngine).getLastLocation(lastListener) + } + + @Test + fun transitionCallbackFinishedTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + val listener = mock(OnLocationCameraTransitionListener::class.java) + + val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java) + locationComponent.setCameraMode(CameraMode.TRACKING, listener) + verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(TRANSITION_ANIMATION_DURATION_MS), isNull(), isNull(), isNull(), callback.capture()) + callback.value.onLocationCameraTransitionFinished(CameraMode.TRACKING) + + verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING) + verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false) + } + + @Test + fun transitionCallbackCanceledTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + val listener = mock(OnLocationCameraTransitionListener::class.java) + + val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java) + locationComponent.setCameraMode(CameraMode.TRACKING, listener) + verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(TRANSITION_ANIMATION_DURATION_MS), isNull(), isNull(), isNull(), callback.capture()) + callback.value.onLocationCameraTransitionCanceled(CameraMode.TRACKING) + + verify(listener).onLocationCameraTransitionCanceled(CameraMode.TRACKING) + verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false) + } + + @Test + fun transitionCustomFinishedTest() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + val listener = mock(OnLocationCameraTransitionListener::class.java) + + val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java) + locationComponent.setCameraMode(CameraMode.TRACKING, 1200, 14.0, 13.0, 45.0, listener) + verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(1200L), eq(14.0), eq(13.0), eq(45.0), callback.capture()) + callback.value.onLocationCameraTransitionFinished(CameraMode.TRACKING) + + verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING) + verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false) + } + + @Test + fun compass_listenWhenConsumedByNoneCamera() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationCameraController.isConsumingCompass).thenReturn(true) + locationComponent.cameraMode = CameraMode.NONE_COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_listenWhenConsumedByTrackingCamera() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationCameraController.isConsumingCompass).thenReturn(true) + locationComponent.cameraMode = CameraMode.TRACKING_COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_listenWhenConsumedByLayer() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notListenWhenNotConsumed() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(false) + `when`(locationCameraController.isConsumingCompass).thenReturn(false) + locationComponent.renderMode = RenderMode.GPS + locationComponent.renderMode = RenderMode.NORMAL + locationComponent.cameraMode = CameraMode.TRACKING + locationComponent.cameraMode = CameraMode.NONE + locationComponent.cameraMode = CameraMode.NONE_GPS + locationComponent.cameraMode = CameraMode.TRACKING_GPS + locationComponent.cameraMode = CameraMode.TRACKING_GPS_NORTH + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnChange() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + `when`(locationLayerController.isConsumingCompass).thenReturn(false) + locationComponent.renderMode = RenderMode.NORMAL + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnStop() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStop() + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnStart() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStop() + locationComponent.onStart() + verify(compassEngine, times(2)).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnStyleStartLoad() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStartLoadingMap() + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnStyleLoadFinished() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStartLoadingMap() + locationComponent.onFinishLoadingStyle() + verify(compassEngine, times(2)).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnlyWhenEnabled() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.isLocationComponentEnabled = false + + locationComponent.onStartLoadingMap() + locationComponent.onFinishLoadingStyle() + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notAdListenerWhenDisabled() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notAdListenerWhenStopped() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun developerAnimationCalled() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + for (listener in developerAnimationListeners) { + listener.onDeveloperAnimationStarted() + } + verify(locationCameraController).setCameraMode(eq(CameraMode.NONE), isNull(), eq(TRANSITION_ANIMATION_DURATION_MS), isNull(), isNull(), isNull(), any()) + } + + @Test + fun internal_cameraTrackingChangedListener_onCameraTrackingDismissed() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + + val cameraChangeListener: OnCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener::class.java) + locationComponent.addOnCameraTrackingChangedListener(cameraChangeListener) + + locationComponent.cameraTrackingChangedListener.onCameraTrackingDismissed() + + verify(cameraChangeListener).onCameraTrackingDismissed() + } + + @Test + fun internal_cameraTrackingChangedListener_onCameraTrackingChanged() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + + val cameraValueListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java) + val layerValueListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java) + `when`(locationCameraController.animationListeners).thenReturn(setOf(cameraValueListener)) + `when`(locationLayerController.animationListeners).thenReturn(setOf(layerValueListener)) + val cameraChangeListener: OnCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener::class.java) + locationComponent.addOnCameraTrackingChangedListener(cameraChangeListener) + + locationComponent.cameraTrackingChangedListener.onCameraTrackingChanged(CameraMode.TRACKING_GPS) + + verify(locationAnimatorCoordinator).cancelZoomAnimation() + verify(locationAnimatorCoordinator).cancelTiltAnimation() + verify(locationAnimatorCoordinator).updateAnimatorListenerHolders(eq(setOf(cameraValueListener, layerValueListener))) + verify(locationAnimatorCoordinator).resetAllCameraAnimations(any(), anyBoolean()) + verify(locationAnimatorCoordinator).resetAllLayerAnimations() + verify(cameraChangeListener).onCameraTrackingChanged(CameraMode.TRACKING_GPS) + } + + @Test + fun internal_renderModeChangedListener_onRenderModeChanged() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + + val cameraListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java) + val layerListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java) + `when`(locationCameraController.animationListeners).thenReturn(setOf(cameraListener)) + `when`(locationLayerController.animationListeners).thenReturn(setOf(layerListener)) + val renderChangeListener: OnRenderModeChangedListener = mock(OnRenderModeChangedListener::class.java) + locationComponent.addOnRenderModeChangedListener(renderChangeListener) + + locationComponent.renderModeChangedListener.onRenderModeChanged(RenderMode.NORMAL) + + verify(locationAnimatorCoordinator).updateAnimatorListenerHolders(eq(setOf(cameraListener, layerListener))) + verify(locationAnimatorCoordinator).resetAllCameraAnimations(any(), anyBoolean()) + verify(locationAnimatorCoordinator).resetAllLayerAnimations() + verify(renderChangeListener).onRenderModeChanged(RenderMode.NORMAL) + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java new file mode 100644 index 000000000..ed2d015d8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -0,0 +1,718 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; +import android.support.annotation.NonNull; + +import com.google.gson.JsonElement; +import com.mapbox.geojson.Feature; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURACY; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +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 LocationLayerControllerTest { + + private MapboxMap mapboxMap = mock(MapboxMap.class); + private Style style = mock(Style.class); + + @Before + public void before() { + when(mapboxMap.getStyle()).thenReturn(style); + } + + @Test + public void onInitialization_locationSourceIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addSource(locationSource); + } + + @Test + public void onInitialization_shadowLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer shadowLayer = mock(Layer.class); + when(sourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addLayerBelow(shadowLayer, BACKGROUND_LAYER); + } + + @Test + public void onInitialization_backgroundLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer backgroundLayer = mock(Layer.class); + when(sourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addLayerBelow(backgroundLayer, FOREGROUND_LAYER); + } + + @Test + public void onInitialization_foregroundLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer foregroundLayer = mock(Layer.class); + when(sourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addLayerBelow(foregroundLayer, BEARING_LAYER); + } + + @Test + public void onInitialization_bearingLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer bearingLayer = mock(Layer.class); + when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + String layerBelow = "layer-below"; + when(options.layerBelow()).thenReturn(layerBelow); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addLayerBelow(bearingLayer, layerBelow); + } + + @Test + public void onInitialization_accuracyLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer accuracyLayer = mock(Layer.class); + when(sourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addLayerBelow(accuracyLayer, BACKGROUND_LAYER); + } + + @Test + public void onInitialization_numberOfCachedLayerIdsIsConstant() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + controller.initializeComponents(mapboxMap.getStyle(), options); + + assertEquals(5, controller.layerSet.size()); + } + + @Test + public void applyStyle_styleShadowWithValidElevation() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateShadowBitmap(any(LocationComponentOptions.class))).thenReturn(bitmap); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.elevation()).thenReturn(2f); + + // Style is applied on initialization + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(SHADOW_ICON, bitmap); + } + + @Test + public void applyStyle_ignoreStyleShadowWithInvalidElevation() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateShadowBitmap(any(LocationComponentOptions.class))).thenReturn(bitmap); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.elevation()).thenReturn(0f); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style, times(0)).addImage(SHADOW_ICON, bitmap); + } + + @Test + public void applyStyle_styleForegroundFromOptions() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.foregroundDrawable()).thenReturn(drawableResId); + when(options.foregroundTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(FOREGROUND_ICON, bitmap); + } + + @Test + public void applyStyle_styleForegroundStaleFromOptions() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.foregroundDrawableStale()).thenReturn(drawableResId); + when(options.foregroundStaleTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(FOREGROUND_STALE_ICON, bitmap); + } + + @Test + public void applyStyle_styleBackgroundFromOptions() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.backgroundDrawable()).thenReturn(drawableResId); + when(options.backgroundTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(BACKGROUND_ICON, bitmap); + } + + @Test + public void applyStyle_styleBackgroundStaleFromOptions() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.backgroundDrawableStale()).thenReturn(drawableResId); + when(options.backgroundStaleTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(BACKGROUND_STALE_ICON, bitmap); + } + + @Test + public void applyStyle_styleBearingFromOptions() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.bearingDrawable()).thenReturn(drawableResId); + when(options.bearingTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(BEARING_ICON, bitmap); + } + + @Test + public void applyStyle_layerBelowChanged() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + + LocationComponentOptions options = mock(LocationComponentOptions.class); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateShadowBitmap(any(LocationComponentOptions.class))).thenReturn(bitmap); + + LocationLayerController layerController = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + Layer bearingLayer2 = mock(Layer.class); + when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer2); + Layer foregroundLayer2 = mock(Layer.class); + when(sourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer2); + Layer backgroundLayer2 = mock(Layer.class); + when(sourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer2); + Layer shadowLayer2 = mock(Layer.class); + when(sourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer2); + Layer accuracyLayer2 = mock(Layer.class); + when(sourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer2); + String layerBelow = "layer-below"; + when(options.layerBelow()).thenReturn(layerBelow); + + layerController.applyStyle(options); + + verify(style).removeLayer(BEARING_LAYER); + verify(style).removeLayer(FOREGROUND_LAYER); + verify(style).removeLayer(BACKGROUND_LAYER); + verify(style).removeLayer(SHADOW_LAYER); + verify(style).removeLayer(ACCURACY_LAYER); + + verify(style).addLayerBelow(bearingLayer2, layerBelow); + verify(style).addLayerBelow(foregroundLayer2, BEARING_LAYER); + verify(style).addLayerBelow(backgroundLayer2, FOREGROUND_LAYER); + verify(style).addLayerBelow(shadowLayer2, BACKGROUND_LAYER); + verify(style).addLayerBelow(accuracyLayer2, BACKGROUND_LAYER); + } + + @Test + public void applyStyle_layerBelowNotChanged() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateShadowBitmap(any(LocationComponentOptions.class))).thenReturn(bitmap); + + String layerBelow = "layer-below"; + when(options.layerBelow()).thenReturn(layerBelow); + + LocationLayerController layerController = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + options = mock(LocationComponentOptions.class); + layerBelow = "layer-below"; + when(options.layerBelow()).thenReturn(layerBelow); + layerController.applyStyle(options); + + verify(style, times(0)).removeLayer(any(String.class)); + verify(style, times(5)).addLayerBelow(any(Layer.class), any(String.class)); + } + + @Test + public void applyStyle_layerBelowNotChangedNull() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateShadowBitmap(any(LocationComponentOptions.class))).thenReturn(bitmap); + + LocationLayerController layerController = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + options = mock(LocationComponentOptions.class); + layerController.applyStyle(options); + + verify(style, times(0)).removeLayer(any(String.class)); + verify(style, times(1)).addLayer(any(Layer.class)); + verify(style, times(4)).addLayerBelow(any(Layer.class), Mockito.any()); + } + + @Test + public void updateForegroundOffset_foregroundIconPropertyIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + + layer.updateForegroundOffset(2d); + + verify(locationFeature).addProperty(eq(PROPERTY_FOREGROUND_ICON_OFFSET), any(JsonElement.class)); + } + + @Test + public void updateForegroundOffset_shadowPropertyIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.updateForegroundOffset(2d); + + verify(locationFeature).addProperty(eq(PROPERTY_SHADOW_ICON_OFFSET), any(JsonElement.class)); + } + + @Test + public void onNewLatLngValue_locationFeatureIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + + getAnimationListener(ANIMATOR_LAYER_LATLNG, layer.getAnimationListeners()).onNewAnimationValue(new LatLng()); + + // wanted twice (once for initialization) + verify(locationSource, times(2)).setGeoJson(locationFeature); + } + + @Test + public void onNewGpsBearingValue_locationFeatureIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.GPS); + float gpsBearing = 2f; + + getAnimationListener(ANIMATOR_LAYER_GPS_BEARING, layer.getAnimationListeners()).onNewAnimationValue(gpsBearing); + + verify(locationFeature).addNumberProperty(PROPERTY_GPS_BEARING, gpsBearing); + } + + @Test + public void onNewGpsBearingValue_updateIgnoredWithInvalidRenderMode() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.COMPASS); + float gpsBearing = 2f; + + assertNull(getAnimationListener(ANIMATOR_LAYER_GPS_BEARING, layer.getAnimationListeners())); + verify(locationFeature, times(0)).addNumberProperty(PROPERTY_GPS_BEARING, gpsBearing); + } + + @Test + public void onNewCompassBearingValue_locationFeatureIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.COMPASS); + float compassBearing = 2f; + + getAnimationListener(ANIMATOR_LAYER_COMPASS_BEARING, layer.getAnimationListeners()) + .onNewAnimationValue(compassBearing); + + verify(locationFeature).addNumberProperty(PROPERTY_COMPASS_BEARING, compassBearing); + } + + @Test + public void onNewCompassBearingValue_updateIgnoredWithInvalidRenderMode() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.GPS); + float compassBearing = 2f; + + assertNull(getAnimationListener(ANIMATOR_LAYER_COMPASS_BEARING, layer.getAnimationListeners())); + verify(locationFeature, times(0)).addNumberProperty(PROPERTY_COMPASS_BEARING, compassBearing); + } + + @Test + public void onNewAccuracyRadiusValue_locationFeatureIsUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.NORMAL); + float accuracyRadiusValue = 2f; + + getAnimationListener(ANIMATOR_LAYER_ACCURACY, layer.getAnimationListeners()) + .onNewAnimationValue(accuracyRadiusValue); + + verify(locationFeature).addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracyRadiusValue); + } + + @Test + public void onNewAccuracyRadiusValue_updateIgnoredWithInvalidRenderMode() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(style.getSourceAs(LOCATION_SOURCE)).thenReturn(locationSource); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + Feature locationFeature = mock(Feature.class); + LocationLayerController layer = new LocationLayerController( + mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), + bitmapProvider, options, internalRenderModeChangedListener + ); + layer.setRenderMode(RenderMode.GPS); + float accuracyRadiusValue = 2f; + + assertNull(getAnimationListener(ANIMATOR_LAYER_ACCURACY, layer.getAnimationListeners())); + verify(locationFeature, times(0)) + .addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracyRadiusValue); + } + + @Test + public void renderModeChanged_doNotNotifyAboutDuplicates_NORMAL() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + controller.setRenderMode(RenderMode.NORMAL); + controller.setRenderMode(RenderMode.NORMAL); + + verify(internalRenderModeChangedListener, times(1)).onRenderModeChanged(RenderMode.NORMAL); + } + + @Test + public void renderModeChanged_doNotNotifyAboutDuplicates_GPS() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + controller.setRenderMode(RenderMode.GPS); + controller.setRenderMode(RenderMode.GPS); + + verify(internalRenderModeChangedListener, times(1)).onRenderModeChanged(RenderMode.GPS); + } + + @Test + public void layerHidden_renderModeChanged_layerShown_foregroundIconUpdated() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); + LocationComponentOptions options = mock(LocationComponentOptions.class); + int drawableResId = 123; + int tintColor = 456; + when(options.foregroundDrawable()).thenReturn(drawableResId); + when(options.foregroundTintColor()).thenReturn(tintColor); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + Bitmap bitmap = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + verify(style).addImage(FOREGROUND_ICON, bitmap); + + int drawableGpsResId = 789; + when(options.gpsDrawable()).thenReturn(drawableGpsResId); + + Bitmap bitmapGps = mock(Bitmap.class); + when(bitmapProvider.generateBitmap(drawableGpsResId, tintColor)).thenReturn(bitmapGps); + + controller.hide(); + + controller.setRenderMode(RenderMode.GPS); + + controller.show(); + + verify(style).addImage(FOREGROUND_ICON, bitmapGps); + } + + private LayerFeatureProvider buildFeatureProvider(@NonNull LocationComponentOptions options) { + LayerFeatureProvider provider = mock(LayerFeatureProvider.class); + when(provider.generateLocationFeature(null, options)).thenReturn(mock(Feature.class)); + return provider; + } + + private LayerFeatureProvider buildFeatureProvider(Feature feature, @NonNull LocationComponentOptions options) { + LayerFeatureProvider provider = mock(LayerFeatureProvider.class); + when(provider.generateLocationFeature(null, options)).thenReturn(feature); + return provider; + } + + private LayerSourceProvider buildLayerProvider() { + LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); + + Layer shadowLayer = mock(Layer.class); + when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); + when(layerSourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); + + Layer backgroundLayer = mock(Layer.class); + when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER); + when(layerSourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); + + Layer foregroundLayer = mock(Layer.class); + when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER); + when(layerSourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); + + Layer bearingLayer = mock(Layer.class); + when(bearingLayer.getId()).thenReturn(BEARING_LAYER); + when(layerSourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); + + Layer accuracyLayer = mock(Layer.class); + when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); + when(layerSourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); + return layerSourceProvider; + } + + private MapboxAnimator.AnimationsValueChangeListener getAnimationListener( + @MapboxAnimator.Type int animatorType, + Set holders) { + for (AnimatorListenerHolder holder : holders) { + @MapboxAnimator.Type int type = holder.getAnimatorType(); + if (type == animatorType) { + return holder.getListener(); + } + } + return null; + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt new file mode 100644 index 000000000..7c126c783 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt @@ -0,0 +1,43 @@ +package com.mapbox.mapboxsdk.location + +import android.animation.ValueAnimator +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class MapboxAnimatorTest { + + @Test + fun fps_unlimited() { + val valueAnimator = mockk() + every { valueAnimator.animatedValue } answers { 5f } + val listener = mockk>() + every { listener.onNewAnimationValue(any()) } answers {} + val mapboxAnimator = MapboxFloatAnimator(0f, 10f, listener, Int.MAX_VALUE) + + for (i in 0 until 5) + mapboxAnimator.onAnimationUpdate(valueAnimator) + + verify(exactly = 5) { listener.onNewAnimationValue(5f) } + } + + @Test + fun fps_limited() { + val valueAnimator = mockk() + every { valueAnimator.animatedValue } answers { 5f } + val listener = mockk>() + every { listener.onNewAnimationValue(any()) } answers {} + val mapboxAnimator = MapboxFloatAnimator(0f, 10f, listener, 5) + + for (i in 0 until 5) { + mapboxAnimator.onAnimationUpdate(valueAnimator) + Thread.sleep(150) + } + + verify(exactly = 3) { listener.onNewAnimationValue(5f) } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/UtilsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/UtilsTest.java new file mode 100644 index 000000000..bf5ee40f4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/UtilsTest.java @@ -0,0 +1,28 @@ +package com.mapbox.mapboxsdk.location; + +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + +public final class UtilsTest { + + @Test + public void shortestRotation_doesReturnValueDistanceQuickestToZero() throws Exception { + float value = Utils.shortestRotation(0, 181); + assertEquals(360f, value); + value = Utils.shortestRotation(0, 179); + assertEquals(0f, value); + value = Utils.shortestRotation(0, 180); + assertEquals(0f, value); + } + + @Test + public void shortestRotation_doesReturnValueDistanceQuickestToFifty() throws Exception { + float value = Utils.shortestRotation(50, 231); + assertEquals(410f, value); + value = Utils.shortestRotation(50, 229); + assertEquals(50f, value); + value = Utils.shortestRotation(50, 180); + assertEquals(50f, value); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/log/LoggerTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/log/LoggerTest.kt new file mode 100644 index 000000000..82e1c67f6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/log/LoggerTest.kt @@ -0,0 +1,93 @@ +package com.mapbox.mapboxsdk.log + +import io.mockk.mockk +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class LoggerTest { + + private val logger: LoggerDefinition = mockk(relaxed = true) + + @Before + fun setUp() { + Logger.setLoggerDefinition(logger) + } + + @Test + fun verbosityLogLevel() { + Logger.setVerbosity(Logger.VERBOSE) + Logger.v(TAG, MESSAGE) + verify { logger.v(TAG, MESSAGE) } + } + + @Test + fun verbosityLogLevelIgnore() { + Logger.setVerbosity(Logger.DEBUG) + Logger.v(TAG, MESSAGE) + verify(exactly = 0) { logger.v(TAG, MESSAGE) } + } + + @Test + fun debugLogLevel() { + Logger.setVerbosity(Logger.VERBOSE) + Logger.d(TAG, MESSAGE) + verify { logger.d(TAG, MESSAGE) } + } + + @Test + fun debugLogLevelIgnore() { + Logger.setVerbosity(Logger.WARN) + Logger.d(TAG, MESSAGE) + verify(exactly = 0) { logger.d(TAG, MESSAGE) } + } + + @Test + fun warnLogLevel() { + Logger.setVerbosity(Logger.WARN) + Logger.w(TAG, MESSAGE) + verify { logger.w(TAG, MESSAGE) } + } + + @Test + fun warnLogLevelIgnore() { + Logger.setVerbosity(Logger.ERROR) + Logger.w(TAG, MESSAGE) + verify(exactly = 0) { logger.w(TAG, MESSAGE) } + } + + @Test + fun errorLogLevel() { + Logger.setVerbosity(Logger.ERROR) + Logger.e(TAG, MESSAGE) + verify { logger.e(TAG, MESSAGE) } + } + + @Test + fun errorLogLevelIgnore() { + Logger.setVerbosity(Logger.NONE) + Logger.e(TAG, MESSAGE) + verify(exactly = 0) { logger.e(TAG, MESSAGE) } + } + + @Test + fun noneLogLevelIgnore() { + Logger.setVerbosity(Logger.NONE) + Logger.v(TAG, MESSAGE) + Logger.d(TAG, MESSAGE) + Logger.w(TAG, MESSAGE) + Logger.e(TAG, MESSAGE) + verify(exactly = 0) { logger.v(TAG, MESSAGE) } + verify(exactly = 0) { logger.d(TAG, MESSAGE) } + verify(exactly = 0) { logger.w(TAG, MESSAGE) } + verify(exactly = 0) { logger.e(TAG, MESSAGE) } + } + + companion object { + const val TAG: String = "TAG" + const val MESSAGE: String = "message" + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java new file mode 100644 index 000000000..fd59f52a5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java @@ -0,0 +1,86 @@ +package com.mapbox.mapboxsdk.maps; + +import android.support.v4.util.LongSparseArray; + +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Test; +import org.mockito.ArgumentMatchers; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AnnotationManagerTest { + + @Test + public void checksAddAMarker() throws Exception { + NativeMap aNativeMapView = mock(NativeMapView.class); + MapView aMapView = mock(MapView.class); + LongSparseArray annotationsArray = new LongSparseArray<>(); + IconManager aIconManager = mock(IconManager.class); + Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray); + Markers markers = new MarkerContainer(aNativeMapView, annotationsArray, aIconManager); + Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray); + Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray); + ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray); + AnnotationManager annotationManager = new AnnotationManager(aMapView, annotationsArray, + aIconManager, annotations, markers, polygons, polylines, shapeAnnotations); + Marker aMarker = mock(Marker.class); + long aId = 5L; + when(aNativeMapView.addMarker(aMarker)).thenReturn(aId); + BaseMarkerOptions aMarkerOptions = mock(BaseMarkerOptions.class); + MapboxMap aMapboxMap = mock(MapboxMap.class); + when(aMarkerOptions.getMarker()).thenReturn(aMarker); + + annotationManager.addMarker(aMarkerOptions, aMapboxMap); + + assertEquals(aMarker, annotationManager.getAnnotations().get(0)); + assertEquals(aMarker, annotationManager.getAnnotation(aId)); + } + + @Test + public void checksAddMarkers() throws Exception { + NativeMapView aNativeMapView = mock(NativeMapView.class); + MapView aMapView = mock(MapView.class); + LongSparseArray annotationsArray = new LongSparseArray<>(); + IconManager aIconManager = mock(IconManager.class); + Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray); + Markers markers = new MarkerContainer(aNativeMapView, annotationsArray, aIconManager); + Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray); + Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray); + ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray); + AnnotationManager annotationManager = new AnnotationManager(aMapView, annotationsArray, + aIconManager, annotations, markers, polygons, polylines, shapeAnnotations); + + long firstId = 1L; + long secondId = 2L; + List 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.anyList())) + .thenReturn(new long[] {firstId, secondId}); + + annotationManager.addMarkers(markerList, aMapboxMap); + + assertEquals(2, annotationManager.getAnnotations().size()); + assertEquals("first", ((Marker) annotationManager.getAnnotations().get(0)).getTitle()); + assertEquals("second", ((Marker) annotationManager.getAnnotations().get(1)).getTitle()); + assertEquals("first", ((Marker) annotationManager.getAnnotation(firstId)).getTitle()); + assertEquals("second", ((Marker) annotationManager.getAnnotation(secondId)).getTitle()); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java new file mode 100644 index 000000000..025f06752 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java @@ -0,0 +1,586 @@ +package com.mapbox.mapboxsdk.maps; + +import com.google.common.util.concurrent.ExecutionError; +import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.log.LoggerDefinition; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +/** + * Tests integration of MapChangeDispatcher and see if events are correctly forwarded. + */ +public class MapChangeReceiverTest { + + private static final String TEST_STRING = "mapChangeRandom"; + + private MapChangeReceiver mapChangeEventManager; + + @Mock + private MapView.OnCameraWillChangeListener onCameraWillChangeListener; + + @Mock + private MapView.OnCameraDidChangeListener onCameraDidChangeListener; + + @Mock + private MapView.OnCameraIsChangingListener onCameraIsChangingListener; + + @Mock + private MapView.OnWillStartLoadingMapListener onWillStartLoadingMapListener; + + @Mock + private MapView.OnDidFinishLoadingMapListener onDidFinishLoadingMapListener; + + @Mock + private MapView.OnDidFailLoadingMapListener onDidFailLoadingMapListener; + + @Mock + private MapView.OnWillStartRenderingFrameListener onWillStartRenderingFrameListener; + + @Mock + private MapView.OnDidFinishRenderingFrameListener onDidFinishRenderingFrameListener; + + @Mock + private MapView.OnWillStartRenderingMapListener onWillStartRenderingMapListener; + + @Mock + private MapView.OnDidFinishRenderingMapListener onDidFinishRenderingMapListener; + + @Mock + private MapView.OnDidBecomeIdleListener onDidBecomeIdleListener; + + @Mock + private MapView.OnDidFinishLoadingStyleListener onDidFinishLoadingStyleListener; + + @Mock + private MapView.OnSourceChangedListener onSourceChangedListener; + + @Mock + private LoggerDefinition loggerDefinition; + + @Before + public void beforeTest() { + MockitoAnnotations.initMocks(this); + mapChangeEventManager = new MapChangeReceiver(); + } + + @Test + public void testOnCameraRegionWillChangeListener() { + mapChangeEventManager.addOnCameraWillChangeListener(onCameraWillChangeListener); + mapChangeEventManager.onCameraWillChange(false); + verify(onCameraWillChangeListener).onCameraWillChange(false); + + mapChangeEventManager.removeOnCameraWillChangeListener(onCameraWillChangeListener); + mapChangeEventManager.onCameraWillChange(false); + verify(onCameraWillChangeListener).onCameraWillChange(false); + + mapChangeEventManager.addOnCameraWillChangeListener(onCameraWillChangeListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onCameraWillChangeListener).onCameraWillChange(false); + try { + mapChangeEventManager.onCameraWillChange(false); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onCameraWillChangeListener).onCameraWillChange(false); + try { + mapChangeEventManager.onCameraWillChange(false); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnCameraRegionWillChangeAnimatedListener() { + mapChangeEventManager.addOnCameraWillChangeListener(onCameraWillChangeListener); + mapChangeEventManager.onCameraWillChange(true); + verify(onCameraWillChangeListener).onCameraWillChange(true); + mapChangeEventManager.removeOnCameraWillChangeListener(onCameraWillChangeListener); + mapChangeEventManager.onCameraWillChange(true); + verify(onCameraWillChangeListener).onCameraWillChange(true); + + mapChangeEventManager.addOnCameraWillChangeListener(onCameraWillChangeListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onCameraWillChangeListener).onCameraWillChange(true); + try { + mapChangeEventManager.onCameraWillChange(true); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onCameraWillChangeListener).onCameraWillChange(true); + try { + mapChangeEventManager.onCameraWillChange(true); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnCameraIsChangingListener() { + mapChangeEventManager.addOnCameraIsChangingListener(onCameraIsChangingListener); + mapChangeEventManager.onCameraIsChanging(); + verify(onCameraIsChangingListener).onCameraIsChanging(); + mapChangeEventManager.removeOnCameraIsChangingListener(onCameraIsChangingListener); + mapChangeEventManager.onCameraIsChanging(); + verify(onCameraIsChangingListener).onCameraIsChanging(); + + mapChangeEventManager.addOnCameraIsChangingListener(onCameraIsChangingListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onCameraIsChangingListener).onCameraIsChanging(); + try { + mapChangeEventManager.onCameraIsChanging(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onCameraIsChangingListener).onCameraIsChanging(); + try { + mapChangeEventManager.onCameraIsChanging(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnCameraRegionDidChangeListener() { + mapChangeEventManager.addOnCameraDidChangeListener(onCameraDidChangeListener); + mapChangeEventManager.onCameraDidChange(false); + verify(onCameraDidChangeListener).onCameraDidChange(false); + mapChangeEventManager.removeOnCameraDidChangeListener(onCameraDidChangeListener); + mapChangeEventManager.onCameraDidChange(false); + verify(onCameraDidChangeListener).onCameraDidChange(false); + + mapChangeEventManager.addOnCameraDidChangeListener(onCameraDidChangeListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onCameraDidChangeListener).onCameraDidChange(false); + try { + mapChangeEventManager.onCameraDidChange(false); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onCameraDidChangeListener).onCameraDidChange(false); + try { + mapChangeEventManager.onCameraDidChange(false); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnCameraRegionDidChangeAnimatedListener() { + mapChangeEventManager.addOnCameraDidChangeListener(onCameraDidChangeListener); + mapChangeEventManager.onCameraDidChange(true); + verify(onCameraDidChangeListener).onCameraDidChange(true); + mapChangeEventManager.removeOnCameraDidChangeListener(onCameraDidChangeListener); + mapChangeEventManager.onCameraDidChange(true); + verify(onCameraDidChangeListener).onCameraDidChange(true); + + mapChangeEventManager.addOnCameraDidChangeListener(onCameraDidChangeListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onCameraDidChangeListener).onCameraDidChange(true); + try { + mapChangeEventManager.onCameraDidChange(true); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onCameraDidChangeListener).onCameraDidChange(true); + try { + mapChangeEventManager.onCameraDidChange(true); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnWillStartLoadingMapListener() { + mapChangeEventManager.addOnWillStartLoadingMapListener(onWillStartLoadingMapListener); + mapChangeEventManager.onWillStartLoadingMap(); + verify(onWillStartLoadingMapListener).onWillStartLoadingMap(); + mapChangeEventManager.removeOnWillStartLoadingMapListener(onWillStartLoadingMapListener); + mapChangeEventManager.onWillStartLoadingMap(); + verify(onWillStartLoadingMapListener).onWillStartLoadingMap(); + + mapChangeEventManager.addOnWillStartLoadingMapListener(onWillStartLoadingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onWillStartLoadingMapListener).onWillStartLoadingMap(); + try { + mapChangeEventManager.onWillStartLoadingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onWillStartLoadingMapListener).onWillStartLoadingMap(); + try { + mapChangeEventManager.onWillStartLoadingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishLoadingMapListener() { + mapChangeEventManager.addOnDidFinishLoadingMapListener(onDidFinishLoadingMapListener); + mapChangeEventManager.onDidFinishLoadingMap(); + verify(onDidFinishLoadingMapListener).onDidFinishLoadingMap(); + mapChangeEventManager.removeOnDidFinishLoadingMapListener(onDidFinishLoadingMapListener); + mapChangeEventManager.onDidFinishLoadingMap(); + verify(onDidFinishLoadingMapListener).onDidFinishLoadingMap(); + + mapChangeEventManager.addOnDidFinishLoadingMapListener(onDidFinishLoadingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishLoadingMapListener).onDidFinishLoadingMap(); + try { + mapChangeEventManager.onDidFinishLoadingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishLoadingMapListener).onDidFinishLoadingMap(); + try { + mapChangeEventManager.onDidFinishLoadingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFailLoadingMapListener() { + mapChangeEventManager.addOnDidFailLoadingMapListener(onDidFailLoadingMapListener); + mapChangeEventManager.onDidFailLoadingMap(TEST_STRING); + verify(onDidFailLoadingMapListener).onDidFailLoadingMap(TEST_STRING); + mapChangeEventManager.removeOnDidFailLoadingMapListener(onDidFailLoadingMapListener); + mapChangeEventManager.onDidFailLoadingMap(TEST_STRING); + verify(onDidFailLoadingMapListener).onDidFailLoadingMap(TEST_STRING); + + mapChangeEventManager.addOnDidFailLoadingMapListener(onDidFailLoadingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFailLoadingMapListener).onDidFailLoadingMap(TEST_STRING); + try { + mapChangeEventManager.onDidFailLoadingMap(TEST_STRING); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFailLoadingMapListener).onDidFailLoadingMap(TEST_STRING); + try { + mapChangeEventManager.onDidFailLoadingMap(TEST_STRING); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnWillStartRenderingFrameListener() { + mapChangeEventManager.addOnWillStartRenderingFrameListener(onWillStartRenderingFrameListener); + mapChangeEventManager.onWillStartRenderingFrame(); + verify(onWillStartRenderingFrameListener).onWillStartRenderingFrame(); + mapChangeEventManager.removeOnWillStartRenderingFrameListener(onWillStartRenderingFrameListener); + mapChangeEventManager.onWillStartRenderingFrame(); + verify(onWillStartRenderingFrameListener).onWillStartRenderingFrame(); + + mapChangeEventManager.addOnWillStartRenderingFrameListener(onWillStartRenderingFrameListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onWillStartRenderingFrameListener).onWillStartRenderingFrame(); + try { + mapChangeEventManager.onWillStartRenderingFrame(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onWillStartRenderingFrameListener).onWillStartRenderingFrame(); + try { + mapChangeEventManager.onWillStartRenderingFrame(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishRenderingFrameListener() { + mapChangeEventManager.addOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + mapChangeEventManager.onDidFinishRenderingFrame(true); + verify(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(true); + mapChangeEventManager.removeOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + mapChangeEventManager.onDidFinishRenderingFrame(true); + verify(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(true); + + mapChangeEventManager.addOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(true); + try { + mapChangeEventManager.onDidFinishRenderingFrame(true); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(true); + try { + mapChangeEventManager.onDidFinishRenderingFrame(true); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishRenderingFrameFullyRenderedListener() { + mapChangeEventManager.addOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + mapChangeEventManager.onDidFinishRenderingFrame(false); + verify(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(false); + mapChangeEventManager.removeOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + mapChangeEventManager.onDidFinishRenderingFrame(false); + verify(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(false); + + mapChangeEventManager.addOnDidFinishRenderingFrameListener(onDidFinishRenderingFrameListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(false); + try { + mapChangeEventManager.onDidFinishRenderingFrame(false); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishRenderingFrameListener).onDidFinishRenderingFrame(false); + try { + mapChangeEventManager.onDidFinishRenderingFrame(false); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnWillStartRenderingMapListener() { + mapChangeEventManager.addOnWillStartRenderingMapListener(onWillStartRenderingMapListener); + mapChangeEventManager.onWillStartRenderingMap(); + verify(onWillStartRenderingMapListener).onWillStartRenderingMap(); + mapChangeEventManager.removeOnWillStartRenderingMapListener(onWillStartRenderingMapListener); + mapChangeEventManager.onWillStartRenderingMap(); + verify(onWillStartRenderingMapListener).onWillStartRenderingMap(); + + mapChangeEventManager.addOnWillStartRenderingMapListener(onWillStartRenderingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onWillStartRenderingMapListener).onWillStartRenderingMap(); + try { + mapChangeEventManager.onWillStartRenderingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onWillStartRenderingMapListener).onWillStartRenderingMap(); + try { + mapChangeEventManager.onWillStartRenderingMap(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishRenderingMapListener() { + mapChangeEventManager.addOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + mapChangeEventManager.onDidFinishRenderingMap(true); + verify(onDidFinishRenderingMapListener).onDidFinishRenderingMap(true); + mapChangeEventManager.removeOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + mapChangeEventManager.onDidFinishRenderingMap(true); + verify(onDidFinishRenderingMapListener).onDidFinishRenderingMap(true); + + mapChangeEventManager.addOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishRenderingMapListener).onDidFinishRenderingMap(true); + try { + mapChangeEventManager.onDidFinishRenderingMap(true); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishRenderingMapListener).onDidFinishRenderingMap(true); + try { + mapChangeEventManager.onDidFinishRenderingMap(true); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishRenderingMapFullyRenderedListener() { + mapChangeEventManager.addOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + mapChangeEventManager.onDidFinishRenderingMap(false); + verify(onDidFinishRenderingMapListener).onDidFinishRenderingMap(false); + mapChangeEventManager.removeOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + mapChangeEventManager.onDidFinishRenderingMap(false); + verify(onDidFinishRenderingMapListener).onDidFinishRenderingMap(false); + + mapChangeEventManager.addOnDidFinishRenderingMapListener(onDidFinishRenderingMapListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishRenderingMapListener).onDidFinishRenderingMap(false); + try { + mapChangeEventManager.onDidFinishRenderingMap(false); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishRenderingMapListener).onDidFinishRenderingMap(false); + try { + mapChangeEventManager.onDidFinishRenderingMap(false); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidBecomeIdleListener() { + mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener); + mapChangeEventManager.onDidBecomeIdle(); + verify(onDidBecomeIdleListener).onDidBecomeIdle(); + mapChangeEventManager.removeOnDidBecomeIdleListener(onDidBecomeIdleListener); + mapChangeEventManager.onDidBecomeIdle(); + verify(onDidBecomeIdleListener).onDidBecomeIdle(); + + mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidBecomeIdleListener).onDidBecomeIdle(); + try { + mapChangeEventManager.onDidBecomeIdle(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidBecomeIdleListener).onDidBecomeIdle(); + try { + mapChangeEventManager.onDidBecomeIdle(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnDidFinishLoadingStyleListener() { + mapChangeEventManager.addOnDidFinishLoadingStyleListener(onDidFinishLoadingStyleListener); + mapChangeEventManager.onDidFinishLoadingStyle(); + verify(onDidFinishLoadingStyleListener).onDidFinishLoadingStyle(); + mapChangeEventManager.removeOnDidFinishLoadingStyleListener(onDidFinishLoadingStyleListener); + mapChangeEventManager.onDidFinishLoadingStyle(); + verify(onDidFinishLoadingStyleListener).onDidFinishLoadingStyle(); + + mapChangeEventManager.addOnDidFinishLoadingStyleListener(onDidFinishLoadingStyleListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidFinishLoadingStyleListener).onDidFinishLoadingStyle(); + try { + mapChangeEventManager.onDidFinishLoadingStyle(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidFinishLoadingStyleListener).onDidFinishLoadingStyle(); + try { + mapChangeEventManager.onDidFinishLoadingStyle(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test + public void testOnSourceChangedListener() { + mapChangeEventManager.addOnSourceChangedListener(onSourceChangedListener); + mapChangeEventManager.onSourceChanged(TEST_STRING); + verify(onSourceChangedListener).onSourceChangedListener(TEST_STRING); + mapChangeEventManager.removeOnSourceChangedListener(onSourceChangedListener); + mapChangeEventManager.onSourceChanged(TEST_STRING); + verify(onSourceChangedListener).onSourceChangedListener(TEST_STRING); + + mapChangeEventManager.addOnSourceChangedListener(onSourceChangedListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onSourceChangedListener).onSourceChangedListener(TEST_STRING); + try { + mapChangeEventManager.onSourceChanged(TEST_STRING); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onSourceChangedListener).onSourceChangedListener(TEST_STRING); + try { + mapChangeEventManager.onSourceChanged(TEST_STRING); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java new file mode 100644 index 000000000..cb097c283 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java @@ -0,0 +1,157 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.PointF; + +import android.support.annotation.Nullable; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Before; +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 { + + @Nullable + private MapGestureDetector mapGestureDetector; + private LatLng latLng; + private PointF pointF; + + @Before + public void setUp() throws Exception { + latLng = new LatLng(); + pointF = new PointF(); + + Projection projection = mock(Projection.class); + when(projection.fromScreenLocation(pointF)).thenReturn(latLng); + mapGestureDetector = new MapGestureDetector(null, + null, projection, null, null, null); + } + + @Test + public void onMapClickListenerTest() throws Exception { + 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 { + 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 { + 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 onMoveListenerTest() throws Exception { + MapboxMap.OnMoveListener listener = mock(MapboxMap.OnMoveListener.class); + MoveGestureDetector detector = mock(MoveGestureDetector.class); + mapGestureDetector.addOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + + mapGestureDetector.removeOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + } + + @Test + public void onRotateListenerTest() throws Exception { + MapboxMap.OnRotateListener listener = mock(MapboxMap.OnRotateListener.class); + RotateGestureDetector detector = mock(RotateGestureDetector.class); + mapGestureDetector.addOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + + mapGestureDetector.removeOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + } + + @Test + public void onScaleListenerTest() throws Exception { + MapboxMap.OnScaleListener listener = mock(MapboxMap.OnScaleListener.class); + StandardScaleGestureDetector detector = mock(StandardScaleGestureDetector.class); + mapGestureDetector.addOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + + mapGestureDetector.removeOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + } + + @Test + public void onShoveListenerTest() throws Exception { + MapboxMap.OnShoveListener listener = mock(MapboxMap.OnShoveListener.class); + ShoveGestureDetector detector = mock(ShoveGestureDetector.class); + mapGestureDetector.addShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + + mapGestureDetector.removeShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + } +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt new file mode 100644 index 000000000..ee8024257 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt @@ -0,0 +1,101 @@ +package com.mapbox.mapboxsdk.maps + +import android.content.Context +import android.content.res.Resources +import android.content.res.TypedArray +import com.mapbox.mapboxsdk.R +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class MapboxMapOptionsAttrsTest { + + @RelaxedMockK + private lateinit var options: MapboxMapOptions + + @RelaxedMockK + private lateinit var typedArray: TypedArray + + @RelaxedMockK + private lateinit var context: Context + + @RelaxedMockK + private lateinit var resources: Resources + + @Before + fun setUp() { + MockKAnnotations.init(this) + every { + context.resources + }.returns(resources) + } + + @Test + fun enabledLocalIdeographFontFamily() { + mockEnableLocalIdeograph(enabled = true) + + val options = MapboxMapOptions.createFromAttributes(options, context, typedArray) + + verify(exactly = 1) { + options.localIdeographFontFamily(any()) + } + } + + @Test + fun localIdeographFontFamily() { + mockEnableLocalIdeograph(enabled = true) + + val font = "foo" + mockLocalIdeographString(font) + + val options = MapboxMapOptions.createFromAttributes(options, context, typedArray) + + verify(exactly = 1) { + options.localIdeographFontFamily(font) + } + } + + @Test + fun localIdeographFontFamilies() { + mockEnableLocalIdeograph(enabled = true) + + val fonts = arrayOf("foo", "bar") + mockLocalIdeographStringArray(fonts) + + val options = MapboxMapOptions.createFromAttributes(options, context, typedArray) + + verify(exactly = 1) { + options.localIdeographFontFamily(*fonts) + } + } + + private fun mockEnableLocalIdeograph(enabled: Boolean) { + every { + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true) + }.returns(enabled) + } + + private fun mockLocalIdeographString(font: String) { + every { + typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily) + }.returns(font) + } + + private fun mockLocalIdeographStringArray(fonts: Array) { + val resId = 9000 + + every { + typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0) + }.returns(resId) + + every { + resources.getStringArray(resId) + }.returns(fonts) + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java new file mode 100644 index 000000000..6978afcf1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -0,0 +1,186 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.Color; +import android.view.Gravity; + +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.Arrays; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@RunWith(RobolectricTestRunner.class) +public class MapboxMapOptionsTest { + + private static final double DELTA = 1e-15; + + @Test + public void testSanity() { + assertNotNull("should not be null", new MapboxMapOptions()); + } + + @Test + public void testDebugEnabled() { + assertFalse(new MapboxMapOptions().getDebugActive()); + assertTrue(new MapboxMapOptions().debugActive(true).getDebugActive()); + assertFalse(new MapboxMapOptions().debugActive(false).getDebugActive()); + } + + @Test + public void testCompassEnabled() { + assertTrue(new MapboxMapOptions().compassEnabled(true).getCompassEnabled()); + assertFalse(new MapboxMapOptions().compassEnabled(false).getCompassEnabled()); + } + + @Test + public void testCompassGravity() { + assertEquals(Gravity.TOP | Gravity.END, new MapboxMapOptions().getCompassGravity()); + assertEquals(Gravity.BOTTOM, new MapboxMapOptions().compassGravity(Gravity.BOTTOM).getCompassGravity()); + assertNotEquals(Gravity.START, new MapboxMapOptions().compassGravity(Gravity.BOTTOM).getCompassGravity()); + } + + @Test + public void testCompassMargins() { + assertTrue(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().compassMargins( + new int[] {0, 1, 2, 3}).getCompassMargins())); + assertFalse(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().compassMargins( + new int[] {0, 0, 0, 0}).getCompassMargins())); + } + + @Test + public void testLogoEnabled() { + assertTrue(new MapboxMapOptions().logoEnabled(true).getLogoEnabled()); + assertFalse(new MapboxMapOptions().logoEnabled(false).getLogoEnabled()); + } + + @Test + public void testLogoGravity() { + assertEquals(Gravity.BOTTOM | Gravity.START, new MapboxMapOptions().getLogoGravity()); + assertEquals(Gravity.BOTTOM, new MapboxMapOptions().logoGravity(Gravity.BOTTOM).getLogoGravity()); + assertNotEquals(Gravity.START, new MapboxMapOptions().logoGravity(Gravity.BOTTOM).getLogoGravity()); + } + + @Test + public void testLogoMargins() { + assertTrue(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().logoMargins( + new int[] {0, 1, 2, 3}).getLogoMargins())); + assertFalse(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().logoMargins( + new int[] {0, 0, 0, 0}).getLogoMargins())); + } + + @Test + public void testAttributionTintColor() { + assertEquals(-1, new MapboxMapOptions().getAttributionTintColor()); + assertEquals(Color.RED, new MapboxMapOptions().attributionTintColor(Color.RED).getAttributionTintColor()); + } + + @Test + public void testAttributionEnabled() { + assertTrue(new MapboxMapOptions().attributionEnabled(true).getAttributionEnabled()); + assertFalse(new MapboxMapOptions().attributionEnabled(false).getAttributionEnabled()); + } + + @Test + public void testAttributionGravity() { + assertEquals(Gravity.BOTTOM | Gravity.START, new MapboxMapOptions().getAttributionGravity()); + assertEquals(Gravity.BOTTOM, new MapboxMapOptions().attributionGravity(Gravity.BOTTOM).getAttributionGravity()); + assertNotEquals(Gravity.START, new MapboxMapOptions().attributionGravity(Gravity.BOTTOM).getAttributionGravity()); + } + + @Test + public void testAttributionMargins() { + assertTrue(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().attributionMargins( + new int[] {0, 1, 2, 3}).getAttributionMargins())); + assertFalse(Arrays.equals(new int[] {0, 1, 2, 3}, new MapboxMapOptions().attributionMargins( + new int[] {0, 0, 0, 0}).getAttributionMargins())); + } + + @Test + public void testMinZoom() { + assertEquals(MapboxConstants.MINIMUM_ZOOM, new MapboxMapOptions().getMinZoomPreference(), DELTA); + assertEquals(5.0f, new MapboxMapOptions().minZoomPreference(5.0f).getMinZoomPreference(), DELTA); + assertNotEquals(2.0f, new MapboxMapOptions().minZoomPreference(5.0f).getMinZoomPreference(), DELTA); + } + + @Test + public void testMaxZoom() { + assertEquals(MapboxConstants.MAXIMUM_ZOOM, new MapboxMapOptions().getMaxZoomPreference(), DELTA); + assertEquals(5.0f, new MapboxMapOptions().maxZoomPreference(5.0f).getMaxZoomPreference(), DELTA); + assertNotEquals(2.0f, new MapboxMapOptions().maxZoomPreference(5.0f).getMaxZoomPreference(), DELTA); + } + + @Test + public void testTiltGesturesEnabled() { + assertTrue(new MapboxMapOptions().getTiltGesturesEnabled()); + assertTrue(new MapboxMapOptions().tiltGesturesEnabled(true).getTiltGesturesEnabled()); + assertFalse(new MapboxMapOptions().tiltGesturesEnabled(false).getTiltGesturesEnabled()); + } + + @Test + public void testScrollGesturesEnabled() { + assertTrue(new MapboxMapOptions().getScrollGesturesEnabled()); + assertTrue(new MapboxMapOptions().scrollGesturesEnabled(true).getScrollGesturesEnabled()); + assertFalse(new MapboxMapOptions().scrollGesturesEnabled(false).getScrollGesturesEnabled()); + } + + @Test + public void testZoomGesturesEnabled() { + assertTrue(new MapboxMapOptions().getZoomGesturesEnabled()); + assertTrue(new MapboxMapOptions().zoomGesturesEnabled(true).getZoomGesturesEnabled()); + assertFalse(new MapboxMapOptions().zoomGesturesEnabled(false).getZoomGesturesEnabled()); + } + + @Test + public void testRotateGesturesEnabled() { + assertTrue(new MapboxMapOptions().getRotateGesturesEnabled()); + assertTrue(new MapboxMapOptions().rotateGesturesEnabled(true).getRotateGesturesEnabled()); + assertFalse(new MapboxMapOptions().rotateGesturesEnabled(false).getRotateGesturesEnabled()); + } + + @Test + public void testCamera() { + CameraPosition position = new CameraPosition.Builder().build(); + assertEquals(new CameraPosition.Builder(position).build(), new MapboxMapOptions().camera(position).getCamera()); + assertNotEquals(new CameraPosition.Builder().target(new LatLng(1, 1)), new MapboxMapOptions().camera(position)); + assertNull(new MapboxMapOptions().getCamera()); + } + + @Test + public void testPrefetchesTiles() { + // Default value + assertTrue(new MapboxMapOptions().getPrefetchesTiles()); + + // Check mutations + assertTrue(new MapboxMapOptions().setPrefetchesTiles(true).getPrefetchesTiles()); + assertFalse(new MapboxMapOptions().setPrefetchesTiles(false).getPrefetchesTiles()); + } + + @Test + public void testCrossSourceCollisions() { + // Default value + assertTrue(new MapboxMapOptions().getCrossSourceCollisions()); + + // check mutations + assertTrue(new MapboxMapOptions().crossSourceCollisions(true).getCrossSourceCollisions()); + assertFalse(new MapboxMapOptions().crossSourceCollisions(false).getCrossSourceCollisions()); + } + + @Test + public void testLocalIdeographFontFamily_enabledByDefault() { + MapboxMapOptions options = MapboxMapOptions.createFromAttributes(RuntimeEnvironment.application, null); + assertEquals(MapboxConstants.DEFAULT_FONT, options.getLocalIdeographFontFamily()); + } +} + diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt new file mode 100644 index 000000000..deb5f603c --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -0,0 +1,202 @@ +package com.mapbox.mapboxsdk.maps + +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory +import com.mapbox.mapboxsdk.constants.MapboxConstants +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.geometry.LatLngBounds +import com.mapbox.mapboxsdk.style.layers.TransitionOptions +import io.mockk.* +import junit.framework.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class MapboxMapTest { + + private lateinit var mapboxMap: MapboxMap + + private lateinit var nativeMapView: NativeMap + + private lateinit var transform: Transform + + private lateinit var cameraChangeDispatcher: CameraChangeDispatcher + + private lateinit var developerAnimationListener: MapboxMap.OnDeveloperAnimationListener + + @Before + fun setup() { + cameraChangeDispatcher = spyk() + developerAnimationListener = mockk(relaxed = true) + nativeMapView = mockk(relaxed = true) + transform = mockk(relaxed = true) + mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher, listOf(developerAnimationListener)) + every { nativeMapView.isDestroyed } returns false + every { nativeMapView.nativePtr } returns 5 + mapboxMap.injectLocationComponent(spyk()) + mapboxMap.setStyle(Style.MAPBOX_STREETS) + mapboxMap.onFinishLoadingStyle() + } + + @Test + fun testTransitionOptions() { + val expected = TransitionOptions(100, 200) + mapboxMap.style?.transition = expected + verify { nativeMapView.transitionOptions = expected } + } + + @Test + fun testMoveCamera() { + val callback = mockk() + val target = LatLng(1.0, 2.0) + val expected = CameraPosition.Builder().target(target).build() + val update = CameraUpdateFactory.newCameraPosition(expected) + mapboxMap.moveCamera(update, callback) + verify { transform.moveCamera(mapboxMap, update, callback) } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testEaseCamera() { + val callback = mockk() + val target = LatLng(1.0, 2.0) + val expected = CameraPosition.Builder().target(target).build() + val update = CameraUpdateFactory.newCameraPosition(expected) + mapboxMap.easeCamera(update, callback) + verify { transform.easeCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, true, callback) } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testAnimateCamera() { + val callback = mockk() + val target = LatLng(1.0, 2.0) + val expected = CameraPosition.Builder().target(target).build() + val update = CameraUpdateFactory.newCameraPosition(expected) + mapboxMap.animateCamera(update, callback) + verify { transform.animateCamera(mapboxMap, update, MapboxConstants.ANIMATION_DURATION, callback) } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testScrollBy() { + mapboxMap.scrollBy(100f, 200f) + verify { nativeMapView.moveBy(100.0, 200.0, 0) } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testResetNorth() { + mapboxMap.resetNorth() + verify { transform.resetNorth() } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testFocalBearing() { + mapboxMap.setFocalBearing(35.0, 100f, 200f, 1000) + verify { transform.setBearing(35.0, 100f, 200f, 1000) } + verify { developerAnimationListener.onDeveloperAnimationStarted() } + } + + @Test + fun testMinZoom() { + mapboxMap.setMinZoomPreference(10.0) + verify { transform.minZoom = 10.0 } + } + + @Test + fun testMaxZoom() { + mapboxMap.setMaxZoomPreference(10.0) + verify { transform.maxZoom = 10.0 } + } + + @Test + fun testFpsListener() { + val fpsChangedListener = mockk() + mapboxMap.onFpsChangedListener = fpsChangedListener + assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener) + } + + @Test + fun testTilePrefetch() { + mapboxMap.prefetchesTiles = true + verify { nativeMapView.prefetchTiles = true } + } + + @Test + fun testCameraForLatLngBounds() { + val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() + mapboxMap.setLatLngBoundsForCameraTarget(bounds) + verify { nativeMapView.setLatLngBounds(bounds) } + } + + @Test(expected = IllegalArgumentException::class) + fun testAnimateCameraChecksDurationPositive() { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test(expected = IllegalArgumentException::class) + fun testEaseCameraChecksDurationPositive() { + mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test + fun testGetNativeMapPtr() { + assertEquals(5, mapboxMap.nativeMapPtr) + } + + @Test + fun testNativeMapIsNotCalledOnStateSave() { + clearMocks(nativeMapView) + mapboxMap.onSaveInstanceState(mockk(relaxed = true)) + verify { nativeMapView wasNot Called } + } + + @Test + fun testCameraChangeDispatcherCleared() { + mapboxMap.onDestroy() + verify { cameraChangeDispatcher.onDestroy() } + } + + @Test + fun testStyleClearedOnDestroy() { + val style = mockk + + + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml new file mode 100644 index 000000000..d36c741c5 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -0,0 +1,94 @@ + + + Concurrent Open InfoWindows + Deselect Markers On Tap + Reset + Toggle icon overlap + Filter layer + Change location + Accelerate/Decelerate interpolator + Bounce interpolator + Anticipate/Overshoot interpolator + PathInterpolator interpolator + Toggle Symbol Layer Visibility + Move + Ease + Animate + Open dialog + Download region + List regions + Remove polylines + Change visibility + Change alpha + Change points + Change color + Change holes + Change width + "Click the map to calculate the distance" + Move the map by x/y pixels + Open navigation drawer + Close navigation drawer + X: %1$d + Y: %1$d + Animate to new position + Chelsea + Stamford Bridge + Arsenal + Emirates Stadium + Zoom: %.2f + ViewCache size %d + Latitude + -180 + Longitude + Zoom + 18 + Bearing + 0 + Tilt + No Results + Change intensity + Change Anchor + Amount of markers + Update layer (invalidate) + Red + Green + Blue + Add an exponential zoom function + Add an interval zoom function + Add a categorical source function + Add an exponential source function + Add an identity source function + Add an interval source function + Add a composite, categorical function + Add a composite, exponential function + Add a composite, interval function + Bangalore + List all layers in the style + List all sources in the style + Color the water + Set background opacity + Set road symbol placement to Point + Set layer visibility to false + Add a parks layer + Add a dynamic GeoJSON source + Remove buildings layer + Add a terrain layer + Add a satellite layer + Change the water color on zoom + Custom tiles + Apply filtered fill + Apply filtered line + Apply numeric fill filter + Bring water to front + Toggle text size + Toggle text field contents + Toggle text font + Zoom in + Zoom out + Zoom by 2 + Zoom to point + Zoom to 4 + Restrict almost worldview + Restrict across IDL + Reset bounds + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml new file mode 100644 index 000000000..ad9f88a46 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml @@ -0,0 +1,15 @@ + + + + 10 + 100 + 500 + 1000 + 10000 + + + foo + monospace + bar + + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml new file mode 100644 index 000000000..94c805f35 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml @@ -0,0 +1,21 @@ + + + category + _Basic + Annotation + Camera + Custom Layer + Fragment + Image Generator + Info Window + Map Layout + Offline + Styling + Features + Storage + Texture View + Location + _Integration + Telemetry + Turf + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml new file mode 100644 index 000000000..88524d44e --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml @@ -0,0 +1,13 @@ + + + #52A1D8 + #3887BE + #E55E5E + #F9F9F9 + #56B881 + + #D50000 + #2962FF + #1B5E20 + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml new file mode 100644 index 000000000..7f018a43f --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -0,0 +1,89 @@ + + + Overlay a custom native layer on the map + Learn how to create a custom InfoWindow + CameraPosition capabilities + Showcase MapFragment + Showcase SupportMapFragment + Showcase using a Map Fragment with a fragment backstack + Activity with multiple maps on screen + Add marker to map on long press + Different types of zoom methods + Configure a max and min zoomlevel + Learn how to handle the InfoWindow + Add Markers In Bulk to a Map + Showcase the different animation types + Center the camera around a bounds + Update position and icon + Map Padding example + Debug Mode + Offline Map example + Download an offline region. + Update metadata example + Delete region example + Change resources cache path example + Animate the position change of a symbol layer + Add a polyline to a map + Add a polygon to a map + Scroll with pixels in x,y direction + Example to make a snapshot of the map + 2 maps in a view hierarchy + Learn how to create a dynamic custom InfoWindow + Use SupportMapFragments in a ViewPager + Adopt the map style on the fly + Show a gradient line layer from a geojson source + Use functions to change the map appearance + Manipulate symbols at runtime + Use a custom sprite in a Symbol Layer + Use GeoJson sources and dynamic layers to cluster information + Use realtime GeoJSON data streams to move a symbol on your map + Shows how to print a map + Query rendered feature properties on click + Count all rendered features in box + Count all rendered symbols in box + Highlight buildings in box + Query source for features + Shows a simple map + Logs map change events to Logcat + Changes visibility of map and view parent + Change Symbol icon when zoom levels changes + Use a local file as the style + Display a map inside a dialog fragment + Show bus stops and route in Singapore + Transform urls on the fly + Control the cache management with FileSource API + Limit viewport to Iceland + Shows how to add 3D extruded shapes + Shows how to show 3D extruded buildings + Shows how to animate georeferenced images + Show 2 MapView on screen with a bottom sheet + Show a static bitmap taken with the MapSnapshotter + Show how to reuse a MapSnapshotter instance + Show how to add a marker to a Snapshot + Show how to load a local style with a Snapshot + Use Android SDK Animators to animate camera position changes + Use Android SDK Views as symbols + Use TextureView to render the map + Resize a map rendered on a TextureView + Animate a map rendered on a TextureView + Enable a transparent surface on TextureView + Blend an overlay on a map + Example Custom Geometry Source + Load a map without providing a style URI or JSON + Suzhou using Droid Sans for Chinese glyphs + Example raster-dem source and hillshade layer + Use HeatmapLayer to visualise earthquakes + Manipulate gestures detector\'s settings + Merge external offline database + Click to add a marker, long-click to drag + Change map\'s style while location is displayed + Showcases location render and tracking modes + Uses LocationComponent in a Fragment + Force location updates and don\'t rely on the engine + Use LocationComponentActivationOptions to set options + Show multiple TextureView MapViews as recyclerView items + Show multiple GLSurfaceView MapViews as recyclerView items + Show a MapView inside a viewpager inside a recyclerView + Show the use PerformanceEvent for performance measurements + Use TurfTransformation#circle() to show a Cirlce expressed in physical units + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml new file mode 100644 index 000000000..9d3418343 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml @@ -0,0 +1,10 @@ + + + 16dp + 10dp + 96dp + 256dp + 32dp + 0dp + 240dp + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml new file mode 100644 index 000000000..6701032d9 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml new file mode 100644 index 000000000..45048f8b0 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Mapbox Android SDK TestApp + fps30 + fps60 + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml new file mode 100644 index 000000000..8d7da603f --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml new file mode 100644 index 000000000..90baaed28 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -0,0 +1,89 @@ + + + Support Map Fragment + Map Fragment + Backstack Map Fragment + Multiple Maps on Screen + Add Markers In Bulk + Animated SymbolLayer + Dynamic Marker + Polyline + Polygon + Press Map For Marker + Zoom function with SymbolLayer + Standard InfoWindow + Custom InfoWindow + Custom Dynamic InfoWindow + Animation Types + Zoom Methods + LatLngBounds Method + CameraPosition Method + Scroll By Method + Double Map Activity + Snapshot Activity + Custom Layer + Map Padding + Debug Mode + Offline Map + Update metadata Map + Delete region + Change resources cache path + Min/Max Zoom + ViewPager + Runtime Style + Gradient line layer + Data Driven Style + Circle layer + Local Style file + GeoJson Clustering + Add live realtime data + Print a map + Query feature properties + Count features in box + Count symbols in box + Highlight features in box + Query source features + Symbols + Add Custom Sprite + Simple Map + Map Change Events + Visibility Map + Dialog with map + Url transform + Cache management + Restrict camera to a bounds + Fill extrusions + Building layer + Animated Image Source + Bottom sheet + Map Snapshotter + Map Snapshotter Reuse + Map Snapshot with marker + Map Snapshot with local style + Animator animation + SymbolGenerator + TextureView debug + TextureView resize + TextureView animation + TextureView transparent background + Map overlay + Grid Source + No Style URI/JSON + Local CJK glyph generation + Hillshade + Heatmap layer + Gestures detector + Offline DB merge + Draggable marker + Simple Location Activity + Location Modes Activity + Location Fragment + Manual Location updates + Build Location Activation + RecyclerView TextureView + RecyclerView GLSurfaceView + Nested ViewPager + Performance Measurement + Physical Unit Circle + Download region + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..b7b2cb225 --- /dev/null +++ b/README.md @@ -0,0 +1,118 @@ +# [Mapbox Maps SDK for Android](https://www.mapbox.com/android-sdk/) + +[![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) + +[![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://docs.mapbox.com/android/maps/overview/) + +The Mapbox Maps SDK for Android is a library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps onto Android devices. + +## Getting Started + +This particular README is for people who are interested in working on and improving the Maps SDK for Android. If you're looking for more general information and instructions on the Maps SDK: + +Visit [https://docs.mapbox.com/android/maps/overview](https://docs.mapbox.com/android/maps/overview/) to see current documentation on the Maps SDK for Android. + +Visit [https://docs.mapbox.com/android/api/map-sdk](https://docs.mapbox.com/android/api/map-sdk/) to view the Maps SDK's current API reference Javadoc files. + +See [the Mapbox website's Android install flow](https://www.mapbox.com/install/android/) to install and use the Mapbox Maps SDK for Android in an application. + +### Setup environment + +These instructions are for developers interested in making code-level contributions to the SDK itself. If you instead want to use the SDK in your app, see above. + +#### Getting the source + +Clone the git repository + +```bash +git clone git@github.com:mapbox/mapbox-gl-native.git && cd mapbox-gl-native +``` + +#### Installing dependencies + +These dependencies are required for all operating systems and all platform targets. + +- Latest stable [Android Studio](https://developer.android.com/studio/index.html) +- Update the Mapbox Maps SDK for Android with the latest + - Android SDK Build-Tools + - Android Platform-Tools + - Android SDK Tools + - CMake + - NDK + - LLDB +- Modern C++ compiler that supports `-std=c++14`\* + - clang++ 3.5 or later or + - g++-4.9 or later +- [Node.js](https://nodejs.org/) + - make sure [npm](https://www.npmjs.com) is installed as well +- [ccache](https://ccache.samba.org/) (optional) + +**Note**: We partially support C++14 because GCC 4.9 does not fully implement the +final draft of the C++14 standard. More information in [DEVELOPING.md](../../DEVELOPING.md). + +**Note**: On macOS you can install clang with installing the [Apple command line developer tools](https://developer.apple.com/download/). + +### Opening the project + +#### macOS + +Execute the following command in this repository's root folder to generate the required build files and open the project with Android Studio: + +``` +make aproj +``` + +#### linux + +run `make android-configuration` in the root folder of the project and open the Android Studio project in `/platform/android`. + +If you are using Arch Linux, install [ncurses5-compat-libs](https://aur.archlinux.org/packages/ncurses5-compat-libs). + +### Project configuration + +#### Setup Checkstyle + +Mapbox uses specific IDE settings related to code and check style. +See [checkstyle guide](https://github.com/mapbox/mapbox-gl-native/wiki/Setting-up-Mapbox-checkstyle) for configuration details. + +#### Resolving duplicate file entries +With buck build support, Android Studio can complain about duplicate source files. To remove this warning, open `MapboxGLAndroidSDK.iml` find the list of `excludeFolder` entries and add `` line. + +##### Setting Mapbox Access Token + +_The test application (used for development purposes) uses Mapbox vector tiles, which require a Mapbox account and API access token. Obtain a free access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._ + +With the first gradle invocation, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml`. If the environment variable wasn't set, you can edit `developer-config.xml` manually and add your access token to the `mapbox_access_token` resource. + +### Running project + +Run the configuration for the `MapboxGLAndroidSDKTestApp` module and select a device or emulator to deploy on. Based on the selected device, the c++ code will be compiled for the related processor architecture. You can see the project compiling in the `View > Tool Windows > Gradle Console`. + +More information about building and distributing this project in [DISTRIBUTE.md](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/DISTRIBUTE.md). + +### Additional resources + +#### Using the SDK snapshot + +Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example, the `7.3.0-SNAPSHOT` would look like: + +```java +// Mapbox SDK dependency +implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:7.3.0-SNAPSHOT' +``` + +You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies: +``` +allprojects { + repositories { + jcenter() + maven { url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/' } + } +} +``` + + +#### Symbolicating native crashes + +When hitting native crashes you can use ndk-stack to symbolicate crashes. +More information in [this](https://github.com/mapbox/mapbox-gl-native/wiki/Getting-line-numbers-from-an-Android-crash-with-ndk-stack) guide. diff --git a/TESTS.md b/TESTS.md new file mode 100644 index 000000000..f0bdeb2dc --- /dev/null +++ b/TESTS.md @@ -0,0 +1,117 @@ +# Mapbox GL Test App + +## Testing + +### Running Espresso tests on a device + +This test project comes with all the required Android Testing Support Library dependencies +in the Gradle file. Tests are under the `app/src/androidTest` folder. + +Note that before running your tests, you might want to turn off animations on your test device. +It's a known issue that leaving system animations turned on in a test device +(window animation scale, transition animation scale, animator duration scale) +might cause unexpected results, or may lead tests to fail. + +To create a new run configuration: +* Click on Run -> Edit Configurations... +* Click on the plus sign and then on "Android Tests" +* Give a name to the configuration, e.g. `TestAppTests` +* Choose the `MapboxGLAndroidSDKTestApp` module +* Choose `android.support.test.runner.AndroidJUnitRunner` as the instrumentation runner +* Click OK to save the new configuration + +You can now run this configuration from the main toolbar dropdown menu. + +### Running Espresso tests on Firebase within AS + +Tests are under the `app/src/androidTest` folder. + +1) _Sign In_ with your Google account. + +![Firebase Tests AS 1][1] + +2) Or _Add Account_ if you want to sign in with a different account. + +![Firebase Tests AS 2][2] + +3) Select the test configuration you want to run and click _Play_ button. + +4) Click on _Cloud Testing_ tab. You need to create a project in Firebase and define a _Matrix configuration_ previously (see +[Firebase Test Lab for Android guide](https://firebase.google.com/docs/test-lab/overview)). Select your template (e.g. _Nexus 5 (3)_). + +5) Select your _Cloud project_ (e.g. _android-gl-native (android-gl-native)_). + +![Firebase Tests AS 3-5][3] + +6) Click on _OK_ button to run the tests. + +![Firebase Tests AS 6][4] + +7) When tests finish the results will appear within AS. + +![Firebase Tests AS 7][5] + +### Running Espresso tests on AWS Device Farm + +On a terminal, within `mapbox-gl-native/android/java`, +run the tests (`cC` stands for `connectedCheck`): + +``` +$ ./gradlew -Pmapbox.abis=all cC -p MapboxGLAndroidSDKTestApp +``` + +Then: +* Go to your AWS Console and choose Device Farm. +* Create a new project, e.g. `MapboxGLAndroidSDKTestApp` +* On step 1, upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-unaligned.apk` +* On step 2, choose Instrumentation, test filter is `com.mapbox.mapboxgl.testapp.MainActivityTest` and upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest-unaligned.apk` +* On step 3, choose a device pool. E.g. Top Devices +* On step 4, customize your device state (if needed) +* Finally, confirm the configuration and run the tests. + +On Step 2, you can also separate by commas different classes: `com.mapbox.mapboxgl.testapp.MainActivityTest,com.mapbox.mapboxgl.testapp.MainActivityScreenTest` + +If you have no tests for your app, or want to test some random user behavior, +you can just choose "Built-in: Fuzz" in step 2. + +### Running pure JUnit tests + +These tests run on a local JVM on your development machine and they are extremely fast to run +(as compared to Espresso). These tests are located under `src/test/java`. To run them you switch +to the Unit Tests build variant, then right click the corresponding test class or method +and select "Run ...". + +You can also have a run configuration: +* Click on Run -> Edit Configurations... +* Click on "Junit Tests" +* Give a name to the configuration, e.g. `JUnit tests` +* As "Test Kind", choose "All in directory" +* As folder, choose the following folder: `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/src/test/java` +* Click OK to save the new configuration + +You can also run the tests from the command line with: + +``` +$ ./gradlew -Pmapbox.abis=none test -p MapboxGLAndroidSDKTestApp +``` + +### Running the UI/Application Exerciser Monkey + +Similar to the "Built-in: Fuzz" test mentioned above, Android provides +[Monkey](http://developer.android.com/tools/help/monkey.html), +"a program that runs on your emulator or device and generates pseudo-random streams of user events +such as clicks, touches, or gestures, as well as a number of system-level events." + +To exercise Monkey on the test app, install the package on the device (e.g. via Android Studio) +and then: + +``` +$ adb shell monkey -p com.mapbox.mapboxgl.testapp -v 500 +``` + + +[1]: ./art/tests/FirebaseTestsAS_1.png +[2]: ./art/tests/FirebaseTestsAS_2.png +[3]: ./art/tests/FirebaseTestsAS_3-5.png +[4]: ./art/tests/FirebaseTestsAS_6.png +[5]: ./art/tests/FirebaseTestsAS_7.png diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..c74912fb6 --- /dev/null +++ b/build.gradle @@ -0,0 +1,34 @@ +buildscript { + apply from: "${rootDir}/gradle/dependencies.gradle" + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath dependenciesList.licensesPlugin + classpath dependenciesList.kotlinPlugin + classpath dependenciesList.bintrayPlugin + classpath dependenciesList.artifactoryPlugin + classpath dependenciesList.androidPublishPlugin + classpath dependenciesList.jacocoPlugin + } +} + +allprojects { + repositories { + mavenCentral() + google() + jcenter() + // For publishing Maps SDK files to Bintray + maven { url 'https://mapbox.bintray.com/mapbox' } + // Snapshot repository + // maven { url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/' } + } + apply from: "${rootDir}/gradle/ktlint.gradle" +} + +subprojects { + apply from: "${rootDir}/gradle/dependencies.gradle" +} \ No newline at end of file diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 000000000..c73ada156 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/android-nitpick.gradle b/gradle/android-nitpick.gradle new file mode 100644 index 000000000..6db351967 --- /dev/null +++ b/gradle/android-nitpick.gradle @@ -0,0 +1,66 @@ +apply from: "${rootDir}/gradle/dependencies.gradle" + +def MAPBOX_JAVA_DIR = 'mapbox-java' +def MAPBOX_JAVA_TAG_PREFIX = 'v' + +def MAPBOX_TELEMETRY_DIR = 'mapbox-events-android' +def MAPBOX_TELEMETRY_TAG_PREFIX = 'telem-' +def MAPBOX_CORE_TAG_PREFIX = '-core-' + +def MAPBOX_GESTURES_DIR = 'mapbox-gestures-android' +def MAPBOX_GESTURES_TAG_PREFIX = 'v' + +task androidNitpick { + doLast { + println "Running android nitpick script" + + println "Verify vendor submodule pins" + verifyVendorSubmodulePin(MAPBOX_JAVA_DIR, MAPBOX_JAVA_TAG_PREFIX, versions.mapboxServices) + verifyVendorSubmodulePin(MAPBOX_TELEMETRY_DIR, MAPBOX_TELEMETRY_TAG_PREFIX, + versions.mapboxTelemetry + MAPBOX_CORE_TAG_PREFIX + versions.mapboxCore) + verifyVendorSubmodulePin(MAPBOX_GESTURES_DIR, MAPBOX_GESTURES_TAG_PREFIX, versions.mapboxGestures) + + verifyLicenseGeneration() + } +} + +private def verifyVendorSubmodulePin(def dir, def prefix, def version) { + println "Verify vendor submodule pin: ${dir} (${prefix + version})" + exec { + workingDir = "${rootDir}/vendor/${dir}" + commandLine "git", "fetch", "-t" + } + + def output = new ByteArrayOutputStream() + exec { + workingDir = "${rootDir}/vendor/${dir}" + commandLine "git", "rev-list", "-n", "1", "tags/${prefix + version}" + standardOutput = output + } + def expectedCommit = output.toString().trim() + output.reset() + + exec { + workingDir = "${rootDir}/vendor/${dir}" + commandLine "git", "rev-parse", "HEAD" + standardOutput = output + } + def actualCommit = output.toString().trim() + + if (actualCommit != expectedCommit) { + throw new IllegalStateException("${dir} vendor repository is not checked out on the consumed binary's tag.\n" + + "Expected commit: " + expectedCommit + "(${prefix + version} tag).\n" + + "Actual commit: " + actualCommit + ".\n" + + "If you've updated the version in the dependencies.gradle file, make sure to bump the submodule pin in the platform/android/vendor/ directory to match the release tag.\n" + + "If you've bumped the pin, make sure to verify the version tag prefix in the android-nitpick.gradle file.") + } + output.close() +} + +private def verifyLicenseGeneration() { + println "Verify license generation with git diff..." + exec { + workingDir = "${rootDir}" + commandLine "python", "scripts/validate-license.py" + } +} \ No newline at end of file diff --git a/gradle/artifact-settings.gradle b/gradle/artifact-settings.gradle new file mode 100644 index 000000000..acf29eeb8 --- /dev/null +++ b/gradle/artifact-settings.gradle @@ -0,0 +1,21 @@ +ext { + mapboxArtifactGroupId = 'com.mapbox.mapboxsdk' + mapboxArtifactId = 'mapbox-android-sdk' + mapboxArtifactTitle = 'Mapbox Maps SDK for Android' + mapboxArtifactDescription = 'Mapbox Maps SDK for Android' + mapboxDeveloperName = 'Mapbox' + mapboxDeveloperId = 'mapbox' + mapboxArtifactUrl = 'https://github.com/mapbox/mapbox-gl-native' + mapboxArtifactVcsUrl = 'https://github.com/mapbox/mapbox-gl-native.git' + mapboxArtifactScmUrl = 'scm:git@github.com:mapbox/mapbox-gl-native.git' + mapboxArtifactLicenseName = 'BSD' + mapboxArtifactLicenseUrl = 'https://opensource.org/licenses/BSD-2-Clause' + versionName = project.hasProperty('VERSION_NAME') ? project.property('VERSION_NAME') : System.getenv('VERSION_NAME') + + mapboxBintrayUserOrg = 'mapbox' + mapboxBintrayRepoName = 'mapbox' + mapboxBintrayPackageName = 'com.mapbox.mapboxsdk:mapbox-android-sdk' + mapboxBintrayUser = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER') + mapboxBintrayApiKey = project.hasProperty('BINTRAY_API_KEY') ? project.property('BINTRAY_API_KEY') : System.getenv('BINTRAY_API_KEY') + mapboxGpgPassphrase = project.hasProperty('GPG_PASSPHRASE') ? project.property('GPG_PASSPHRASE') : System.getenv('GPG_PASSPHRASE') +} diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle new file mode 100644 index 000000000..c1c489472 --- /dev/null +++ b/gradle/dependencies.gradle @@ -0,0 +1,90 @@ +ext { + + androidVersions = [ + minSdkVersion : 14, + targetSdkVersion : 28, + compileSdkVersion: 28, + ] + + versions = [ + mapboxServices : '4.9.0-alpha.1', + mapboxTelemetry : '4.5.1', + mapboxCore : '1.3.0', + mapboxGestures : '0.5.1', + mapboxAccounts : '0.2.0', + supportLib : '28.0.0', + constraintLayout: '1.1.2', + uiAutomator : '2.1.3', + espresso : '3.0.2', + testRunner : '1.0.2', + leakCanary : '1.6.3', + junit : '4.12', + mockito : '3.0.0', + mockk : '1.9.3', + robolectric : '4.3', + timber : '4.7.1', + okhttp : '3.12.3', + kotlin : '1.3.41', + licenses : '0.8.5', + bintray : '1.8.4', + artifactory : '4.9.3', + androidPublish : '3.6.2', + lint : '26.4.2', + gms : '16.0.0', + soLoader : '0.6.1', + jacoco : '0.8.4', + appcenter : '1.4', + ktlint : '0.34.0', + commonsIO : '2.6' + ] + + dependenciesList = [ + mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-sdk-geojson:${versions.mapboxServices}", + mapboxAndroidTelemetry : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${versions.mapboxTelemetry}", + mapboxAndroidGestures : "com.mapbox.mapboxsdk:mapbox-android-gestures:${versions.mapboxGestures}", + mapboxAndroidAccounts : "com.mapbox.mapboxsdk:mapbox-android-accounts:${versions.mapboxAccounts}", + mapboxJavaTurf : "com.mapbox.mapboxsdk:mapbox-sdk-turf:${versions.mapboxServices}", + + junit : "junit:junit:${versions.junit}", + mockito : "org.mockito:mockito-core:${versions.mockito}", + mockk : "io.mockk:mockk:${versions.mockk}", + robolectric : "org.robolectric:robolectric:${versions.robolectric}", + + testRunner : "com.android.support.test:runner:${versions.testRunner}", + testRules : "com.android.support.test:rules:${versions.testRunner}", + testEspressoCore : "com.android.support.test.espresso:espresso-core:${versions.espresso}", + testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${versions.espresso}", + testEspressoContrib : "com.android.support.test.espresso:espresso-contrib:${versions.espresso}", + testUiAutomator : "com.android.support.test.uiautomator:uiautomator-v18:${versions.uiAutomator}", + appCenter : "com.microsoft.appcenter:espresso-test-extension:${versions.appcenter}", + commonsIO : "commons-io:commons-io:${versions.commonsIO}", + supportAnnotations : "com.android.support:support-annotations:${versions.supportLib}", + supportAppcompatV7 : "com.android.support:appcompat-v7:${versions.supportLib}", + supportFragmentV4 : "com.android.support:support-fragment:${versions.supportLib}", + supportUtilV4 : "com.android.support:support-core-utils:${versions.supportLib}", + supportDesign : "com.android.support:design:${versions.supportLib}", + supportRecyclerView : "com.android.support:recyclerview-v7:${versions.supportLib}", + supportConstraintLayout: "com.android.support.constraint:constraint-layout:${versions.constraintLayout}", + + gmsLocation : "com.google.android.gms:play-services-location:${versions.gms}", + timber : "com.jakewharton.timber:timber:${versions.timber}", + okhttp3 : "com.squareup.okhttp3:okhttp:${versions.okhttp}", + leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${versions.leakCanary}", + leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${versions.leakCanary}", + soLoader : "com.facebook.soloader:soloader:${versions.soLoader}", + + kotlinLib : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}", + kotlinPlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}", + licensesPlugin : "com.jaredsburrows:gradle-license-plugin:${versions.licenses}", + bintrayPlugin : "com.jfrog.bintray.gradle:gradle-bintray-plugin:${versions.bintray}", + artifactoryPlugin : "org.jfrog.buildinfo:build-info-extractor-gradle:${versions.artifactory}", + androidPublishPlugin : "digital.wup:android-maven-publish:${versions.androidPublish}", + jacocoPlugin : "org.jacoco:org.jacoco.core:${versions.jacoco}", + + lint : "com.android.tools.lint:lint:${versions.lint}", + lintApi : "com.android.tools.lint:lint-api:${versions.lint}", + lintChecks : "com.android.tools.lint:lint-checks:${versions.lint}", + lintTests : "com.android.tools.lint:lint-tests:${versions.lint}", + ktlint : "com.pinterest:ktlint:${versions.ktlint}" + ] +} diff --git a/gradle/gradle-bintray.gradle b/gradle/gradle-bintray.gradle new file mode 100644 index 000000000..e8ace7359 --- /dev/null +++ b/gradle/gradle-bintray.gradle @@ -0,0 +1,117 @@ +apply plugin: 'digital.wup.android-maven-publish' +apply plugin: 'maven-publish' +apply plugin: 'com.jfrog.bintray' +apply plugin: 'com.jfrog.artifactory' +apply from: file('../gradle/artifact-settings.gradle') + +version = project.ext.versionName +group = project.ext.mapboxArtifactGroupId + +publishing { + publications { + MapboxMapsSdkPublication(MavenPublication) { + from components.android + groupId this.group + artifactId project.ext.mapboxArtifactId + version this.version + + afterEvaluate { + artifact(androidSourcesJar) + artifact(androidJavadocsJar) + } + + pom.withXml { + final mainNode = asNode() + mainNode.appendNode('name', project.ext.mapboxArtifactTitle) + mainNode.appendNode('description', project.ext.mapboxArtifactTitle) + mainNode.appendNode('url', project.ext.mapboxArtifactUrl) + + final licenseNode = mainNode.appendNode('licenses').appendNode('license') + licenseNode.appendNode('name', project.ext.mapboxArtifactLicenseName) + licenseNode.appendNode('url', project.ext.mapboxArtifactLicenseUrl) + licenseNode.appendNode('distribution', "repo") + + final developerNode = mainNode.appendNode('developers').appendNode('developer') + developerNode.appendNode('id', project.ext.mapboxDeveloperId) + developerNode.appendNode('name', project.ext.mapboxDeveloperName) + + final scmNode = mainNode.appendNode("scm") + scmNode.appendNode("connection", project.ext.mapboxArtifactScmUrl) + scmNode.appendNode("developerConnection", project.ext.mapboxArtifactScmUrl) + scmNode.appendNode("url", project.ext.mapboxArtifactUrl) + } + } + } +} + +bintray { + user = mapboxBintrayUser + key = mapboxBintrayApiKey + publications('MapboxMapsSdkPublication') + pkg { + repo = project.ext.mapboxBintrayRepoName + name = project.ext.mapboxBintrayPackageName + userOrg = project.ext.mapboxBintrayUserOrg + licenses = [project.ext.mapboxArtifactLicenseName] + vcsUrl = project.ext.mapboxArtifactVcsUrl + publish = false + version { + name = project.ext.versionName + desc = project.ext.mapboxArtifactDescription + released = new Date() + gpg { + sign = true + passphrase = mapboxGpgPassphrase + } + mavenCentralSync { + sync = false + } + } + } +} + +artifactory { + contextUrl = 'http://oss.jfrog.org' + publish { + repository { + repoKey = 'oss-snapshot-local' + username = mapboxBintrayUser + password = mapboxBintrayApiKey + } + defaults { + publications('MapboxMapsSdkPublication') + } + } +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.sourceFiles + classpath = files(android.bootClasspath) + failOnError = false +} + +task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task androidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.sourceFiles +} + +tasks.withType(Javadoc) { + options.addStringOption('encoding', 'UTF-8') + options.addStringOption('docencoding', 'UTF-8') + options.addStringOption('charset', 'UTF-8') +} + +afterEvaluate { project -> + android.libraryVariants.all { variant -> + tasks.androidJavadocs.doFirst { + classpath += files(variant.javaCompile.classpath.files) + } + } +} + + diff --git a/gradle/gradle-checkstyle.gradle b/gradle/gradle-checkstyle.gradle new file mode 100644 index 000000000..8eb4baa85 --- /dev/null +++ b/gradle/gradle-checkstyle.gradle @@ -0,0 +1,26 @@ +apply plugin: 'checkstyle' + +checkstyle { + toolVersion = "7.1.1" // 7.3 + configFile = "../checkstyle.xml" as File +} + +task checkstyle(type: Checkstyle) { + description 'Checks if the code adheres to coding standards' + group 'verification' + configFile file("../checkstyle.xml") + source 'src' + include '**/*.java' + exclude '**/gen/**' + exclude '**/style/*LayerTest.java' + exclude '**/style/LightTest.java' + exclude '**/style/layers/Property.java' + exclude '**/style/layers/PropertyFactory.java' + exclude '**/style/layers/*Layer.java' + exclude '**/style/light/Light.java' + exclude '**/log/LoggerDefinition.java' + exclude '**/log/Logger.java' + exclude '**/Expression.java' + classpath = files() + ignoreFailures = false +} diff --git a/gradle/gradle-config.gradle b/gradle/gradle-config.gradle new file mode 100644 index 000000000..834680663 --- /dev/null +++ b/gradle/gradle-config.gradle @@ -0,0 +1,23 @@ +// +// Configuration file for gradle build execution. +// + +task accessToken { + def tokenFile = new File("${projectDir}/src/main/res/values/developer-config.xml") + if (!tokenFile.exists()) { + String mapboxAccessToken = "$System.env.MAPBOX_ACCESS_TOKEN" + if (mapboxAccessToken == "null") { + System.out.println("You should set the MAPBOX_ACCESS_TOKEN environment variable.") + mapboxAccessToken = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE" + } + String tokenFileContents = "\n" + + "\n" + + " " + mapboxAccessToken + "\n" + + "" + tokenFile.write(tokenFileContents) + } +} + +gradle.projectsEvaluated { + preBuild.dependsOn('accessToken') +} diff --git a/gradle/gradle-dependencies-graph.gradle b/gradle/gradle-dependencies-graph.gradle new file mode 100644 index 000000000..5cbc7b974 --- /dev/null +++ b/gradle/gradle-dependencies-graph.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.3.0" + } +} + +import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin +import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator +import com.vanniktech.dependency.graph.generator.dot.GraphFormattingOptions +import com.vanniktech.dependency.graph.generator.dot.Color +import com.vanniktech.dependency.graph.generator.dot.Shape +import com.vanniktech.dependency.graph.generator.dot.Style + +plugins.apply(DependencyGraphGeneratorPlugin) + +def mapboxGenerator = new Generator( + "mapboxLibraries", // Suffix for our Gradle task. + "", // Root suffix that we don't want in this case. + { dependency -> dependency.getModuleGroup().startsWith("com.mapbox.mapboxsdk") }, // Only want Mapbox libs. + { dependency -> true }, // Include transitive dependencies. +) + +dependencyGraphGenerator { + generators = [mapboxGenerator] +} diff --git a/gradle/gradle-javadoc.gradle b/gradle/gradle-javadoc.gradle new file mode 100644 index 000000000..ba530a9b6 --- /dev/null +++ b/gradle/gradle-javadoc.gradle @@ -0,0 +1,18 @@ +android.libraryVariants.all { variant -> + def name = variant.name + task "javadoc$name"(type: Javadoc) { + description = "Generates javadoc for build $name" + destinationDir = new File(destinationDir, variant.baseName) + source = variant.sourceSets.collect { it.java.sourceFiles }.inject { m, i -> m + i } + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + options.windowTitle("Mapbox Maps SDK for Android $VERSION_NAME Reference") + options.docTitle("Mapbox Maps SDK for Android $VERSION_NAME") + options.header("Mapbox Maps SDK for Android $VERSION_NAME Reference") + options.bottom("© 2015–2019 Mapbox. All rights reserved.") + options.links("http://docs.oracle.com/javase/7/docs/api/") + options.linksOffline "http://d.android.com/reference","${android.sdkDirectory}/docs/reference" + options.overview("src/main/java/overview.html") + options.group("Mapbox Android SDK", "com.mapbox.*") + exclude '**/R.java', '**/BuildConfig.java', '**/**.java.ejs', '**/**.html' + } +} \ No newline at end of file diff --git a/gradle/gradle-lint.gradle b/gradle/gradle-lint.gradle new file mode 100644 index 000000000..cbebeaa74 --- /dev/null +++ b/gradle/gradle-lint.gradle @@ -0,0 +1,30 @@ +task ciLint(type: Copy) { + if (isLocalBuild()) { + from "${projectDir}/lint/lint-baseline-local.xml" + into "${projectDir}" + rename { String fileName -> + fileName.replace("lint-baseline-local.xml", "lint-baseline.xml") + } + } else { + from "${projectDir}/lint/lint-baseline-ci.xml" + into "${projectDir}" + rename { String fileName -> + fileName.replace("lint-baseline-ci.xml", "lint-baseline.xml") + } + } +} + +def isLocalBuild() { + if (System.getenv('IS_LOCAL_DEVELOPMENT') != null) { + return System.getenv('IS_LOCAL_DEVELOPMENT').toBoolean() + } + return true +} + +lint.dependsOn ciLint + +tasks.whenTaskAdded { task -> + if (task.name == 'lintVitalRelease') { + task.dependsOn ciLint + } +} \ No newline at end of file diff --git a/gradle/gradle-make.gradle b/gradle/gradle-make.gradle new file mode 100644 index 000000000..65d971cc9 --- /dev/null +++ b/gradle/gradle-make.gradle @@ -0,0 +1,18 @@ +// +// Contains GL-native make commands +// + +task makeClean(type: Exec) { + workingDir '../../' + commandLine 'make', 'clean' +} + +task makeAndroid(type: Exec) { + workingDir '../../' + commandLine 'make', 'android' +} + +task makeAndroidAll(type: Exec) { + workingDir '../../' + commandLine 'make', 'apackage' +} diff --git a/gradle/gradle-update-vendor-modules.gradle b/gradle/gradle-update-vendor-modules.gradle new file mode 100644 index 000000000..e215450ec --- /dev/null +++ b/gradle/gradle-update-vendor-modules.gradle @@ -0,0 +1,8 @@ +task updateVendorSubmodules { + doLast { + exec { + workingDir = "${rootDir}" + commandLine "git", "submodule", "update", "--init", "vendor" + } + } +} \ No newline at end of file diff --git a/gradle/jacoco-report.gradle b/gradle/jacoco-report.gradle new file mode 100644 index 000000000..c4e0bb913 --- /dev/null +++ b/gradle/jacoco-report.gradle @@ -0,0 +1,33 @@ +apply plugin: 'jacoco' +apply from: "${rootDir}/gradle/dependencies.gradle" + +jacoco { + toolVersion = versions.jacoco +} + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { + group = "Reporting" + description = "Combine code coverage to unified report." + + reports { + xml.enabled = true + html.enabled = true + } + + def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes) + def mainSrc = "${project.projectDir}/src/main/java" + println(mainSrc) + def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec") + def execSrc = fileTree(dir: "$project.buildDir", include: "**/*.exec") + + doFirst { + def files = files([ecSrc, execSrc]).files + println "Creating Jacoco Report for ${files.size()} coverage files" + files.each { file -> println file } + } + + sourceDirectories.from = files([mainSrc]) + classDirectories.from = files([debugTree]) + executionData.from = files([ecSrc, execSrc]) +} \ No newline at end of file diff --git a/gradle/ktlint.gradle b/gradle/ktlint.gradle new file mode 100644 index 000000000..31743ccd4 --- /dev/null +++ b/gradle/ktlint.gradle @@ -0,0 +1,27 @@ +apply from: "${rootDir}/gradle/dependencies.gradle" + +repositories { + jcenter() +} + +configurations { + ktlint +} + +dependencies { + ktlint dependenciesList.ktlint +} + +task ktlint(type: JavaExec, group: "verification") { + description = "Check Kotlin code style." + classpath = configurations.ktlint + main = "com.pinterest.ktlint.Main" + args "src/**/*.kt" +} + +task ktlintFormat(type: JavaExec, group: "formatting") { + description = "Fix Kotlin code style deviations." + classpath = configurations.ktlint + main = "com.pinterest.ktlint.Main" + args "-F", "src/**/*.kt" +} \ No newline at end of file diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle new file mode 100644 index 000000000..9e8f58015 --- /dev/null +++ b/gradle/native-build.gradle @@ -0,0 +1,63 @@ +ext.nativeBuild = { nativeTargets -> + android { + defaultPublishConfig project.hasProperty("mapbox.buildtype") ? project.getProperty("mapbox.buildtype") : "debug" + + // We sometimes want to invoke Gradle without building a native dependency, e.g. when we just want + // 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 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') || 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") + } + + if (abi != 'none') { + externalNativeBuild { + cmake { + path "../vendor/mapbox-gl-native/CMakeLists.txt" + version "3.10.2" + } + } + } + + // Allow determining the C++ STL we're using when building Mapbox GL. + def stl = 'c++_static' + if (project.hasProperty("mapbox.stl")) { + stl = project.getProperty("mapbox.stl") + } + + defaultConfig { + if (abi != 'none') { + externalNativeBuild { + cmake { + arguments "-DANDROID_TOOLCHAIN=clang" + arguments "-DANDROID_STL=" + stl + arguments "-DANDROID_CPP_FEATURES=exceptions" + + // Enable ccache if the user has installed it. + if (file("/usr/bin/ccache").exists()) { + arguments "-DANDROID_CCACHE=/usr/bin/ccache" + } + + for (target in nativeTargets) { + targets target + } + + if (abi != 'all') { + abiFilters abi.split(' ') + } else { + abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..51288f9c2f05faf8d42e1a751a387ca7923882c3 GIT binary patch literal 54227 zcmaI7W0WS{vNc-lF59+k+qP}nt}ffQZQE5{wp~xzc30g#d_WEY_lIM<*>kEH?T**n)L|d4_rKbms*8e?2n)Ki&=O?<4J<%>V7R{?iBg zUq0qeh9)+q|G%!t|L*GUWa!{v>h%8_vhfuLJO%*-l>FD9;-818|MyT)4^v}T7kei< zV;e(f=M?n_Z{$_P@0tV}PfeKL81;-1K%hd2jPC7;DA>wd?+UcoR*R#W($?M))u>gd zdn}ehUd3m+8_k40@?K-j2J`KZyalp1AAH~OemS09)oMlsj}Ip=JKY&CS%B#&?VkHQ zbp0RoxZiO54G4JffN7@lTM-EP35bJi7)bfM8EqjCYYcnn{VS&2QEn5KJxt6fN4jA5 z35`f+Sduq7yq)PG@7FzVPY-Jv0EQW7A|u)@XZ43(l=9JiPNOEX-?M91MKSb8LB7*ix_1 zP;pX`ce%>4<(cfvymJ}t(%d{Q0z=8R1bQv29j?-2sm$ONs(@PIGdy@9R%Ta=*YdEA z&d3ZtFAJZsYhJ)vf*)knsFyO}Y=592S4#xG?1vm(x|kp{tuD2chGmvsN`Pzy^ zUV@_Yn2NIb#=1!#ZV!rb;}EdSGKZGG!tBKgC=%PM#u0uc?HGxKOZ9pZ7_T|A*1#Qy zf$Rm!>2sH}rRl&DRAmM3N>s80GU*RYMpwv5BW)XS&*^g<%=05?3M^7)<&I1!aW`0s z&|9LT!iow_V9V%qPOf<7C7X$)ABMd05mgn;wfKiF_Pq*?msg;KGz$4;ER)t4nxfpQ z>NJFiAO81*#gMz>5y%b5ZK(1yt)P-Kre5KQC3YH?naRFiq=b zJGw+CtdguK-J8U(x~Pj8^~>uka;Ov~%`0$5NxZck$uYX(d75Q@4yqjY9dl38H@E9W2#wa*RJ8+Fq#c%!`8 zF?p_di`A_*fY_}yp!i7Tkv@$(lKu;SFRYmSf^wOzrJS-o78?qR;M;FFvyw!qlC@@U zjOGrCIjd*tv02Jqu9Kx`kDN_RazI{F##4p9_>71}duTTOg+3*QxxW8&f8T&T>SwHa-%rxr1sm0msfK|vl&OQI zX&*rkG-JX~)q&mH7lf~Zy}Z}7U|~=(6%wDv zXggVP{CTshNqV&AXub;T_43>o*E6$B1-0epUkaVp40X1y$=!96kgUo zQAWHAQ4ln6PPLTKRtm|vB90=hFW>%6&a3Vxd&+4)-RLEH+7&*$N#o@kG-=jl9>#1{ zmA_w6RaTULUkhTUPuuirdzrP-E*H7VLpxQbZ1nM0jU1g9WR`IdH%?agZbu88eAX!D zmmH#^1wp!tnHJ!>H+UD~o#?l=TaYt97?r-!bgjq6OdAYtzBP>2kC7H6i5oHEphkp zXwA+ySm+72eNV~9feSko<*D;cffr6e&cy%;qNZSI2spGwz0q^o0ocX!Xj{Q3F_FFy zb;xtD7*4?WLK3%$cb>s{W9Q&3(PD@F(i%LS6uG@nCDEj-8k$@3;>2k48067l8*}^f zDK1+;{IRWcX9VNm7Upz%V#NEjq}`_K^*p)Vza)4Z!DS(t4nSte6V)4t{4zL9S!Rt( zG{n^ISmKsVo2QDFceIUfS|WN{o_BbkcY09LPkC0>vo5ZtVTJ0qcQ!3~XP=nGv1 zJo-kS`382}lM(yeA}-?&GjM11ZN}hk3NG%6OLm!3viy4Se)z*zljGWqNMTRT z;|}+51hU6pvm>GAzY!k9b#*Qp!4uUd{BHHM=>z7(TUQ&61wgNHQl)lHtm$Tv{V8?< zk}YmbB)h;VK~-h)&*iAh&3CrB-vGbFBvrq;kS955Nc(!x4d&^0{<$rOYwALrDOsQ4 zW9hcssstO*k44cLQ%oj=Xj9q|<70?iI9T0cS6YjjP+BYXQepHl8|&Ti8B#65lL2A6H|t*f&z#g5Xapa^l!(# z{3O494S#6RU}ob3Jn||E zC_hOlR0p5`1g7@8F13LjC$1vO%+&M*gnInCca^I=)t1-j*Sz;lm3mi<95Fr|0BFc+ zu7#3Ed?%B~Ue(h6*BMLO%@xB;6k8MgnjgMWjopLNBA9B0ynXzYzi2B4s?*J`Z6}M9 z`z+Ety}W&Vn)+KW)ql|+_RkE4d_;T&aHIwh$qd6>IR;n7%`5{W&?Roh16J=vX;Sz(L_>M=+Ys zq^-2;)!L)YO}{_rzt7a@)sp)32M`bz91sxMKhIRb(8WT~+1b?A$j0=4K%d&1KK5VG zM<=1BS#3*W%xxfHDuYZ2T)91JD|?Vi-HHU3Og$negw~995uVc6)mWhJ)ggOB&AZU~ z;+wRRur(+D;Qd|Ry1T9`ogYs2CU`ULoyq=?b2F9I_Wd<`@eSet_Z_{@6D^!vJEqVt z7M(~r1dExgu9$o!tEoXH#W-y6TTZhWy|CWY%}8N?!c8UQ{2+>vnqAL)pG@)nixQ8l3#ZDiH- zOAKW<`aqk}2YVOsgkJn^o1&MTTwm?Z7nNVZ!KSmh7M)yntYx|-(mIs}Tx+Ef#=Eeb zJ9eLf!`0Kz#>vad)zZ+)?`guu&dSx$k&oM1Q_$x<)K7U9#kDG4GatB$p>pq5WZX$- z+bQkIXhgxm#Ln+Iq9S7Cy@D8Adlo&0bgaHEnN4(v-8hvgE=x3sj3_QM^-ND`E*D2f z4Iz`_sKU){3q9S;{>cO(!Duz;Y3V>sB$$VB=phfv*F;pxRVz!1i{0*%QQ}ZK7ARHbULmBp8A7 zz93B7-OS_TvFL!)V<3|WKIDk{_$C$Gpw}Sl&YiUR!TvO4y;-YbzS-gk4rR>KFm}GQ z(y0jd8o`kZO}4_uCe0pGLAzRy6L%bc)KC-;ODa9{Yw9EW>F00Sp=p|Fb9e~NQ=P`B zC!*duS%7J&u3)s-SO#I-pRb^G3l)C}q=_KtlE@yr-(=Lj`miy-Az_O=REB;!DvnTN zk=+WzuHH6>mN8TjMp^0|_N20YLb$W={LE4B#2oP$p*e=t9*Pq^A%CUB9JhGQs200( zhV4T*OKUIM`{b^3Xt<+B?OS08(%d=UIwYp@E81^+&57K#eg*w1-RZiVpAJkC=VrCOt1UIT|y#IB$V5l}&G8kO{eaZFLGx3RoJ&N;4O9yunGUqu?ea z_(0(#OeEfb*Vg)R}!1*oms#bJAGG83BAD4+Q+e;y0;RhEa~F zz`Oo_z!J)KI)+4vzOeSt1mYkFe~D1AC&ZuJlB8ZY14)uVQUWpt%(YK?-imDdvIW)V zRfLI>P%DVp;?PA_5xP*fg4*Bu^H^|KM6F7~Kh?ER!vNwOE@2!hj?JMnQTrdAW6x)! zFK1p03IGKY^f7g%?fq*BSY7TX2QP&EbQ6jo4k+)%X3L5vc zBgoN{WOq|@unntspvNN5q`cUiO$=zt{SNkTy)J;pf8r@$(il*!`~7x?@Y+~G>*n=) zOt^zka-hG2j|*o5^BkI2ePjqWjvNycLpt5jBDy$f4bZ&vTS|W08a~$$$HtK(P_@p8 zMUUu?UUT1Fa_^fo7g>yK@y-M_sE#1BGpaSmh3BY-tK<}L=50V1>P|u{*fT7yL9RD% za;^U1y<;Kt&T{dD>E)ZssbT7R>Ro$ff_p}?@(ZTg`{ZFNUj&X*n&bB+ub zq)0d%*cs3S34)l8068Ko@q8d;1PK@jgqshQOc2Q6-z+H zuPims#_D_e+utKms(L7Wt2x0o!w2`NyC1Z>_E%p=yZCiLYmpC*HUjFTD@EG0@>Xl; z;$Xa3UV!idY2D{4WqokC@;~{7k5xzUT5wfI;h|+z4l1~DBMmU}V}?co!o46N9BNe0 zDe;atV+Pq`p$GL2g&;#xdAflKR2&Wfj1gwlTZN@PYYIya%6gjBly&E7;;c>AYIA>a z@#lO2-Roe_1)23y=JfMB-bqXw)bg2jxp{WnzS(AJrTm39v109e?kErRK^uE&eT3(g3KwitamUX%r=36jqIb}JtYaiXHS`+tt!u3-IgyIxh2=i!{PiU ziqcdkUO^Rtvovc=tj8HeMGMkbTq$kRq8G)N^)~Cdvy(;*i!M`wXNVS4Fc2VD<8$zn zvXs3mw`%va+$rukKI0F?fHJ01Tk5D9*{1GmEDpj4z7$KB^@mO0_x7xG8+Lx0IRqyz zm27+_T=9*OevoYpwS>f`eMTl{LyFZYqUGv8_yQoP6ME$)Z;yA3lf*2m*yiUvi(#uf z1;-wx@s7ARy%wQ~djP3Us92T<6aCTY08l35F3~rW@xs znO_V+$s1G;i=QBEw1vU3Pwk}i{3#nP>~+JmQW|4q(Pt8clH$ynV2|s1=N#aLJ-&Wz zS2UV#f?iy?BhFm8W6(4iv~GSHV^NXyko0FBm}Rcrg{kU}nVx+G#`@!mHJpHyeqPKr z6Lgrdr^rU7D#=j(%P zZ|R{u#_gd#2JjFX^5)tZ`w61jvtP`x1qgLI5q4`4#CapsWEhp1ESm%l$mnGpL}T+| z?@wZ5@hJuvXD{AH#L6?4?la@&8AnTMk;H+}wz06RNj^X;ZwuB7si%=< z9lJM)rS=>{;H#5lp=D(=n(k5}s5D6G>Bm1% z&25b2t5a2TTv;n8-Fpr!v`+I`w|y7B3>^u0nue5~^_Wj1wrQ)-Q{lX7w%LTLapV}S zU}NSrz$z1N7!KELA^`=x@CI}k?Cp3e+bR>gqs{FQrlJMm(rzflHaaJErBK6;Un&*o zH63;rpuq`y`-PhKB30SJ#oBo+q?##C--15`GXw<&iTO3N-?|szKyHO}5!NTPF%2u0 zmHwP{wF&^k`4!WVVGV8n=aBM5Z_@{{(DMnN!rJZ?_-Ge=P#dHHVpXj6BHxeS%7RQZ z5;1Zg@2h}-gOZtugHqU(XE*BOw#HJSWIx*1at zRrG=z+kI=U#BiDXcaYY~o@1WMB|UH8m?VuAep2nWY@x&2tkj;XN(pgME;mT(R%;^N zjPg%R-0mgo>D{8sXwPeCo4nzPuhh=>sCHglSrKvvajw*GSpq}{{cl#mebopG^vLAA zj^Jf|{X7*fEi-Jpe9;mo5bN{nL(fGVge-dF8Ue0cf&mB=B<1|1TRRMi;XYY)+8Je6 z)|y$Pr8=f}|Gi8F#A>t_tDn>=HZa$+R_58Ntusu@2Is4c*i`s&Ov~aKz)5xBW)nto zHe0i2-#|aF*kXsT+5^IFNf%zBYF>ZXzUC^W&C5k~Im9Hr%A4Gwy8-Mk2l#(8j_49a z+7)`}R12t))N8XC#916}iuKwGx+@ThYtWOO?D zFTB$Pyvq-=m#?4yUaVOWSj9I3{}m=cfq*#vIRX7!u|^_eZ)|8IV(IMSWNGB;Vrg&p zFV0>`TN+ys6LOpaue7UiNVcXV$m-QIYJ`mi2d> zN*=@RX=EOenr3$$(wpB_CAIABy)kR~B?22(#`W;uA0{H&-*Wy&8rL83?QX|_zrLmQShDC*nAJ$v8q7U*1(xBK1(s;q##37*2IvNSh zwr=LR#R|?jr6hQdK(?fo^jC?eiF;+s1TB)E_FBT*H)&U{lIz3qbtKQ2HY+B%ep7+n z_ytKe!a7?!kSGrXf&p(ojv44{`cs3Thr55=<*1gV$VLP|dskx$GL&l5#61gJ^+VqN z9lx@G1&;#?massD3C#waJrev|_Q@qTPP-4ixHhrEBevY5SFq5d8Q4qo1sobpScc-% zlIapW4WVEJwW*mg4cc2!OmwO-agkj!o}pVvG$tjGyP_80MsjiUD8o|l1)goh9L zS`Q>&2k7Nq1h4u!?d#QW4*DljC&<4?!i!gRKm1=YOW?0q#PZLP@IU+niGq{8ho_*c zi-oD3i>0yQ|0*}iS9VB(D7>J_Bc_&)s`V>Uw$>q)G_RKpcNod+9FgK(P z%wk(;FCf9Dit(O)wTUp7%@pjrN-(0z@I2k{h& z4~F7+(KryqTkF$=|I@hh${li3@!mq=>Z}!_Wp_`D>c@#H29zqaM;mpxa;5b0y;dYU z=>8MxjZ5&o-fuq)iJdJT?fk*|EhMk7g%2fGat8fS80}&QYkaDB+Yeim^_98)?{BZ&SKW{kHEC(riD; zhlrcGqj$)(j!z6}4Epde;Noe%4KH~04;znvE3$&p$l+!b_DaXNtv|Yg>(s(wBAM=? zkd)yySesZSr_g#ctWx5@Hu7K!dX1|%JHv>WYg{?5tVAJ4Z16Gc8;#GIH|jI1bvK4FrXAHDcrx5L zkM{>n8}B?MRqQ8SYnMVh8@B)V05kEL+D-f$T)cmkQigvHFlA3?7gO86(e+nObg?vb zmN2yYt402cA&ODcR@PQU`C^mgAjFyIVUf@-ZVA>_qL(0Tra~b>1tEnf(K{#1CJPI7 zJ{Xq-wtsrp(#J7B53+}w;h0%UWB48I`yyVkD@Sy=GGWsAykYI@ebv&}vMTrW{t?Fy z+#PQ3dpc75ixU5w;cUoNhC2OjfH=nfE#E**j!3DiV9yrZ8S2>AVz3xpk&{lMfnr1! zUxh}}qZ)D2qYRN+Bjq4<>#!8vnr~~gOR1ZD#*E=)8=%sI;kT;5+0HOSUygZGV4cfcL~k zev9V}!;^)ZwQgHl%TqF4kftMTOW}HGHhPR5xupqM=m`xsqSV@km=wJ2rWRMtX2F`> z=zJTRZ4~m@9CK5qWZN{#26CtJ87c=pMX|L;0VZ)t*iWd%YU5&|2d&JD?$B}L(~Z=C zJ{WAqMa{B3A{mB;8Df7ELof2$GTb4iGw1C^cT9;UxoTBTfXkcvO zAL3X$>sZnx{uI6mO*>g(&kc|m(P6r#R2enAp)@+qr!%A%Mr^|~3V=8JAN-S|BVh8% zC>`65(EwORVnZvr6|?9wb7$X!^xpK87Jye^cy5^r4@FvKdpJ6nR@_U*GLz(W2|=w9 zsLrlp6l7p+nTnQJcNI}!F_iGAU7ey+;5A@4t+CYD=8SZvc0yU!EM_Ux4q7L@)pqiF zTkhP`^n$lm`$qTJNp*zmS~5YY0bH5Pq(TBf4Bi?Eg9EOK`chD}HVQ{Cb{w9c z|4SDYAApRScfgFA2MCO$zb*Myr{WW15B5WTM+t;BB~3$swj{>Z4yBHI^ONmD!4ufz zV$vBZo6{}jIYq?dfRdUxXxv4{NE~GO#VCJ5g@jcnkiK=Z=~i!yD&2z{WLbddhqZ}< zk*3_nO6z5o&)3uCSNipDK-!K+=HZZrS$v&r!`XV2>22aze$56|K1qv=%B~?qTL%7w zGQXFp78SBN|D9=T&Q#?-$y?|$QCdrt{F#{$h{goO2Un8rEXu0;4fqhaWg*@tFeBqP+0OptF|;X6xeNL61nagmA#cXZQGqZ#*UV zO?`Jx#RHURffxb=V_`7{85DJBdV{hg_S%G(YOaP@+0%nQ#63ds@CSv3|9lcAvx+^7 zg^4>^?5(!_blsvw?fV$V^C}8cScRJxd8}wX#?itkWDRRg@NMSDoGAbR<$%m5fM%n4 z1Yf9hf{kwbxx<-nd~&+*58loncHnr8^7_HI5?q%B@nRd%Wx$F=`Eq+GY z(j4pfcwnwGU`-Q(zw5lpAkCmiBRAmww;b{T)-QV&)AN4N|M&GRrwZeB>2EF12LJ!f z@Y^}N7~0s7F#b1a%K6J2pr~W|$v-nqngt+eIcQtVi>=YXLKi4N20}sF3a1HR3xOHC zHgeniAY;C`q)DrM3TQRYuuSg_CvAw9-c#rxH=zCXxEx%!J%G$O`g*f(n z&gR_pNqh0x<=*A={MfDQ{b7Lp)e571+YW=Dyf4gz!6Y*tFHaQp>j!fLn4A>_S%Qcl z+Ty(lse{z5=Ynrk!K+?{(!jXzHy^Z zBQpLNIoF+}k5s5Uxr5+vp5#H(s}53LnnBX55QseKZ8Hxa@eumRm$anNS7WF-D^J-z zHI%M7OxKv(L#Xc{6|cp5>0sm*B_KMXWvjZ{o!TW*Zh-1zD7CDEc^J=m@4 zUC-W2IZE*bPdOZ}1KiBlbjE3Feqt*5441XE7;c-Ba*}bV$wU`f%rp&3VNM(;4AG`Y zhmEqsI%4|K2GCpNGAiU+;;ns=^=K~jupEa{{2Ny-ZqT-XsL9@3+$X8af%k9EME7DT zdL_NPOp^kh+bmbBH44fSBvY|XHcOZ`X5oh&rFkx+ZDY7cS7!D}IW+|D>J#b;&DP7C zlJ5<+mdp=yJCiyCZU;L1R1!1IA@z=sce|i!{9G>6W7362#;Q{czmcL<-ze0~gZP2B z$dioNJY1tMFo~{uW4n>bEJLYBt(CTLENJik@lCsoBR-S&MLO+~RTrMPx(kecyPQ8I z`eSaG*F$i)+>U**F9vC`f<8gLnZjqUWOynXn^Hx8P$%iqb7P}C1jpKLZPgs3ytT&M zO?bo6U477Z7w>#A{RkS<{!--p3wKO(l*6sbFte+7#-4wWKa&+No{Aq}5AMvd{AvN{ zuO+ei`;DRME}vL^^N!$6T$SyWhH_)9-Ie>DvAdCZyMar3yfz!9^l}nZWGhcIi`&*7 zxe{!J*)rP@)j;g)1*DYv=RkiJ_+jaECX~u^OjvXHv)OEUGTI z5%xHYFBW9u!w0hrT@UIHhwIc2>nvLqCs%W9^O)Wu$yv-78n(g5!RM__FQyUbL8+!d zx2$|y{ZX!sR&w3RPG%bvahWHlMCV}2xW~RAO*d)=PH|awjnKinvJZD_E)?te6>Bs`87e+# zcT=hsbqYzg=jtQJR#{G>h${J2Oh^zT$LJbxZ?oz zdCb~Js#N#7J%y2ps_s7uSQSRgqSd=PqA#M=1p*NaJ`G-QZMtx@UHSoNJ;4?x@T>Ej zTYR0@L~`_)=F>jeffiI+BO8!+d|~cODqYGdr&R}VRH}~VuTDAb@}hNyzF-v=r&qNR zT-BUgya?S#Z#)RnBenZEk?66!_m6ZT?C}`kZD1W?f=Z6pq$0}D$&s@K<_8P@dUc+$ zs(05^Rf8U%cSogY?3S5f7Q>3}_U+Nl?=_qRb27Nh?(GSlIN{)q#?EU~I=kEnk-Bhe zgv-7-)|}78vT|2Mc}^w^B%Ue+VWs1RCx>`qaJq&myTv2B4fx;v2wx$FEqFhd$n>O` zJTzeU^DFldU4g@v9xznt59+-j<9<|U3^ToZ0>LxNC8uWHG2|V*l54X33NnH7R0gPM z@kWThsu?Qbl4J@WstaC?QDop59=188%fvE`QhD8!T^Y0Lh2D%}>{E~`N{x0sClrhc zh5pb_sAo^DD7?8xdW>DppX%D@Ks@b(9}9W|+rjV78vdCMb?dJ>GRyM%LI3YL@y1Il z?dC7$U;c~vY5y7X3)$Pd{ACji9b^qH?UY>%om~DG@N2p+sv&%#Or{cxpqT^zlz<@| zo-tCEvXr!dYKH{N7BGfjEkGIRbpvZmo?s%`M(=!qzuiddO-0X2RrY${@So=w;#O}& zvUkYLc1~OG%it#d{`2`_4x~3A&m`obJ!&{5tr71aI7&b_p)pK~nU-)cnFxcQYN|7! z+S`ph3{_Sf)K0eF8BB?}t&!p&JlgeJqP^qiAB`jj>hPELj!hrWJbL$E3Z~V>)P(3@ zfU)jqVG4;g1O$#E%uHVLe)O0cD1;=lSjba3%OBcw=&Kp7vbw7gNKzS^s`{$5F}v0x z^E-1=AV!pnR3uQTnTwhSfhBf!Ow^7$ELVxLX{4&m3$0e`Q<Vw37*ldO`jX2H?M?}WZW16~7e3r1*O?D#={<(WU@*&&8Z>oH)j1BH zB%EvM?N_q&o`0szW@V-vCm*ymTP>|i6%+FnDep5Aq$^B`y9Q`}PB}DF%1{3u={{Bw zZ>cUaF{lZtV-CU?EDV5)fpglR`8#UQB4iVlZibeE-TP!7L=jt31C8-Q?RZdtAYtEv2e z_^XD%EZy70yKZH0usn)SK-#O+fUu8j zz;=6SPkSiD{5aBWG&)G%j z=GWkI>em+7sEVaH?T2XSBrpTt>Q64PQtbkt6xSiWGFLpa(miCGSqZ*P*_tclLfca9+#UIs42wtVx zv*e~MD@-;dAbr*MklPxeIg~q#GQ>HBR?5QhBY|#|y^;bCrJ_Qz0-J|TuyeSxwlQ@J z=5GwXd2e~}AbFn6cqQ7u+ydRcMNkKgxm*mQR|15$;*6WAYJo-(OLFj-$Rr}E`N=sW zoa_b0>s1*Tq0sc+R0B=`eW1nVPbFz+A_>oo>)>oJt5*0=%iAHupM+c|en z1?0MdH!=h`2;oQ*uViOC?!+`-Az$J;H|#JF9+zOVMckosT4BFGfI*xPk{*xvBMf!= zA=D5DY(XZ&hl=`6#WbRF^T-&F2quiN9EFhjaixT_ZQ_U`0FT;YB-Z4o->O2>wz#%lGz(!3Mwd@goQ6zrP+(!k7vS>EY!Wltd3_a|U4&wQ~a?fHTP?#?E{q z2^`Cv57~a@Qaftgta9lPRbFza&z3gO8zG?Yw^p( ztmyBGx%}6N|9R#7KXlx`$_d|S*}n}#2qC)`tXkA=^uM52Lvsi49SG@o1Z{+EASER$ zd$OS6_X>vpa$-Ekym(VSbuR!&0^z}a3?m_*R`#?>-wIO0&X$^aHIxgfEpWqD=8o20 zmUD`%Dq0M(;1JhHYH}!A&kGS<=`nx*s%Rh~CkC<37_=Q}c?oW;)jg8~A2rEYwbGUaC^6rW{vlW+!}y<| zpGDCpt*}TMP4T(8&NrNS4^;kNU+=Jc2=Yl1duAYM4%C60dJ=r+;=K`ljPXCT1zv>Dvcqy zIifqtMuQ8MT5xseaa|3Zj*5z6#kLeXTWg)mMi5wSa|#r$ax3svMpS5Z&pKia&u9}A zu`j1 z5=G(SLOf^(kVlX?OhcpJpZ4$OIz=FDGt?1QwUG_g^sml6XO2xtcr2#D~XL-K!qyMNX28jwCH ztG-{k&0Wk`KM2tfXx8f2Mj>#i0c$u1^$GC?4Rp;CCIf5HYQ&azR_46S(7){#I%^kk zY`4iQvAb*+*er2RENoZx5)j7hF5*9W>)2!ujxC%Y`4-6Db~cys7DA8J4R*T${yjJT zQ~s}Wal3!?fVfAJ137Z71~orJaB@?Jn16)*iUkKvyQPD@Vao?J2EOcRg5HccJ9+3W ze3syRO$d;GX$?VR?U);|)?!!;e8B#t+>^)f6NkcFeTMtR?-)6Kw))9$B|-BB%Z_d{ z$gJL~V`nj6d3y8rqqura2qNi!7JR{oyZVgutKYHz_(IcPOh}CCOA_j(bMLL)$6g4w zpV$}W{OrN$B@MHm+~;c5+D0Me{Bd=w|I>pBnYO%qEKbABFc}*rxWU&V=1^O z9Pf8DJT(fTlbJxJwv4b?8KKf`J~e8g8|>65ifZZ9AO~-@GU_2?vmhb@0%p#g-mudj zz316PhKTE&8F>@-^k12IKTAI1t`&GVUHhHT@Fj9^-CG10a-Yj=@1Ni!zj#wy$*X7b z>{1k>s4sN)G06A7ycYRX;cshgg9v7tnTnRB%=&@rUg|yCQp)7^0=_zNWYgxYfP0NR z*N)eEY?I00F~eo=YF>RQ<38xVxQ>a3&68WNOMhiT>EzFq^$ZX7*s3df?8G?f?j{2P z_MS~ysmq!^voZA6A-TzGC~KBXC^s=7qhY62E1d=G&nBB)TT}L0?@XBGSWUU%EjuwT zS7v@++k>Lu8Z^pQp_xa;2w`JMjg{8&=lZU}V|=N3kvD#3Z9--`Gtg~)%(#@HczTu)Tz0vtTeu_4V3!u5{)}$6XdbmA>R1suiJ>%W#Z81vcnO-k{Tvk>> zjxG1HkZa>-H~CZQc}P3;e6-$WcQ#w9!m_>gcRR>AxZ7m(6?(=N;bxv|_{k_0*J|#J zg0}lz^kZpFIJ#xa!9tB}R>HWmNg`jecUx@xpVTZ#=}K2sm7{tMk}X|Pj6_Bv@{1}C zl?)7(pNE>$ml8+JsrGSchV8Yz>{d6`29uR0tIo+D1CE|44lx|49w646=TZ!ZJHa_Q ziAR>Aj*3)pRn+1szxF*wHWm&&mb1dPmS{pqv%9kzOhWbcq1qsZ)7N9Y(IO*J+;U>vu59(lgYef z8ssn0HI!$T6P#=yMbPN+d;U@%RHNxE5jI4n5ul|U6n2ZlSEU>zUb6G#&shic!|Tdj&~hqoIHy@j?I|fZXeG zIAXrM5^R1$3Bh${({5>EL26d6!9$#S9q%dU)adGO`>mHq2M1TmGe%01rzCPzteMRU z@c3~_2I;(yrXkVjUg9|pyRUx5ZM8nuM$emzn5k~LMXreH@G$mmIHlMTZCn(iGRZI` z8r(Q`(S}U5dJ3Lwbe54&cCk1$Ysj*vlBz4vNo#q--Tvx|7OtE3WV8!v zeY+KFN(bhth|xCss>}_J5s{f@o3Raz-qVKdSxHwyPs^x36(REq!mz! z8>!Z^IkwM^wdcS=wq@S#!`3?fMy(#ri6JUNz3sKWCFt&yex@5y>N~K@IlJZ6V3X73 z8>N1#biY;WZW3ePGIk+dI&{n`?n|wXdo?FzB@CJ~Q2{&};R!Dzma1u$bpW5`fVYu#3hOwiUJpy#w<-6WCV;0lnqY<` zXe}#q*?ZB}?9tf~_uV&sR<~q$z6Pc}&2L$ccTDawu10Qrgux0J6YR!$HhTCa&m}ydNF6WaC z(R7akrkk)xuBOE^w6IF^1D?`h z(I}cD=;}fGJyWR>s&1SDGCvXX>cjD<%S!KGxM_1b{gt_Mrp+Yu z#;%ExL(m$`IFP9It>kk%h>$b}xDB>f^F)ES@8N3wp%VE467mjDn`yk3iT#7NPn z;5IVXR#qO!VswVez^gpJT;=ySZjV7)b;MXOcRB+ua;;fcSb0sZ*tB9=+Wl(Jp6rV+ z%jOYw)cRw{mrHv#Pa{ubE;6CkzSiXN)XQwaFT=s=1meJ;Ep9po^?`BY_TTZEzB)=$NKpL@3;vGsq>S9c4QZqYBHcEZ9c<>K401) z{BCu6SN8Mj@a7o2`!IsZhj7F}UDd#z6oww)tT=KZF;2gf7|E{GA=4gog$vzo+J5l| zf(Ns=C8!f>?TI4NZcCQkE%ZfabmtJnYw!bVZFi?70MrM~A>L7aJbXGBGQAj=Qiw^E zpe$p9c`A|x*R7Un1U_|uOXJ4{fnQiZOT0I{pL)q_;j-fOy>dD>O8-H!! zHh9-ic+@%UYil30Fz8eKYZ&<7PYFP)+fg%$INZ~Rp0=KZ^MAt`rPAX5C!8>}F!~WAs2h5!?)MOufMx$>Gd$oq&H?KceyVD4IAZsdNrjjVD{j$W$F|6ax5 zN>6Rf&XNfqlREmW@#r>LNuyL2TgbSTwwyEIsEFn!je*WPUPFf1rNke&#e9PZxv`p0 z@y4i+i7*L>6CjeLCr>PpU`SXZDiBe+ks#3)%E4)_9VXrSGn`oOOFQj_d+5IxoI!y2 z!#H`()_iZg3WpX;rBe!m{EjW8N;0lbSC@1u+Bd9I3M}kSZU!XT0my$;Gv3Lq0gCg` zMnLf)Ne1Cf%+_Eq8(hof{glQAgCG3gdEg(m_?ftWw}D?$0s#^Hb6F+%-`eQEswz!L zAC;pPesbmv?hG9QFd>W;#0V33ZY%^?$@n#d_<9V4J2K}aoea{Q4q>DVHGDO#E3s|c z5nL-v)D*CoNZaj}R<){{mX_9)=a%Q5-jbWY*8Sb#ZpI`@2SV28^Ri>ldGVcn!>ehBY z>QA>YA6-JJlp(Ev?N+UWctERTSKg4{%AYODd$%J;cI?9C62BeF*>DJCRSvX#ISnLP zo;>eYCQF$RWZ;eQm<0_c#)@0I5O2^WVrRe>IrO{e{3Ph7X0H%mU3?q$2)R0i4=OTa zg=|B*-HLd#h>$!3I5w90s;$*ddr?7!D*A9SHI(RJIqN^n<66Lzw ztW}D5p*6!&%ZDeep*6KpEt)uYWJRV=va?*0C9{|XFjJRJs|X?XlC7(FdOS6gZQ>12 z`EuxHM~kpFEY-9_&cadx43>yDbzTq{HS-cBpS06zHY1<(O;?m`ipX;5d-(ftAI;nPe)j?!(-7}v&!zmP%Bj7i@~jBdR+ z7K05s2=oX;Td&Rt^(o`(QELO9opv~)>5UK}@Xa4uVwJXMKtfy8ti`f%%yqCRn@?e3 zoeUpKP2-efKVUUNb`%wV=1^XjO!_5eSkE5wTeob^fep<-w9+tNHtStJO|V}>;+Xd~ z(G=RB9iYXyln^u6p$R-mjxAO?M&r%3>xqki{bU_T%3*uUrVuhJW#%n#Cy^aGuhWF4 z0SSi{OUtb{F)ichp%^NnTuEvcP+u*?Fijs=&Aq%tDL=8%4zaMl3439cHl6@g76&P< zFfP_Itpkbqe;9kmC|$Z_UAtDI=uV?m2{xMj_2Ff|G(rG=7gi|!L z*F28JDpjJmUD54UP_$C>kim#}`@v(r94s=S%@DUHq24wY%Y)+mu;DQ@8Src(exhbB zTLJ^97|N;R3)2WoRr=FP_K0Lxyk6+fO-A+8!!b@0Zj%npngK&htPT)$OLSxNbJ?@#jkI$U-a8{Zodq^Qq_FCZ?oCd@`2N5Ml~;!gwHJyIJ8y;|D0q^g_0Z zF_|22Z6TM>UFy-uS|gZ^2%MX&&kF2*CGFF+^z}lA8c<7jD`s~> zgBD*CO{dFmEoo|+_MeLTPnXeB@?zUgW~c&n_Hm2fH4a-ia}`=oZBp{_qz!W5mF&)f zD?eq^7W0tiIQ4DB=QOAr%47l;7k36Ejc!25YM+(vEM&Iw^l2pn$8Hr}TwNLp#A&#U zt&Q!=GbeHS%S+uC7^Mr3j@=VCi*?JH`TZ$BB7RlPDt==EmS*`%oM60V3WHA&5+AP{ z^}Hldil_l2r{*3gFN)5PH!E+Q-`x|dk9Z(`1b913ZehIgM|F3xYI*QqZv2${(20{4-r86b*@b|Yl4{5v$pXz!Ti^ID=MY4)AWz zAiu;8@b0iEzXG=U)v6Ui%idAHln(y9;LPV#HAYKx9c5FzJ0@X{CjnO0!Qw@XjRjI0Rl20snZEc<;5<59i;9_`w(RQ{yd3R?Gg=lRiS+bSxE z3$oR#$VXDlW7$SGW?GV1C_-ax5qH!c-ww~e5JGe)_6kyHoNo(U6qT0XJeZ|*>QM%p zDaKTUQ|thATUvz#DH>{>jm>xpqnh_)d~BWi{Bz!TN~}Dy!Qt{DMOHG?_*4syl(nuF z&4oDj#!yB2TaF2iV?VTGRV8QlN~UGB-3|R<{b7JJ?elxAr~Mq5jUZlY7Ht**SHEY! zN!eI>ntTOmk($D1dZ&9HO(t}kh9({>E|iEV-di%oc3=rwHwihBwPklAcuyjE!FuTT zH6qv8iGzpv$MQ?+TjJ>6*(vLW?ZBKv1fKe)5Czc;`bDiB@4fS?`3i4;L~f^bg{Rg7 zg+sj5B?;2t0evnQEtX+KM4R`ku~<*2ywdFXzSu=ZLFRF_rEEWuxMZ>$W{db^KBF%l z&oW`%)Yloo#I?FhoFv=$43REEi|Xtf^jcrk(2a3%CwEIS0{_|)uCXDl)@`J)P^+Fl zxCZ(p_ecMeww^pd=4qoEcaQ?@E;&o#`~hh9WHNt;xhCUUOdlE^(vZ{WU;zedlg^u( zqr$bgZVhm>r&Z#ei{Gbn2HaELLcvb%JWK5TD+zY`MOzL^alkkO zn?xKP6B=tA&tkEJauJivDDl`FyCa~O!k=|HYm15ZU?NMsmQ0|uy$-Pqa^@g+qbd7? z+#J8@w?$`MvW&Fzw%UNbUrSVZdge_KB03|;EwK0nt&RPw&82K2_vDOB0P%QpZx!=L z$1qGt^^oJoT8=MyT$$y|+cj82>+|zQYkK`O^EcOwE0IY`-LcK+EPv2awTtIUvPVP6 zll`1Pw8f=Vcc_A^iUc_{_d4WYS09l?jow1<7_;K(UE#ccT%g@J!;rh(WN7k=xgQ82 zn^BEti_yWvd87;`s$!ECw%^jfjF!XBJqxi0V@=Bt;jMD0VdRZCaT=va)|UX=nodWe zQ@EPVCLfOpKc)}&Kc04>v1$50FYJ-FUl!=x5tc54sG1b zarK3?bUa`vT@3!T7ubTAwxNQ1^=nB)QTA72=2y%r+!YlWQ3u5t6KFxKQ<-rp3);W4 z=2&81XLP74sGiXgOOQ03Svnz=gP1mG#dv(sv*y?k{3BF2)t% z@n~?Mt>%AMmJi34OXnMV23d@oyS++~wy44&HmAug*?|OgOyOf~6U%0bH&Ft42s<6| zef)H#J@l!7G5&xoFp~Nf?XAYaUvH6naNZ;Uxj>m!_(|w9{WRXe>_dnH^&0jbUd1U` zyl@C|2Wl4eWHSm!333N^d`~0rv-Qws<>KgLNC%D*NQu!ZX@MExA`reUl5|>y-w;d7 z4Pm0_f;pNtDA#2=bsp9+;DmeD9LRZ=Wd0|p^PI60MNTo0nfzKnrrb4RMJJfZX#Sl! z#D?TktZu?&$^&OBo`_(--U84)enARV_hNPqIc!8p^2jc#W0f^NLjY{0iZW`OGD85U)sx&296;^J zYn%v=`dMk+qFia+nWL&yI^msw3YC@Q7Ck+?lagu3bs$0Co_3269gh$zAiS3f|EU$S z1#rG)HslNEO=)l=0Uj4E=GLnN@|)3ubvE8*GM25!C+dUMXh^(CK~?}mw3O{SL9HAs z&$#;5kLni#X#JbeOq;#pC`49Mv9bI5qm;>74t6%32jbB`)i2_?l4TQl>=aV3D zTh-W)6V&P3(sE}e&xfd#g_;P9e+0HQkFi4%VXqZ(K7MhDktu@k2#MDIqO|+0h-^K% zK6$!MqUtq9u8@40fwS1{$cT8#$m%9k(O+rHxP*c2~*$8Fxv{UX9Ywb~C85>i@M zk#Ba0nN%O65puFgzcMegyhEhfvMuUg5|`4kip1fp;uAd zc>%h|uxG{vn&;-Xe40BYurSBUbGBym`M}qv7sDb}Y%u5<)c866r?hhM3lIe?v3CM? z-v4v)$7&sj`%lE)K$rR4VA~(CHHce}02v)2gJ{P;)jlw-_~>TFwwr@ZW~qGh@Yba~ z5_SBOEzQY3VswI&@p{+sW};_Ymw$Qo1wD#lO!)}&)$;I#ZuVbgHU-&EYqB;t?lV#~ z+S?2ycmLAZi6U|u$uEGB^K|^FKLilycv-APy z;8xC@wOQLoDQYvO=!NT>;5T86;=--8ms|Z%k)a+cz1`q|rIW~n2B_=5p9r%LJNkgV zei5tIGY`@y$bR!h2z`&J))ArS214qILUGPQ{GM!1fQ*)l>aPu9(jnR9yS#^h8#m3P z<_J3eC8@b@jNwR=ue)+M8e9H3U*$@`E)IW=lP9xs)rxK8Ea|~Y%!B3DlAs@v3A;}8 zN3qsSfdWtdn310$=YE193}~0fnrIO8q)vcQ9ssywHWB<4bOf=P>}if2?0F=|!Rf0u zJ>Z1)r-cPeR*?$0F}c)H?P`?_QhIcT>QO7mZUzaIF3W z$Y>l+;Dl)U6=>iDPv8Wur0)}4124bog^Aod!s}Hwm6#cA?E>r`YuSaXX=TfxvEaD_ zgXC+PR3a($#3 zl#aI)Smp8atcp@QK>EKVzG5L`F}aOZs)$KlXUmv+2qFi*Ahd^QA2Zi?yL$L1cUP4V zuU8I&-z><6y)i1iqEvG3`0l%GoZ7);V<*36wiHct;LgO#Zu-Vcf_Z|qC^&wG^9hZ> zNle;Y24`k&tji9GTpoh_S`O9TNZp$}jNfoKP2&2EGN~V(&aj;MXdfZKL0xuWN9(;f z*~TH}I5}0x4bu4Ii|>D?*8YU*o#lNaDJjvvum5{$P4pi~$A7XG|0=WmuhIoDFQg@m zFTNP>+ZXN_7?A)1@NEzkbny^rF`PBu9-#IR0tk-%KGawz5l)7*g;*zI>($xR25Hwh zr?`g14R(kVsq{;ytB%=@r{}J=dTPnwn`*x8lg+2j5AUnD&Y}1(_h$xx^nO$nF1tTr z6KH@j)|A(yUCG_}d$>N_l7Txk2O!%;dpwmZ2H%vZhtxsf z%G9V@)}w=w+qa_ON=gR6l#S>Kx=0Uh30k<%hZ69jORo3iTYRK?I8dVZ`Y3t*qRXDq zd8>Aj+yr~bP`o4tSh-7g=bj_*vJ;uJ@AmE>JMsCt$lybryml^>0MJrcd zUftMHzIUzXBf7P-(XoLO?D+)a^!Nx4+!}R4c5f#o8xizYX~fL1N+`EzLaLCIRTFft zwh9l967$Cuy1~W8xxw^BsfGLvjEf7jZu+1;2Sj*aEkCrRQAkf;`ydAQYXMol!xf z%Z3NDK)#p#CnR+#my%f>jkau5oNnS!t?#MBWnsYB z5wRkx$U{R!d%0V$fZZjKvN$FMQ)UEuCB-hfhnAkb%Ad)8w^fI3;)SS!{MuMvA_L)} zO6s%;Ue&P)XEd33z`N=+v>7dq+{ZN&_9tWUoXSabdB?1Kf<*OKoNJ=NdGG+iW<_P_J?PD%u_tzY=6a)P#Y zo-jXs`6!>`gZTF7q{>pE8Z~7jozM0#Kf}7rpSeDB2?DuTG6tDg)S4xG_*mYdzEIT; zcRFR%lMNYk*rWSg?u-acPKhdhOpb`dObuMjhJU4AG?|Bax3VmzNnqHk%op^((V?{h zG~y1c))y60+ZcJh(rmD*fYyI#mM0El$)(Thm0b{qurbAG zN!pRALLr|ZK`0|nbiy1P@Umzp9A%cLr9_r54gE=&6GADi6h089mKTayn;?_E*Ezez z^fH?)qc+nV%adRMj8ZFwgeLCoEoxpwniP%#$hCSe+}j{X1iFD>N*F-Mz>|nsY$_x= zVKl7F)<22BnZ~@A3!c7?z+)U>u~cZ0Zc=D|6>BKcKie-+DvY!`FR1T~xMkYdDxLRIdX;7(F9Qu%_vdwsFXDLmtkCrZHu^u8E zEfN_k$83-LDIHcaC(Ki2=>AAf7onA&O1fbMC;ir+xI`RjEhn5$${G^c9_44%m(~pY zhsq$n9q-R9#1Rc?oJYMCTy2WG1HHYW-%^fit9eCbdA95x4Xd^{-4iz4q23Iaw&)SL zWC!itECbI%8n*OMWPmflLY>!vlpQl?n#`?1B^7yF;NWnQs*xn~%(}x`BZZHO_79jD4X(dJJ7Vd7rM?-RrYq1gMn`3(zu?v0#_S0 zSYsAF`ow`;yvVJl(nd%B9&^p&NL1pE$|T3S&YqohmNUH47bR!IX_LmX$W}9~R#K#L zZpRBdOq+u(XbU!|nkE`rtvw=?G)qdvdy|Ve(E(f+~}uqxfZ?hwo}-RMq|3 zkeHA`ku^A|#nH(H|F%t20L9d9d83Fcvv>_X{vxYPH^j9GttuOjG+W0h00{PZ%V4xK;At7Sy%w#OB}Shxq(M2%ky#eh3D!Y8koB3ca}5{eD%0;?(Dd zyJx9_GuOaj>D~gmprgNYs*mNLgV8`GUW2`VH1he+LN{R8r2;2QUjL?0im9t>Ay*?d zM+5PO!2nJRCzD^O07elEFP4)|7{H(&$srw%FP!+y@!2ExbEvOqG3q0xwNUZ5=tE9| z1CuPO@w3!BAXbsaXAWHG6ZisNl-k~#lA)&s$; zMZv1Ul3tcA*7ldapFl+q$m%t2hFP-%OS>Vo8p6;Dbu?@AX1jb2b`!nW=IJ%vL;q0s zgAjfp0lJ09i!oFa1=?`hdBi$97K4QC$7N;H9w*w!F4G>hX#O58^E^esw$|xMU zfPUco9Un17p&7-`*7f4y*oRF}4f0-DNLDPzwGLmB&i_Gtyorf6p8}L-FUElav??D6 z+iFy7J&zcSVv~nh(-pNMQhG~r4%t3GQLa#D>GYX3F;+F1aZcIz0a({eGM2Y6P+p5N zsR#6B4b2SFi=oB%Tl(d^)p2>jXyqpHvaT(gt31EUmX` zXAnZmK8i67hz7%|3r&)Q-mdUU{v2Ird73Y@ob)=vv5K)0srj{nraZ2*WqrYj#2DZs z00x26*8-Z+8J0e@YUhF{PgZidcC{m}Tl@MHTwG75 zr`!cG726xraXfFf@R!tn=6M4-L8P(NS1Pocxh~eoMz1#QlQr$rEd_LpIR=T89z9>Q z&FGH8r2|5{1>)Jj*S~=!flEC$w7$#5<-Y|*|BIOD??_kK(bz%E*4kLg*4EP5?(bkX zQc+VD^BYhi605!Vpin{H*kqvzthu6bp*+_=Ru-xRjt?Pg6bMm8+h(M0^{(1MY+*4w z#CtEw!qcZfHSFIu(lX)N>3BFke#OW43s9}M%ujxN#4T@|B1=4k0$fi=MC&;eUZe(p zr^PP@pab4RUPQr6x>piH5;|V<_3>4JQg?Nv%C_)+RzPMd$z?9vDah`0nVp4stfpLJ z(owptb(DT1lIq*LMPyB&NqTz3>YL5gVrA)jg7jH9>~;k%Jwfp@H=C>$J;mnoWs%bZ zvt~k)L=;G+U$I#RuTNkFqoR4U8~0J7S5dsX&~M|U!UPGA+LvoAuu!5d@wSO{Oln&f zAK)@Kx1G(qjoQnkIa_!)uOgVDN0PnMq(wDZYh=*hYOGke7Vc*hX&xH^a-8)hGS@)4ZVawHSMC<> zI$xc14^{3K4F`SaiVfy`-6i&Vos!%UC3jh|bA#EZm*|PHM1Xk}L4exjO@i2AGvY>v zpJ^X+-0Uq8WHwPnPrVsh#{*!`pS2f^emUehKS;gtD(`{w5fWw|hcbX}-W$Im>Vy1U zT!l}N$}SWak31vBGz$cUrl+eJLq4KM#U2Gltc>SN!A*?Q%Z%F?FRNj6&)nyod`x%w z;pY*^A6o+28Q`BB!ztAJ462^86i6rxO{fy$0v#*lTl6BIr=0?DF_;nzwNn9g)~?Gky8ig8wgO`p>PH zkgbi0xv8^*{(p0HBIB)Pkp$p}zSfQw{dxU-^YREU2r_cEnIPbl8I++>#Jq&6?2?EM zqSm!pZWPT48Eyjcy5Wp7Iy7@C*816)>Y47cKQ6T1-lnE>0S>RpgC$c&^jO2OBcLzs z`GzLA*`8Y5yC(!O!_B#krXQ{OuFqB2YP5s(YwXQ_F~ST%MpRBb6hjAYzJ{G>LKl`4 z8**Cbi?bBdJasVn0|n)7D&2Kw=&D({M5E8@p6{6re<2t)xW3{BlY~gV4BCQT4G(zYT2rdn96eZvT`4k*;my* z%HO#3AT=de_gaHoq-}4Ps~oYNdUH^$^{5T5Pb!q3nWHS;qpkWzaHR#8eLa?mh_=O< z3a=oP{xRJl`n9DHrGzKLCpvk>Bb;c~ToNKQcj4i=2$g>IOQ~^N{Sy-g1$stD*M_#5 z<+M$6;`Q*dJd({B#($UzI^!3?C)EuLa?Fz4ZqayT&<~iOo9qwSx`|bsy1OE0)2mSQ zKR$y26hdx7kq4eHa_PWzkvoaKIPQV;GP2LnV0OTP zf6>41YD&ZuKr`k8w^V|PkK#KPq+S6jz~jeD#8g1nK~LJ3!FasGa6`1kdl&HylQHn%dOaWFPCHn(&7muIpJbHRS2 zkpZSVR0Ya*-xHwKm(|p^0cFlZ#H2MBD2{@EY(9@JdSbCj^cZ1jMd?wkSVRaZobxP- z=^>1?^0y+h9n{m@TV)#SZN;l>|7ZXOn^_5eP22PmTU&fvVZs|3_XzsZmVaiG#-+Nv zT@@*72KV{5SN(pw|I_;88~E^#_8R|eondHY{y%zQ{Pks`GbZP8-%cUpTk7<0pvS*% z7qYds{$|}sncEo4={tNcU&OL@e>nxkZ_JjB>EA0@qT+=N(l=ab4z4MoQF}C*Jk3ve zmByH2mn>uu6N%^t5;W)+%!OK#m23LOz;XUF@Moeh{!BmEb#8=f5tZN?@U!F5CYR$S z&(Y*R7O@{CyDRurISHhOMX>_vL5>tkvnj!a`UEgA#^z`&>? zEsZ>%v6`^1>5C@EYc`Il`rVenO-FI{25m0Qqx72RJWJ^m)(pfJIzseDOIE5CSASdr zzLKuk1zm1W*H?BsY4*rd!CfzW1-9g1xQxlY4qAJwIk>@rFElK(wi?oSZP|OvxSEvj zG-xhajl$X1;R1BoBguZG7J=(73#{#AFS&=mMxaW51QZEY?^(JH0|YIh&ARhum!3|-4 z7#l?mZJ<+X=2l^dK?RMpQJ8(TCL{FBnWd*Z1S7>z6Bc!rGJBnn>p*b|J^1yC#pRiY z%Q&9F$K)~glfx!I9p?mA@G`iEi)-B&{mikY@acZky^Urabmqb}hYZEMsPu4ZFNpi2 z8Tw-pT{>Ym4v^O{P zpvABswskwrFFlipjA@!4XM(>kBJKCRO|EZqY_IkDiN45gYpS_vigfub!#Jg8e?e;; z`o<-X)=x|}^T62GfAI}}nYb<-?`;0JiBo|6Kbp9J$+y(|Z##GV+r%pqt!3xF6@FiT zu+EM_vB*QFp#1ou5_0oG805XcM}(1_LfaW!EpZmASX_VJ5It*q5rj(Qh5oeya{npM zuZ#6#koK73cv|1$INEev%kJv@0FWCD14Ws`tV=l|6IW#@Cx~>1Aw^Y6P^MAYncNZ>ejld;X(x9?QtQ4XrYRFn;B#cG7d~VQIP_G|dg$Jy=ImZ>9B+XefgO%P zN+kIfmVeUYuZyh{fk443V6+=Ob*~mdV9vY|SeR_>Z6qONfp%9b0G#qa^Y@7%sATmR;HLx7FlT@|CKRp!3tj*{es!RvV8>?>D) zxAM9Aq_RZ3M?3qZOnhhX~&Jg326FbIcWSjJa zZ%ng^6NeVZPco2WCmBj;=-4H5%&CF{xan>XOiAXvltQ1J-yCLL{~{Os%jO9^Ml|BS zU3%)bWbofu_y6YB|F-jgCf-#v9sdFwB%qJg{zQcC-@(QAHAGrR1xzTA1OLM>=35{x zl=HJzSyU-jOZ{;6t>Xi#{l4;`5UxS7w_x1qwO`2emF!h$^_QrM(Mp|UQGDoR)-n;SnsE~ag!WegIEuu zG!ziwjhZ|y^^0L9=pZV{bE6*28L|^4--_&kFC(#EM23?T5g+tKG%DXePEt>rX89%B zQGQ4nWwT$zY^o+Wl%T_`Tx?*8__)}GQ)&aVKz&$*t;rVNN9Hale_>!O&XjoqMuNKv zUxUdq?~qEGj_FK+I2~yis491SD`Jt)`E=Gr;(M{aRsjnf>Yr^*Dx}RcR zw`5{juDQ=Lta#`<8==cqIHhv1 zm%~m}lB<@&c*U-Z?zkGKCthk+n@1E6q%H`eL945I?X+_ToR-N*O;R@It*2nyR0+bI z_Gxe-WN7fxlDseaf?tjyrxg`Aj6o-m3 z2_Y&ZHUX?-Ol5wOK74#m0o2%HQbil4%iUd@|JEycoS(5?ezRqMr!@S;*3(^fhTQ?s z=4h3pG$ie-i~6rY5=8fyTLOz;qFjVpbjDeNqufGk>xvD00>pPri#!4iMX~i%A>z#r zb|5&2xCU5(&HZ2Tb`x^%Um&;#y5 z290*%aA=yK*zK#-5AM{%bXB{Q=MYFydf?_+8EleU!vvHn~`v z&L0=GmNAaub?EuPTMDra%@mcYfS|H#Y@hFLI=SL{63qaf%_Sz3h6J8Z{ zOR1PDxhGGxSq^>elf~eU5t#aOu`40{7CBA)IYQi7P z@>3((I=!n*PIV{RdlfoQj^ygKw1$1uOZ$!m^<&G=IJ+yCoyJya6Qpe6uD#?ZkR!NL ztPk)Vkxd;{BaBV+09p7XJt~9C{j`@JE5X{-)4yB{VlZ&^v#Jpe)jzcdIkd>!5A9;R z1nEFVtKA_6?804+v;Z@PKAqWIBVf z-2=qlqG5#7A?MrHs-FrEe=YyP(|As`K0R`{+mFlLKTKVpKpnxkj+1|g!;4?21yq)JSytE_(8My$9eLgJN}Od;ZT>o1^~}T2@;o$`rt)_sb+1eS)4Vbt_*AlvIgD|94|)Js z>!41HC*@?IF_fv*MC`E$}VkZO!Bo?B3;XtH=?}J`}I<` z7~2F~8~xJtP8r779u_1pvlMnEz1m5aad<%_>S;_4I8=q7)MBdV_t zbkqo=a_!$>i-j5pzxz=~C+L+Yl8^s@>IFvNEx1E>5qc*|5PU;t>*Zx1(GiNe{FP1Z zP`dTsd-8u+tFCc$(YKWze_#LBX7S%*kbiD1|A`9;j1c$>7xMGVtWg8X<)AghQfNvJ z8Te-pQollmZ!n^wR;wNF9Uq>_=GliE;4pkJxR7wbv6W5JwsmDn&9L;E zg!ZN71erO`nlsT=+&7?E5JUCsw0mPAfxsl7ur{%zf*K`UaAEhzJrRLF#8snyBGD-d zhu|buP+U87uW%=isNhRX{FDR8%k&sz3oyb96x}oXHS!(ifhN`K-*(*@R$5cV-?-`` zp#Q*C|KGp$@38Cd5C4WsIT`*xE&2lO_)u9s2G zN#8(Ga9pr;(0QrSYzBi-nWr`AAA~1hp-zg#W{i6-!L2(P;nV?>^#l2IOY^I}0?W>k z0R5fEkzutB`%Lf+#`Wpy^+p9jHo`1oKk}gowP1k~cREA?wzzMO>{H9>3U7YvC|4|J zpH~I>{GkZ+L<=lW0>F)aB5MdFC-nm&M_jZ>qGzSfNZrV0k7&tU0DjT?T~fx-q!iq1XkWeCR< zfkmOf9kW+udSo5#)(h@1T9_AS%w+V@cu{?FX~Gr~k6zmIaDExf`Z5k{UgNO_roTbzro=wfX=9UD50wOIcAG$@x zAJvana4Ln5Q;#R3k4cuKp4UkdkQPCs5O1Oaqp&H1bwf)II`|$ILpaF^gSmgN1{nBA zEJQv+py5Y1D49E76-?@?m1g-Rl=krl(pbL`+`r_-Bm^L4qjOBRS$g6`>aY$PY*If*51a zir%@`IJF0*@fMoXJ(d7W%lbJMdTarhmim(lqU6Putn>lye>yKRU@>Tn?=dy~D{=6j zWBR`jVWhmYWFJ4g_uS&(e03Sw6d^ODNVPPDm^?BdB*f;QlU6Hnwz`dkPgb~30H1_r z>0ID=LA0by_xh`E%GuG=8CEyXB#skK24V)WB2*Pj?iN(BRnL0@#ZDJ`)e8H80E8!w zth)hVH6#LO^jLroW@>4RKa(Gpcy7uF3)%Vt1e}DLQG*g8I;cIi+aqF@r+!f&9dmlY zx~#%U7X!~xygX|<0}DjqYD@hYP62CYRpwwY^3OF@6oXI&v*T`0vU^bbE(`98OofC4 z&K+6C##c0wmKhHSt*t7xfU%3o^y+|1AE@35mtB96fF@R5s%p0YTn{jgPP#Gyd^d`|I6~{M3PPk1n zu<+VMgnZ00VbGdFH=)pBOf*oBL>txMPW)q~NU@w=B(E&3saR>8uONR<$kt|c3`VRp z0oHYl7>XLX`5yz4aaFi zlxDPOQi-ajSPLSZ0qj`5H*@TF3NB?P5w3;7 zjaY^rJVl7a!tqzKHciFLh(Dfm!OQ47z1eA5tW0z2bCOJI?n?9!uqH&lfiY$)Pjnh^ zse9YQx?3q;8>Z-~dW0EXX^GuZg>oU>MU@{tO?G!INWF0^ZvaScf(4GE+V^{ctcxcJg%qFZ-{Xvgb%8-A#kRY5^T%?|Wr5Z$F%Vg)!+gKt<%|&iT8TQWNu0Ueo^;TWxnrSGXOXs z9gGa$+^MO%Ea#Pem2rc_s?I5$h<8^{{a&VRclriG2~r)*^P&OF^O6BG3KshE=aMA= zU}HS6Q&{H_0%0_EkJFq6(r+fnndsO}aOE8O3zK%Y7}TdvGWRFN>~M!J7-&{}9Q_de zk68qxpzIn!eU0=huIAqb9qG;>MQemZP~i)0Bc=oGP?F7P^`M`~ zL6S3{9WI_7?rraYf*-Ke+azwZEsuUnqKZ3Y4g!kXY!d}{rRP)JCgva<=_OJ-q|bUW zKO*kI0B1jpTgR)HUZ@M!9jN!x2yUDV&E4KJ@Y=u5|4UixUyf_vV1aDsdr`3Y&L;Ey zr{nsUh2fu3t+I`!&3FII|0Uq-P##nG>+pnUgjk=E9~}NBFob*r9(*U4FodwMP#IYx zuugA@SaI*zC@4)TLHAl$OAIBN6784o*Y@C2ZzL95YfU>(DkOp+iT%#u=H=Q`MyL1X z#Qw+CpDTcUdrbl8JxEUa8G-T)`uN`cfu00E^KoH&mM}|bhn2l7+yQK%cLdk5);3Z= z=u@Dz#SP=|tPU%Ph-PP@Dm%V6~u~{Bd5{+Nf;&Sdcl^j-Q}B-WjzV0-gh=ix|CQGO=N2s1)Ui zvqhJ@hv`YQI{V1Yjg#7n=l*)jo)&RpK(gmYO?R`unh#Q=K9VzN66_FDvbKzmH@$Uq z93mye|L`cVWv=AZ7%B#xRi3VG#>IFtW}5$z4Ku`>-89d!S&LxM*&}io-K=wBFknOP zzCPt+u5owSw5@C4p^(x^q0leF5YhNCH@27&ra66;n)gv^$bqyQN$D{|Hr^g)L#%X< zUn(e&9HtK~Qk%0&ikja%K>su~*F(R6yaq5oho59EYV^9piWa8NykWrQ;P z%Epsc_edr1@gs7u@y9|f6@xHdFYK#YPz*9muChYI@Y6iWErM8{H*@Vr1Jw+zRHv>X zSWH7LPe8*tZtvEvy3klkgPQBpg0~H4cRZFg!lRiBe^hzC`{bbP=FTL$No`aOJ_PhyaFc znsAxhKIBkCR139t!^vG{W%p2SL<1`md!CB-f6Ge;7B--nA_4#mepiJ5|L3Luo<0A} zORGb3OS`R;v6I50S5^yfUyZ_uk;Oy1IDS)Liql^<49?)I8~WOidk^f+c<2+dJp+ ztnOG`J-fMTblrS^Zb1@e4wpTgg?;sTdH>0aH*!>s`9YKXDT8;mpR34up*LF^s=kMv z>13|WiE+NT(x;QU$oy!Ykv_zEbfVN9B=f>8xEITba#O-RdF01UyU(=Gq_Ibs344u> z7rkK49X+>PJx7dtwa0Yu1pFd}945}G-52kzMNMQnVj319^>D*%HZte!)ilWD1W6yh zj~FTGTxRfSpW1M63o#r9`Jx2rPr1XT$XhQg+i2s0o89NQub6YAm5J)uIC$rzF?z?M zlVcw#Gv<~n)7UN+f@;|=TzoeGDe2rQXM%dyg1L0+R7lJsU)EXJYB zi+1cqP#v@R6H_-s^vta=`i#XU=8_VjWp&6>_)5}ioxE$w!mCt96@1TG3%}!GH_Z1Q z5L5SXk91`TG*iPp|DN^5tzPZOA@k2Q3TJxz!q7w>#QRKM{XiwJP5g*Uq`y?ZQ3ZH# zrJ43{#6Si5T#9n$jUMqjdNgRCwR3Eg43otmk$mJI2I(p$!^JSWamXRRn{64Y^bm?I zoy<-fuDNE(zO}wsZGBINMvO@HnZag^Kg_TKy933kXL^)&=&(#E3t)x}Ax);1`PLSY zo~722n)05^MfL&a4VWB!=#c|hZB2sJuuSWKpkoz_V)LVzOU+EizN^|M^P@50+{0t& z-M=E8EEzIuEgn`;$}yXm=NIX=>RMecRu7Vy>0eZBm|WA8wQuxFC@mV*+saka?afeh zhM6f1sM;#HMhulOojX<_($)v{G?yb>f7bRLq}GR@XA>~3s~9t>H8Ubwms^CV(GZlE zaUfSnoLd{yTdj=JY5`_}n2;l{DC4bLHxiEz^kdZkv1IMgjUzXyWy+VYD0TWGlfz-H z*7?U$vNZ5w_S36nGe`?klqF@MMWkv9p;BLJBSVAjNv3F#6rQE5JIA6*vO+atwsJOU z%rpvu%Tp0en3!c^z>Hq?=WuP}24E`k>f1J%3VVr5R0l{9((!r5jLcC;rW__(VOtH% zTFHm`NT%`I4O`+qL-fE}0c4K3vT2U^_TwHV7syxolGgR@gfb=cLijLDV9a99ff~a# zyH(mjF@j#|{GJXY-czN%%IWkCFhQE=T@@2-8bgNV=rJFzX$Vnz6Ii5^f-$v0vR_K= zU;z8WX|1CQh2*ZoalgpK#zV?f*2)zhd$11^To9L_&SABx@9ucZ4+{7jF&4QT25x_^ zAxQ z2Xtm4ri37eEclAwiwpXfCTVHb0z=oCNsYO4F*HuAL30dy%^sK2L-Bi@PfcR*2u&r# z*52C0$aQInLz#lBKPtG{N&81m#F{M5Sm_bg72|6YsOpTnQ5dL{hu!|TG&Y6F4#FTd zNKJ$^t5D!EPCfky3LiBxl+1J`j_+HaFP=PBqC7QmtVao#PUmtYox6|A705vb;h(%r z1)@3{8+8n-caWQjGpglR+b8)ou24pe&f6z25NL~Vd?6@k8{zabUA_+@DjK6dPXQg> z32noATA+0Rbh}3?U>zEwM)x3Re+op3iC-{V+Xg4>?U*J4;5L4Iq8h4WlnvW>EJhd#C`w{z0 zL)|-a@C~{%sd~<>t0(*54CWJi3m{`GipJk|A1K5>4AP%(itW43jDor26jhyV551&h z+3jU_;sA837Yw>Hu}kmT`u(TB?GYD%8HuD}Aw<|fqA}>!2w31Tt^d`b5P&rc-5jH2 zaKE{GXl>X;qOsT*GrP1(`dI#q*!*^1-u-fqIu>-Jm>|=mGn~)Jw&x44{}tN*SJ_uU zRkd|((~WdD(jna--7TF;hop3OH%NDPcXue=NQb0!H~;ay-d8Wz_kQ=^W1MjgL)Y`H zy;ttJ=6t3gcZUP!Jt43DakuNhD%~Ux1aDV_scX+_IaIwFHYBT-tB3NMj%t&3#D<2RwFoMXZw;VowBD2SQ>?4 zBEuFOjLh!XUPu(IJMrh#J`usd>1#&tulr<87WKwt8)sKH)CLvu13TT2tq*rAch^EY zsu|{2x33|5?rxl*63bf7K|m;#HECesUK5$H_hE&xxXbUfdl8eCih$17B@&@FYvHk% zDEP6P(z$%=WyIJkmQB6N<&{&xD(1M#cBhQO>&5m1J|&(Y}fGe`U0Qwa$Q*M zw3To`R$6fsT7zkm2PNR$V~|=D{6k4KUyR^I8xL&zfD2Z!FG+S;tuNiAdYN42w~N9< z2Fsp_FgQ3`aqfK5ZMaE!u*3S1Wt55jnWr2JWj`9mcw@Dx!qzI0ml(9EgAeU~mANeE+%`A+iP^7s zhk53vFCy`vo5I(>O#%>NoR*t|_F@L)LXqCu0J6r=jP8KyExRLX!=gnWcFB_UMTSq) zIG!@ENc=}mw3Qn?!z<;+R?&@53;Oawf@;nD%jEX9iJ7YC{1aM)stg0BPc72SDdWQj z>x+x3voos1Ss@b2>~ZTaNp>ddDmrywpN0+=PErl^1rjjTT4#rF`)v4TssqsB>Q$RJ zwK~FROA!gmt(KF@2qj3VCmG3SUDdxh1u;?ES1u;C<~5yzXyH1g=c&hd^WuvyElJ`k z5qvT1mA`;1C|^KR7(iw|^DnW|XwmWmcsXN0vk7&HLvB%j{>mB`;$FsDI5c7(%#+_C z0}87&(P)+SGGRU|s%+$fKT0Fv1^nq(B5O9iogrBvWArMLQ3;l9zlwRe9h6nb-7G!9 z!T=xdP~3WgcOr(w8RlbWC8{>e39bjPlR*TUr>KM)R>B{RdXl++D z)4#G&g(cq)LnTb;_Ik?~liDGmfbDeo&V*Vi)t||VIR~@{kEzx8Bn1vgZsa=(r5cw_MGN$z*5BBh1DzmZZ;1t<39~ zCqNqlVr1(6M<5l&+0eFW$n<@N(TIet%{xSabD{{7@eD@qQ?m;`41SK79KgrEPz)|r z*{!DvQ?dwFdc`9Uq5BARTXj&r`qX`n+2~vNjqrRF6vu&glkGx*U*Svj*S&0kJZ;YG zc#+vF1$hNEPZtv@K_`N+-s%1WhpTb+JVDnt&hB}ZW7pWSek+rLM)>RG_i0_wJj^GE zn^%)LWNMs^Yfvj8YwP%&-w?wfb5}suDS4P{`@UUWjxi(d19#dA%k5r$r8~^5E^cKt zK%y{&D&3mBzus&UD5dSpf~_b}q~(+xZ{mS|Q*q(aLfQ05v~Zsu&8rD_DuA*)9pqTC zH$)XA3%lHG;piayGp^7O=GvyTnBx3+GxRb`Qq~mm$2+RqLYPoP^pU;HF9O`n0V7fN zreUK;-!eG@3dW8kEij74fU(jRRtraHKcmGc@d}+)Qr}0r4Ht|vsqI0>IR|ep`ad+f zew`W=HKw%vB(B27;NhExkQD*ge*-7>oifVMKLa?mj~d1iZ4dC&e}C zD|tBApiNO8vTSDryULH$OML{B2OQCl$ag$q6&Cv4D!cEmm&Idtt(`$yMI+4^^Z1#% z)BIksrb3t~?0h>X*~Jwc;q^mn95XFWy5P64$WoCgpPbB?%%fRG?gDnZHq+5AY=I{lC$srho`453`HGxDM4l%-s+6^-)$Xj?nvAxV%ypsK1*HSZQ`ANR0SR;`!&yhrPm4vLI_)vG#%>?*dyeQp+-d>~GrJ&A zur;DOqIe8zP4b7OnYJ6M-i?^GQ26IyM;+?%O8G@87Cb!$3e0zDt8hfcXYC(niT$_Yb@RiO4%6j zl(Ka_6lT(NRF`jA)DbsxDGT8g!__&i?YKwgyB3$P zK;%dYBFRUF0lhB@6ED#GMQn8%3Kqo#MQ?e=@ ziH5B%;y3TV(rQ*$l|x|JtLJQkRNX_R)k1XSzL`)y z_aY;D+k7ZdXeEoz;~8T0saIVyI^U|;g-=-2{sQVXYoM&fOEMe$_sqUPUR71 zm*afYT?c|OxWn7=5^~XRG<6pc7U$tJ<9~|)R3*Aw4;^V9V4y!s{`ngyd0a!$lJH>= z!gv{9l#6|sC{Z!Fe8}}(VQparZ4^*i-^SFkB)=ki^w)*xvxVyIh&N(1ljDMG-Ox#5 zti$eXKzDua>Wd_~Ms#*Fkf_%=8&^5Oid4<9+J}6|z{{|3xOCIZAS=A%#6v!!-!$LKKAEwsH%sr z1uSNn6qPZ#WKN7I&TEQ@AcB2OzYcJpKbDZV1(u+P;tFduln3czWG#hpX|T-$jBA1} zX!AVASKj?bW7?(n4L+BRc1`F9c9`kD_Pq0>S*`eI!p6J-mk>2L!|dyMBxs8K}P>ke70P zQl!2O0&vJ!4N+E(KOc@%XwAHigA@cC(?a4Gu>D>Mje{laF;-=lN~n2fF9~FUmMQIu ztc#f}*{4gVTW+`8mGn{`BSU*YX2psi-n;GOv(%%-Hk-SV!``Pf4`4p7<=9Gahq4S( zqHGjBWGO5n)ll)%QzvaRZCq{5JXvu}1U-Q+B&^xh0yuC7hI2pqHdQaWwLvM{da3pH zt_2qoSEW8@SDsK81G8>7#x^g@(@*vKt~e_?T}S>WJbjCAy^b~@Tkhq$BCfC533v%N zF!4Vg>tWedbX`MxkUKe1gr=Wf>0m{y8cE%q!Q6vfNnVo{J1KUR1JY5;l>oB6Zh5}P z*$VWH@%<9-muX&ZvS%+VV1v7aWPDJ)A2oxd5kh`GquOPBP}$eV%(QHjaO*y7Z`(|k z>=D4%SkAw?H&}7YEu@8%EQu&2^vtCaIT~mwCWSuOq;SRTVzJ}p75Lbt~)`taaQ#D$TTW#P{ zt&{Zd^^&UsZq}y;BAE@_AzaQ*BW9SWP#3D!r!#0$6Y1DoISY_Ag3w(;wogD*RI+Wem#H)9RbU?y7GjutCrHVB)Jy-(!8bSY@%}zU7OSC z%V)QD(7F`wK$Sm-@3LX0Y<)X5R%bVcxy(@Mgl~w-BnO)r3aDDBtIb|Cy55VpXG%d0WHM`FWRRcI1wIjM9%!sa7*T;^!tXC`V*B%RWX0eq+6u1I=zKT4lNSi=PE&&6&mu z$DWO;!+)9HGi^xh3|cPcsL-iFb8mjH)U^UOr5jtcioA@}a0z;8>J?5}7mk}Z4Q@3& zxW^A7J!nFBo`*r_=GC;`%4p0yHE%+jZ-zNpFlkA5EP}VMp=x(-hUVy81k-9s!=0J@ z@~|MkI9@w`5zBu}ox9DGtJGgR6^ch>Dae;4$|+)}G7ip&4dccDrMo@9qmz{V<SE4rlTd+GwX154>%e!JXIz``MoXyfG!3l69-dGXmw-(bh71p8H3njf>(3zeaa)80Ol z5*Y%~(+KESmMOhS$Z$~^wfRi-a|8H@vi!)hF&FujYAO8jj_9rHB@RAzZI?svw((fRyOZ85Y=QiSWU$x9kG>S3Jl$j{3>uSh^ct@cPF~<&zA|o&q@Xq6Jp?z$#LpN80Va-9SxjK^$ zEZdm6dm@obL+G+Yg$RUIeW{&S(kfQzfmR38+Ts_pZmx+Of1KtB z`Gj=zhUW2*qa|d~BjtmALRA*()jJf6UjFC@eDF0UZT}}9s^0#nGoKFIam;JAMF@H5 zB2ikXO6e++7rHf-g^iqwTCAYfhWrTxCpCvByNqgutBBL}#~G?}Ixy?}ew1TAFbY-y zDmrjs@20*%`sc6FzuqHN%6y`1=mwdD8e_j)wo{_BANc&4=ngI#+BCPzE=h7G7i#KoRQk z!-z!3cta<*>z;%^8AXCZHYuhMKA7I}BommLW{&@tK=!6k31&Hj=MyuwN`=-UxqLY6&UWh4aJ5H%B%hoPt!U z%rZSCDHWa_^69V(HQ;z$#_BJaAaw}GTTvE8iLfBF4x6TML__Qw*%XL_Q9xL540K^E z-99ylW{l6=Mc9f+2RPSpM0z{bRn@txx=>KsSV_HOGk8@2CaFvVf32wM_$e#+qWzD4 z05`tR(7$y{`lShfobLZ8R!qd?gN?0%o$il+{^QWHSNYqUNjbzv84ai$UfI@9F@~nN%X#$Qb_?_KRW}{x(Z)~WxA!G ze)^l)W4RxxHf?3d6)l5f^leesSQq%21`c)biK6zWn4a{B>JRSXtcq=PFg%M|{&hX? z6&T2rvfmljDF;WwO@!uAiZIe)z`&@5vEO2{zX(`AH$!} zgBD|~nQw7Jqm=G){*tU7v+_BrrDT&BYf`ROvqf`ad*2C*^=36L3|CeY3*U`nsfs*b zLO>G3V7jf<90lVz5*Y5A(dk-hcZgc=nlr|xWGI~voR|6tLm-yh-~d$&Re3@0r&` zjHy=3m4gZuDU=8>H4c5<%v3MMLXa54b~D9Jobh6Wl1xx`H&U#;gi_7s$*fSU10<~I zWo9d{MN0}lSKLUVda^@Zp1cb6{E-4&+8&zra0~mzqsm?vIlnN*!=}a#PlxO4*JFV; z-M!m5!{1ovr6-rA6=D2ecca1iIjlX3xnRtjm~U~`1#(`3X~*$He&Q4Z$hJp>c=nF# z6JvFwH4TeActSV^l6j}E-h#+pQ}1bBd)?kVrXK?`w7iJQBO0(DZ>WZ}PFy(XY{rF& z5!+i)VLiZYSl{;C=TQFwTT^WSHb*^}n&CF?#RaV?%GTJ~h||+Zu|omU09_xEeU7dr zrC@xY^R9R3gtX_XnD!!)x5n>i9gC{Nq2OZ}2IXx!0(W#DfQ*#+IiIt@Swj6x|T}r$Vz6_#J3Xhj zCGejfC1pPZG-m3Wj^ltA7A<`+y>E=f!))%@^VXlB_tgOh%{NuS4LFeegnb(|ZG~42 zLnc#PmQ2Q$pmveaKf65BFe)7A$*fY}m|Sf}SKoc<7_N55@x(|oAfP~nZ|VpZ&5hk9 z?o>9;$TQCDhQyot6*G)2FuLF0J>>t!`2i$)Co2vb;XMnsD%xL4qTeaWUm6ji-Dg z^3k3z&k-uuF?3*tDC;fK-F|lY7}W|9#Y+*6mo<|h+-15`+XUUUk;PaaXwlk<+&!1| zNb0Kgh@yEz-Xd}dAYi!>_$!dF?I2Ac-FsgaYFQ^Rdz%(2W~X2G7Yg8`;7!NRPxn*e zpA>(yjec5>zW7M92AR(ly`l4AEE2bui~&vEQ3T0EC5GfobSG@p&VhO>l8obJn;Zeo z>8B-TLsu+YBf-8m6x2B9tI^(|1(gW;_j>VtH!s4z)OB(Y#6CTXW7crANcadaNc1E9 z)_3M_qu@tGfyx&T92K-jk%fT?p-QFx@Fg;(N%lAc4u6s{$HI^eGHKieN^5Z|br_WQ z#Ilh_AIArRG$bT5$NX}0!IR?Lm_odAn4!sd%s>+XSvb)|PVYCs8YMpgX+!J}VQfoSt)wFz3y;@#`E&_szN`iVvYJu_xJ4a>rGYyNwp#^3!#=?}6bLK(dDq z`c5--w%G%zg&}*}gA9pN zr!et3BXv8ro-Q)>gSN4jXMs^@%1r%06CR4hp;T8BY&dtQoI8G9VyLj$*_R6B^CB{r zHc3*w6H>xN#Y_^fK6qMq-6p&Cg^@%#)J`i-9cyQJ*q*;dg!seZQ? zB)_r0wgruiT%uYE?LHsb|Kdm{#-&TQ6AQFN=DPRUFzoV@(4WMXd7?tIOx~KE&*S{? zFsLRJ%s@}lNVspkPL2Bd((J7q@<&M}fOC3SS56^pmQM_UEu->Dq=8BS)M2rGqp9SM zDW_FVQ9MkNSZRq$_^z^_`UFSRmyBZ&YFpdECa=djnu1t$K(-0i_vhouGvL$3jguDn zQH1z7Y;o_&o2%@=xpd+r=3Bb!*;`xn(erCaOTS(jiB?qkYOV%IgAhQ~Vd363!V3X{ zJDnkG(OB+w{2Qaolw=?Dzs%M&iUTc733T#vXU7%Ilbu&NOc3hm&1DbeVt$oUlS`k?%IBtF8KFy#u;Ser3^VVkZh5^ZSpqc_^Ux5_A) zf{%mn>+IF|YqS87a&Jm0>I9&h2Nq?6dy!6ZhWyp~Ydle>rOSRw*a z%VZOm(%)3?}Yna4K(Dfaw?;>1mvUM;};KqWn~~IN27kU ztyIKL$~*il$#(QX^~3E@qy}VaDIPbKFfItanT(NJ@E9QgOjq+#rn zcUE;+El%WPK6Buc>WV=OsAF}q?(_qS}1nrFl;F(h7>pEHk@Q=)*LhGwW;K-Bnc3XRZPh}ghV6J@erVWH2sc=%D(J8 z-V)9Ru$FxPK}2%%I+W;hwG!<6@G;6))Uh+F+#NZ>@9v(mIh#KLv&tZ1%Y6KhqL z4Pe{*TH9}qv@0LBIHZpFGIVVNQ@GkQeZ{*kUEwc`;T?8h{OZCGbVnbeRZ)pUx9;BJ z3#Uycp3QBY0{lg6O(&GdKYu(#^qAqXKY?_eJsi<8`WnUYqdk6Ce`+}qKXCXu=Bii( zl5iLFXPA}4ksR4|afuXM*JuG(Z)IN@kEWNG)XzJDxEv%q!f|NvMx}WAW8EZfDR%ZL zs4^dnl32*N(ZP%=AtL~}cqT+}8DDlOqz_Hzs77LKf0~pM2;AvE0W*P}MWU%0xduzm z?cv`?a`omS<~MJAOdd!<+h@Fm6i~e|kz$AGN)^TJ=UfDBLopw^!dxRsxdWPWq~9me zkzEGA6zAUD+>>qt2XzBmP?#lJs(oRS{;84)za`jM-wx0S-No)OoMKr8`4(>~14#CB z%UjP?6Go6~l3zgkWEn8IFJ0aop06pCT-`RIaiw3HJiw7^+iTyWW%>Gr8w+wavk7gh z=bw3Wk1XsYN*;x-XqFJ)bcaVz5H zS;AEUwrv7vR+czxols#JX%>D4juIJP+srd)Ri~v0&ioCc2?natg2S zI7_*syFNTvr*NC2%mZ_2SC$fN8x#!BCKe=xv^nwk>pSNg0cgAe!0z@60tkrv@4MSy z_O(CWIi*c(Yyj#zf9!JkKN$TIKbRV;B|G^JAXGBS+En^YKZCH15#wVkpy0W9LP;=9jAC-lAdZJncn>u=OORVrzLy9D%C`vT(jQ%Fn?>a98Nv0(As@ z7BNIshDsFa{3Z=;Dho3Q`K}8&F>6(|-NVurIByVMygY>UnZR?>XAdVTdVN}_1z)7T zpC&9SOGT=*VOeiCVK(a_Dqpo3e~(6&q^TH!QzmUO*huS7Uti4F{*n$WI?kBi%#P32 z^K$mVmvn~K8k1_Aab;Sj(E(u+o6sPLET%b2pw`GHSzgl!sQawVe|ahYE3L@RaA->` zCRzAKSB8bE%VoIxXk-YZbC03=rC>MVn^V?u{$6N!Sj@?aKpgCmwHANUP*MJpo5#yQ zouYVjrlHGaK7XkzdwMB+J$CnOJ%5`9!6LR}Eroa;!zv!S(7jsS@;umhqNQOhlUvVT zA{7%=86OgGA`T)>EaHRLCPdC;r~5#eu5097cRBt8xcc~HqYjwwjxwtd*u{;q+c;#R zz+|IUMP^Mx!N+oeioU|y3AM2}!hC(>VYW^IAMVY>{>|E05@bX$SQd*g@yW{y57e)a z^W%|ugDn250~}VXPeA0Pu{nsJFzE3;Eg_)$NE1GU)(P^mZDLyTZG_=YHlSvpbMx@Y zhmSti%f=q=!|LuA2TZyO62yZ@>kxY`5)D?YRDf1I)ah%pDa|cb3~F!W+JeVu3#*MX ziL!uV2^q7K8YA7HQ0su5VkmbBPcWSeQC&U@wi6sj-`WFMU0eadVE<|a2pAYzelYkS zW*2h>6cto=iz+MYYGX0@*t$6}A3kj;{$f5vSfohgAoGu`bM?}ylhgXMU(AX;GI=wf zx<+bz;tDS{jBazEvU#&6Z5;HV$SOLm^WGi~HjeUaH;$&cTs~eLS<(UJSikL48%oVG z)E2?C!NtNtMmL~YRR@x67&!?_ps^`|nuEt;ROXn0s2H(U=!1A2%Md6Xo)U^!$9{@i zk9B)+bm464uR~*`9;?{<#-UifNOM|2ty)gDgjlFvx64)y|Nuqg=mngb`D(Ea%*Ddvg{wh6v8nOM1w(0>hI zQmrwLDNp^h2zmj@qNEfiQS?ruN&b_qdR|MR!!_9p_vs?2UC#UQdL}&Xpsz0$!IQQS zq!n5rEI9B@W2ja_tufZ-5UB&eLKWw>^?To_*_)fgLMWwq|>MZy|(Qz;|` z;^H25NWnIurE~{+>$D772M{?CWA$z|!_=LC_s7Eo&*=m@iWjWnx9KKah1$+K8Ye`A zz53*MSU?JnK~JXYHi*c}*-@orGR54j?e=CSDg9Ak(jX@h{S(z1vBiimS>HF5Nw`j* z`=NMzV}s-kE^sOdV%@~GqU|Ww2=+0nEAX}Wz3y1HV#rp+4}hganf8D_GaKDd*1dCA z+bREBWzdE7GY==5VEnf?2v<&@!=@`PO!wk$#ZX5DA*l4xh7B9$ zWG06{s<^@lSEgSm~_)dz&@_8#e!9%|zA446r-P;j5DmdOEx^n%OtE9VG9Hj~4A z?Vw%{KRR^T{mv(*VK>M0`AOX{EkObe0Z*-dNPV0q& zqOElZg_yDxJm==U?p{Y&wq$ir%d@0(!lzT|Ho{q1K zi152%8-yF^FVe+dyGlQ>Mc)(rbrq#WGxmlAtfI|;pi;(vvx@$)nEtYM#wx5>PROA? z%21-h+H@=`GNZ8J(zEWlGGR)SBqcAqGg6kR7pF}n)Ov|wHBb~ z>Kr32vFF*v*ABfayQR2&?IN-Cj_@8OliOT2#n5)k&v&s>F0aAvkgix z9zkP?FDxYrS#ZS;qHWvO`$Tmhvn=wfQvSq(Zt4pTN6Xf?VP7;$Kp2^ynyC~B`1f$9oL3bI@H<$RmqA$D#z;Knis}40jlY@Wq^F}4J)uZfxODnqHyrV_UWX+n#92@vz^ZvG zd7!XfYDmMnIPGT}X9~}0TK8bBfVHe7UeKdEx~$lQ=iVTi(u#&}>@ zd|fiGFQ+u|>nUpbIZHZoS_X1HPuNDiRlETf>Ikasm=W)>rNE@nqP(RN%cSyX|uFRh!e%g5~mg|0vxG5bDWL z2jUhyrs;TPhTgcRKWS|OXPi=!nS6h6xRSpY?e4(4WTLoq-gjf4EtYgK3&r}Kr@712 zmvQ84DH+wR-*>%6OjEq0C;$(bFcLdT1)H$D1eN6st8#HA=0*Q|8gv}R5z4FE8T?;n_rgHik@ca)VLfg0q0D+C_mZgx+#_dGl?$KZT3=fDe6Xx zbHjf+IM@v%BSxDD>0WRa7OH>wVYx)}eT@oFl_`HAR~Gik)u4)t5JxOg?kpx^+_$@% z-smRZ#U~&v|4V~zBz}dUstdZJVZQk-0@C^>zq!0OeQgWprZcdG7A#BC7UFmkgkJg} zvXy0eK5I^I!wuFnn!_zQ+TgwxPV?YTx*-;AWP_1K8j5Lc4_8=sn>4*Cp+)a@q^rfm zzifw2!d&=(-Klf!Z;Wkto7&09Bj6*lj?SY7uL&*LtTUgeZ=#O)wgK!(>P0_PDJa!| zf>>0#F{l;JhMbM?sZanfk%;xXd@HYnOW>wUBy}^FlcS}kI36E{%+!}78eeQS(}>Dy z+XP$&Um?*UI%iCqxTZe}c8D?z^+#@QBy6G#oQb2}pej3&k<`psU?aU*Cdm_s=4uec zC;w19u=;9zkT}5Qt4SdqaaveldyZ77*@w(yyj$XjSM+mxHy2Fi@AB26DP#hMqdz7q z)3dP1uSr*NN5@>mF)cyZ!t@os3qNJxesNNr0Beq~r_Y2+AOM{Gm4`57ig4*2ux#Yb zGaZY%jtZLuKwmEcyomgN^mTp*oew|ML4TP|OO*hspz?@3^#F|y`%1J-_f<$;q$X4t zmVta2WCjxWq$%c3kNN|3jQZxS!Of(H3ug%f2RoEk>CZ1&Q-Q9&& zjt#D5T^VLgcBZVPpj@Sf)2OnJ(|H4OpGvKpyZlHW2nz=6u^1z?Z{xn1wQLc~QQs}* zx3nFw=grkLZYTO`yf|Q7NDq2^-}GrkS^Cu1BTxr3k?PmqpYJ@yV+D`5o3b8f|ac0f@31z;N~X4PFOyWcrjnw zt1uEt^h9S=xQ-8sN!G2x#kHcn)Ub&MZ%<=3iv{7-`nVcK=jgXUdqy{?xSP8tpPzW9 zK78J?--WBS7=)rJ+?Yf6I2g;b`^D_4AT{khH*S9DIL@1V2P3fV54~Qt>aTc&v*e5; z{Ee%&2dI&VC0Na+j(o88sfk703C3mlX$#^`X%NDO340A01S;V+3;g$mGag7-hp=($=W@K+<^NYUG7Cn6iXe_~P6I_wg7Z z~A z_lJ2sYFGl40o70TmMOcoPTib(uj{Zz334{pJJ6fHp(6Lr7CSF0QHYUg?|max!!fWc z1%tRG8m+h5;@7mryCsy<$CF!#Rk&efm^ntB1>q%OpAL>~?|dHb+e{Bxf=B?mtIS-2gXD+K;1@2e-^mvI)Mg0$~G+&(DuS+A}^2-fKV)^L+=2n6qd+SO2+1JmagmK@aR}KSOWC1V{vHfGK{IH1pvFHLUC04%*o5d>q zN43@6Vs>1f6Vp=R7+eSr$I`%)5DqCt7afB>k?2GZYnWzNeZsyceGOqP4mEt|L5@c}xHNR0Uy+lx6_2l0px95LsJ7H7aWT z4pm!Rb>r9$S{ND!S)0k$95ZgsoRQ?ijT=OzKEWQG8(Q~-Lvk4C(oG3oLJn5J9LwCk3a;4Fn@+S-2_u*S#UiiGJqgkR%O!~Ixt6DTCqgBc^pIKPUGAReW zFjgXnzZJ99(8S~vlRZE( z$<$O?tJFDMXF9|yj8LJGbz`|RO8YE0726$VZK2DqXsnMG99r?kwQZ#uHLBAz*%65T zP8qhHg?Jic{Z8;pyiP}7gX`?AyYEqltaovEuZ~FEW4C9WbI5hV|Bt!)%u+#L($^wOO_@bGx0}p%NX(WiJ68D5{&3MW(zCIQ9Vp z_BlUXm$3IEijD>H)Zqq8=cAI}xlbL4t|=QzA+iQOf#niCC2x8~bTDFHFw+a0bKT}* zA;j(DIv+d}0*1jrF_sF}8PSAGA0Xd&4i)hbQ?d#zzIeuwrW@*-zoWZB5|n7pxm0~@ zOYljcMND>7Gs`G0jfo;ZN(C3ev-F*b6e7o2u6VRB+%=|O&-)q}oe@>rkt*N};RKQ{ z+%G5tch@FE*WYOH$2j?&q!cKtK7PTdA&wyqli;nAzvVAf?cI5HA|5$#9>)zBAqs$P z>2Kz(Kjm|Nu^m2hIf_;ML-Y?6HiWt^(7beI3}G|dcHwoRfEd)cu|N^hL=WIlZr1!= zJe***N7qUg9rJh(!D~f=VrMuo z-e~NVfD;Fv6COC8u)kyPg{GQ8;MQqAochv{mH)K=x04v1@?qgYQwL~qHrIu{H1#f} zJLrN>qlccEQ^$UKoLzgijV2CS)id~FI$x>|ubks%<@N1WxV8m8$Q#Zz3|-Vdr628( z3B@WGYm%}q;lG6IZ|qC7vq;n$v>B>L%~Bm?nrptqsyE;u@D~dq#hs|C3-m4%pLqXj znulf}4B+3g>aFu$yJM(x1(E@^b?0L&RtcrwHx92l3KM;LZMRCNw@qzqW0n0@#k-to zqygS#`|nIxvpz%G5>S zzD1M0=EfioUhEj0qeDi+D4(nh2|M1JE76461{1 z800%_>Kd|sU{&GZ{Uu4UB%17zQu(y3I}zoV%{Q=75g37Ks1h%Y{oYvn&MiZo98JPd z>+?H7mrT09EKtPUmZ74wOkJ+%XqJ`r%~Ejm4ER_)5(Ul9O1_QR&zsc8n|DqA^}R25 zZ#AE@e_CaHukyS4r)QHj!c(^jDqxZZs5$@<06ssY_W`nZ|17(|`K#DIFbFCrAXgw1 z6i^Ys-vfa1Uk!VJBi4@#5$J&b`%h_MMSfaw84-Xu=3k4ktJ(Q~{~yYL&-WVrdF6P0 zSMd68F=>7oaS>q!#aGfIzanHjBL>(Jeq7&)Qvkm$KN$Um^LYt?_41bz9f058OZ*Vu z|0gOygu##NJJq+p7W|RJ;BU?1!G?>0X;q z?*Nu@>=%DHE&K_Yl?_bcFc*T(0W zWqtz6>HY6KGtW`Jm-^ltzh8jS_~ZJ%nA`zSerfXWVzkc-KTiSkXYm{_D*e9|{$)q` zmv^r}44!}QLf`N4c><1~1n@@xg5dAzIG*3Z^K1t{34l%iiQrd1(dU@YwYGm^&RYHx z=8vcHuavj{#`#P!`6s8}hkwEOo4M-y$CTt=djQ9NPog+IsOgy&)2JeBkB8`=(&F2 zPa+MszY+aX{~!J8pVb7PlRcMP`$?AQ`G1rBel$Oii~Wfy6!U*$lKfMY?DOhB53u=3 zWtjXos^@!`U!L9n(e}@SK7P`0r2dWO7uX+7^1nks{&qjl{MdgIjb{9f=s)QH%d7o4 z@^jzdpUBgIeb4jJ_dS!>ugJe|=;wY(KQT*-|AzVZ$MO$eO3!Qm-2dYzQ+e6HVEPAd zkmpR#PlS+Hz47-s$#aX@Pm;Cvzmfbo!T-{$|BpH3xfSFm iyjj \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/resources/compass.svg b/resources/compass.svg new file mode 100755 index 000000000..fd27e73f2 --- /dev/null +++ b/resources/compass.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/direction-dot.svg b/resources/direction-dot.svg new file mode 100755 index 000000000..14ce0bf7f --- /dev/null +++ b/resources/direction-dot.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/dot-arrow.svg b/resources/dot-arrow.svg new file mode 100644 index 000000000..4c2841a54 --- /dev/null +++ b/resources/dot-arrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/resources/location-dot.svg b/resources/location-dot.svg new file mode 100755 index 000000000..24addea3c --- /dev/null +++ b/resources/location-dot.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/resources/location-static-dot.svg b/resources/location-static-dot.svg new file mode 100755 index 000000000..18269bcdf --- /dev/null +++ b/resources/location-static-dot.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/scripts/exclude-activity-gen.json b/scripts/exclude-activity-gen.json new file mode 100644 index 000000000..0f5bb81b5 --- /dev/null +++ b/scripts/exclude-activity-gen.json @@ -0,0 +1,56 @@ +[ + "BaseLocationActivity", + "MapSnapshotterMarkerActivity", + "MapSnapshotterReuseActivity", + "MapSnapshotterLocalStyleActivity", + "LatLngBoundsActivity", + "BottomSheetActivity", + "MapSnapshotterActivity", + "MockLocationEngine", + "DeleteRegionActivity", + "RealTimeGeoJsonActivity", + "UpdateMetadataActivity", + "CarDrivingActivity", + "MyLocationTrackingModeActivity", + "MyLocationToggleActivity", + "MyLocationTintActivity", + "MyLocationDrawableActivity", + "DoubleMapActivity", + "LocationPickerActivity", + "GeoJsonClusteringActivity", + "RuntimeStyleTestActivity", + "AnimatedSymbolLayerActivity", + "ViewPagerActivity", + "MapFragmentActivity", + "SupportMapFragmentActivity", + "SnapshotActivity", + "NavigationDrawerActivity", + "QueryRenderedFeaturesBoxHighlightActivity", + "MultiMapActivity", + "MapInDialogActivity", + "ManualZoomActivity", + "MaxMinZoomActivity", + "ScrollByActivity", + "ZoomFunctionSymbolLayerActivity", + "SymbolGeneratorActivity", + "TextureViewTransparentBackgroundActivity", + "SimpleMapActivity", + "RenderTestActivity", + "SymbolLayerActivity", + "LocationFragmentActivity", + "MergeOfflineRegionsActivity", + "NestedViewPagerActivity", + "DebugModeActivity", + "TextureViewDebugModeActivity", + "RuntimeStyleActivity", + "GridSourceActivity", + "AnimatedImageSourceActivity", + "EspressoTestActivity", + "ChangeResourcesCachePathActivity", + "EspressoTestActivity", + "FragmentBackStackActivity", + "ChildFragmentMapInDialogActivity", + "PerformanceMeasurementActivity", + "DownloadRegionActivity", + "CacheManagementActivity" +] diff --git a/scripts/generate-license.py b/scripts/generate-license.py new file mode 100644 index 000000000..9e59cb418 --- /dev/null +++ b/scripts/generate-license.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import os +import json + +path = os.getcwd() + "/platform/android/" +with open(path + "LICENSE.md", 'w') as licenseFile: + licenseFile.write(" \n") + licenseFile.write("## Additional Mapbox GL licenses \n") + with open(path + "MapboxGLAndroidSDK/build/reports/licenses/licenseReleaseReport.json", 'r') as dataFile: + data = json.load(dataFile) + + gradleLicensePlugin =""" + { + "project": "Gradle License Plugin", + "url": "https://github.com/jaredsburrows/gradle-license-plugin", + "licenses": [ + { + "license": "The Apache Software License, Version 2.0", + "license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt" + } + ] + } + """ + data.append(json.loads(gradleLicensePlugin)) + + licenseName = "" + licenseUrl = "" + for entry in data: + projectName = entry["project"] + projectUrl = entry["url"] + for license in entry["licenses"]: + licenseName = license["license"] + licenseUrl = license["license_url"] + + licenseFile.write("Mapbox GL uses portions of the %s. \n" % projectName + + ("URL: [%s](%s) \n" % (projectUrl, projectUrl) if projectUrl is not None else "") + + "License: [%s](%s)" % (licenseName, licenseUrl) + + "\n\n===========================================================================\n\n") diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js new file mode 100755 index 000000000..fa814f89a --- /dev/null +++ b/scripts/generate-style-code.js @@ -0,0 +1,394 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const ejs = require('ejs'); +const spec = require('../../../scripts/style-spec'); +const _ = require('lodash'); + +// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 +delete spec.layout_circle["circle-sort-key"] +delete spec.layout_line["line-sort-key"] +delete spec.layout_fill["fill-sort-key"] + +require('../../../scripts/style-code'); + +// Specification parsing // +const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => { + var property = spec[`light`][name]; + property.name = name; + property['light-property'] = true; + property.doc = property.doc.replace(/°/g,'°'); + memo.push(property); + return memo; +}, []); + +// Collect layer types from spec +var layers = Object.keys(spec.layer.type.values).map((type) => { + const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => { + if (name !== 'visibility') { + spec[`layout_${type}`][name].name = name; + memo.push(spec[`layout_${type}`][name]); + } + return memo; + }, []); + + const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => { + spec[`paint_${type}`][name].name = name; + memo.push(spec[`paint_${type}`][name]); + return memo; + }, []); + + return { + type: type, + doc: spec.layer.type.values[type].doc, + layoutProperties: layoutProperties, + paintProperties: paintProperties, + properties: layoutProperties.concat(paintProperties) + }; +}); + +// Process all layer properties +const uniqueArrayEnum = (prop, enums) => { + if (prop.value !== 'enum') return false; + const enumsEqual = (val1, val2) => val1.length === val1.length && val1.every((val, i) => val === val2[i]); + return enums.filter(e => enumsEqual(Object.keys(prop.values).sort(), Object.keys(e.values).sort())).length == 0; +}; + +const layoutProperties = _(layers).map('layoutProperties').flatten().value(); +const paintProperties = _(layers).map('paintProperties').flatten().value(); +const allProperties = _(layoutProperties).union(paintProperties).union(lightProperties).value(); +let allEnumProperties = _(allProperties).filter({'type': 'enum'}).value(); +const uniqueArrayEnumProperties = _(allProperties).filter({'type': 'array'}).filter(prop => uniqueArrayEnum(prop, allEnumProperties)).value(); +const enumProperties = _(allEnumProperties).union(uniqueArrayEnumProperties).value(); + + +global.propertyType = function propertyType(property) { + switch (property.type) { + case 'boolean': + return 'Boolean'; + case 'number': + return 'Float'; + case 'formatted': + return 'Formatted'; + case 'string': + return 'String'; + case 'enum': + return 'String'; + case 'color': + return 'String'; + case 'array': + return `${propertyType({type:property.value})}[]`; + default: + throw new Error(`unknown type for ${property.name}`); + } +} + +global.propertyJavaType = function propertyType(property) { + switch (property.type) { + case 'boolean': + return 'boolean'; + case 'number': + return 'float'; + case 'formatted': + return 'Formatted'; + case 'string': + return 'String'; + case 'enum': + return 'String'; + case 'color': + return 'String'; + case 'array': + return `${propertyJavaType({type:property.value})}[]`; + default: + throw new Error(`unknown type for ${property.name}`); + } + } + +global.propertyJNIType = function propertyJNIType(property) { + switch (property.type) { + case 'boolean': + return 'jboolean'; + case 'number': + return 'jfloat'; + case 'String': + return 'String'; + case 'enum': + return 'String'; + case 'color': + return 'String'; + case 'array': + return `jarray<${propertyType({type:property.value})}[]>`; + default: + return 'jobject*'; + } +} + +global.propertyNativeType = function (property) { + if (/-translate-anchor$/.test(property.name)) { + return 'TranslateAnchorType'; + } + if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) { + return 'AlignmentType'; + } + if (/^(text|icon)-anchor$/.test(property.name)) { + return 'SymbolAnchorType'; + } + switch (property.type) { + case 'boolean': + return 'bool'; + case 'number': + return 'float'; + case 'formatted': + case 'string': + return 'std::string'; + case 'enum': + if(property['light-property']){ + return `Light${camelize(property.name)}Type`; + } + return `${camelize(property.name)}Type`; + case 'color': + return `Color`; + case 'array': + if (property.length) { + return `std::array<${propertyType({type: property.value})}, ${property.length}>`; + } else { + return `std::vector<${propertyType({type: property.value})}>`; + } + default: throw new Error(`unknown type for ${property.name}`) + } +} + +global.propertyTypeAnnotation = function propertyTypeAnnotation(property) { + switch (property.type) { + case 'enum': + return `@Property.${snakeCaseUpper(property.name)}`; + default: + return ""; + } +}; + +global.defaultExpressionJava = function(property) { + switch (property.type) { + case 'boolean': + return 'boolean'; + case 'number': + return 'number'; + case 'formatted': + return 'format'; + case 'string': + return "string"; + case 'enum': + return "string"; + case 'color': + return 'toColor'; + case 'array': + return "array"; + default: return "string"; + } +} + +global.defaultValueJava = function(property) { + if(property.name.endsWith("-pattern")) { + return '"pedestrian-polygon"'; + } + if(property.name.endsWith("-font")) { + return 'new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}'; + } + switch (property.type) { + case 'boolean': + return 'true'; + case 'number': + return '0.3f'; + case 'formatted': + return 'new Formatted(new FormattedSection("default"))' + case 'string': + return '"' + property['default'] + '"'; + case 'enum': + return snakeCaseUpper(property.name) + "_" + snakeCaseUpper(Object.keys(property.values)[0]); + case 'color': + return '"rgba(255,128,0,0.7)"'; + case 'array': + switch (property.value) { + case 'string': + case 'enum': + if (property['default'] !== undefined) { + return '[' + property['default'] + ']'; + } else { + return 'new String[0]'; + } + case 'number': + var result ='new Float[] {'; + for (var i = 0; i < property.length; i++) { + result += "0f"; + if (i +1 != property.length) { + result += ", "; + } + } + return result + "}"; + } + default: throw new Error(`unknown type for ${property.name}`) + } +} + +/** + * Produces documentation for property factory methods + */ +global.propertyFactoryMethodDoc = function (property) { + var replaceIfPixels = function (doc) { + return doc.replace('pixels', 'density-independent pixels') + } + let doc = replaceIfPixels(property.doc); + // Match other items in back ticks + doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) { + if (str.substr(offset - 4, 3) !== 'CSS' && symbol[0].toUpperCase() != symbol[0] && _(enumProperties).filter({'name': symbol}).value().length > 0) { + // Property 'enums' + symbol = snakeCaseUpper(symbol); + return '{@link Property.' + symbol + '}'; + } else if( _(allProperties).filter({'name': symbol}).value().length > 0) { + // Other properties + return '{@link PropertyFactory#' + camelizeWithLeadingLowercase(symbol) + '}'; + } else { + // Left overs + return '`' + symbol + '`'; + } + }); + return doc; +}; + +/** + * Produces documentation for property value constants + */ +global.propertyValueDoc = function (property, value) { + + // Match references to other property names & values. + // Requires the format 'When `foo` is set to `bar`,'. + let doc = property.values[value].doc.replace(/When `(.+?)` is set to `(.+?)`(?: or `([^`]+?)`)?,/g, function (m, peerPropertyName, propertyValue, secondPropertyValue, offset, str) { + let otherProperty = snakeCaseUpper(peerPropertyName); + let otherValue = snakeCaseUpper(peerPropertyName) + '_' + snakeCaseUpper(propertyValue); + const firstPropertyValue = 'When {@link ' + `${otherProperty}` + '} is set to {@link Property#' + `${otherValue}` + '}'; + if (secondPropertyValue) { + return firstPropertyValue + ` or {@link Property#${snakeCaseUpper(peerPropertyName) + '_' + snakeCaseUpper(secondPropertyValue)}},`; + } else { + return firstPropertyValue + ','; + } + }); + + // Match references to our own property values. + // Requires the format 'is equivalent to `bar`'. + doc = doc.replace(/is equivalent to `(.+?)`/g, function(m, propertyValue, offset, str) { + propertyValue = snakeCaseUpper(property.name) + '_' + snakeCaseUpper(propertyValue); + return 'is equivalent to {@link Property#' + propertyValue + '}'; + }); + + // Match other items in back ticks + doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) { + if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) { + // Property values + propertyValue = snakeCaseUpper(property.name) + '_' + snakeCaseUpper(symbol); + console.log("Transforming", symbol, propertyValue); + return '{@link Property#' + `${propertyValue}` + '}'; + } else if (str.substr(offset - 4, 3) !== 'CSS' && symbol[0].toUpperCase() != symbol[0]) { + // Property 'enums' + if (symbol === 'symbol-sort-key') { + return 'symbol sort key'; + } + + symbol = snakeCaseUpper(symbol); + return '{@link ' + symbol + '}'; + } else { + // Left overs + return symbol + } + }); + return doc; +}; + +global.isLightProperty = function (property) { + return property['light-property'] === true; +}; + +global.propertyValueType = function (property) { + switch (property['property-type']) { + default: + return `PropertyValue<${evaluatedType(property)}>`; + } +}; + +global.evaluatedType = function (property) { + if (/-translate-anchor$/.test(property.name)) { + return 'TranslateAnchorType'; + } + if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) { + return 'AlignmentType'; + } + if (/^(text|icon)-anchor$/.test(property.name)) { + return 'SymbolAnchorType'; + } + if (/position/.test(property.name)) { + return 'Position'; + } + switch (property.type) { + case 'boolean': + return 'bool'; + case 'number': + return 'float'; + case 'formatted': + case 'string': + return 'std::string'; + case 'enum': + return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`; + case 'color': + return `Color`; + case 'array': + if (property.length) { + return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`; + } else { + return `std::vector<${evaluatedType({type: property.value})}>`; + } + default: throw new Error(`unknown type for ${property.name}`) + } +}; + +global.supportsZoomFunction = function (property) { + return property.expression && property.expression.parameters.indexOf('zoom') > -1; +}; + +global.supportsPropertyFunction = function (property) { + return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven'; +}; + +// Template processing // + +// Java + JNI Light (Peer model) +const lightJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs', 'utf8'), {strict: true}); +const lightJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs', 'utf8'), {strict: true}); +writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties})); +writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties})); + +// Java + JNI Layers (Peer model) +const layerHpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); +const layerCpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); +const layerJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs', 'utf8'), {strict: true}); +const layerJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs', 'utf8'), {strict: true}); + +for (const layer of layers) { + writeIfModified(`platform/android/src/style/layers/${layer.type.replace('-', '_')}_layer.hpp`, layerHpp(layer)); + writeIfModified(`platform/android/src/style/layers/${layer.type.replace('-', '_')}_layer.cpp`, layerCpp(layer)); + writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer)); + writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); +} + +// Java PropertyFactory +const propertiesTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); +writeIfModified( + `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java`, + propertiesTemplate({layoutProperties: layoutProperties, paintProperties: paintProperties}) +); + +// Java Property +const enumPropertyJavaTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs', 'utf8'), {strict: true}); +writeIfModified( + `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`, + enumPropertyJavaTemplate({properties: enumProperties}) +); diff --git a/scripts/generate-test-code.js b/scripts/generate-test-code.js new file mode 100644 index 000000000..64b38e5ac --- /dev/null +++ b/scripts/generate-test-code.js @@ -0,0 +1,73 @@ +'use strict'; + +const fs = require('fs'); +const ejs = require('ejs'); + +global.iff = function (condition, val) { + return condition() ? val : ""; +} + +global.camelize = function (str) { + return str.replace(/(?:^|-)(.)/g, function (_, x) { + return x.toUpperCase(); + }); +} + +const excludeClasses = JSON.parse(fs.readFileSync('platform/android/scripts/exclude-activity-gen.json', 'utf8')); +const appBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity'; +const testBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen'; +const subPackages = fs.readdirSync(appBasePath); +const ejsConversionTask = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs', 'utf8'), {strict: true}); + +if (!fs.existsSync(testBasePath)){ + fs.mkdirSync(testBasePath); +} + +console.log("\nGenerating test activities:\n"); +var generatedClasses = []; +var excludedClasses = []; +for(const subPackage of subPackages) { + if(!(subPackage.slice(-5) == '.java')) { + const activities = fs.readdirSync(appBasePath+'/'+subPackage); + + // create directories for package + if (!fs.existsSync(testBasePath+"/"+subPackage)){ + fs.mkdirSync(testBasePath+"/"+subPackage); + } + + for (const activity of activities) { + var activityName; + if (activity.slice(-5) === '.java') { + // .java file + activityName = activity.slice(0, -5); + } else { + // .kt file + activityName = activity.slice(0, -3); + } + + // create path for test file + const filePath = testBasePath+"/"+subPackage+"/"+activityName+'Test.java'; + + // try removing previous generated files + try { + fs.accessSync(filePath, fs.F_OK); + fs.unlinkSync(filePath); + } catch (e) { + } + + // only generate test file if not part of exclude list + if contains Activity in name + if ((!(excludeClasses.indexOf(activityName) > -1)) && activityName.includes("Activity")) { + fs.writeFileSync(filePath, ejsConversionTask([activityName, subPackage])); + generatedClasses.push(activityName); + }else{ + excludedClasses.push(activityName); + } + } + } +} + +for(const generatedClass of generatedClasses){ + console.log(generatedClass+"Test"); +} + +console.log("\nFinished generating " + generatedClasses.length + " activity sanity tests, excluded " + excludeClasses.length + " classes.\n"); \ No newline at end of file diff --git a/scripts/metrics.sh b/scripts/metrics.sh new file mode 100755 index 000000000..cc33daf17 --- /dev/null +++ b/scripts/metrics.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +# Track individual architectures +scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/armeabi-v7a/libmapbox-gl.so" "Android arm-v7" +scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/arm64-v8a/libmapbox-gl.so" "Android arm-v8" +scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86/libmapbox-gl.so" "Android x86" +scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86_64/libmapbox-gl.so" "Android x86_64" + +# Track overall library size +scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/outputs/aar/MapboxGLAndroidSDK-release.aar" "Android AAR" + +if [[ $CIRCLE_BRANCH == master ]]; then + # Build source data for http://mapbox.github.io/mapbox-gl-native/metrics/binary-size/ + # and log binary sizes to metrics warehouse + scripts/publish_binary_size.js +fi diff --git a/scripts/parse-jacoco-report.py b/scripts/parse-jacoco-report.py new file mode 100755 index 000000000..4d06fda6c --- /dev/null +++ b/scripts/parse-jacoco-report.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import os +import re +from io import open + +reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +with open(reportPath, 'r', encoding='utf-8') as jacocoReport: + line = jacocoReport.readline().strip() + + # find the last INSTRUCTION coverage report which is a sum of all separate ones + instructionIndex = line.rfind('type="INSTRUCTION"') + startIndex = line.find('missed', instructionIndex) + endIndex = line.find('/>', startIndex) + + # find the missed and covered lines counts + numbers = re.match(r'missed="(\d+)" covered="(\d+)"', line[startIndex:endIndex]) + missed = int(numbers.group(1)) + covered = int(numbers.group(2)) + + # calculate the code coverage percentage + percentage = round(covered * 100.0 / (missed + covered), 2) + print("Android tests code coverage: %s%%" % (str(percentage))) + + # invoke the script that send the data to s3 + testEnvironment = "LOCAL" + if os.environ.get('IS_LOCAL_DEVELOPMENT').lower()=='false': + testEnvironment = "CI" + + cmd = os.getcwd() + ("/scripts/code-coverage.sh %.2f %s %s" % (percentage, "Android", testEnvironment)) + os.system(cmd) diff --git a/scripts/release.py b/scripts/release.py new file mode 100644 index 000000000..d0abd1eea --- /dev/null +++ b/scripts/release.py @@ -0,0 +1,236 @@ +''' +Utility to schedule SDK builds on CircleCI. + +Examples: + +- Publish a snapshot from master (release.py uses the current branch) + + $ git branch + * master + 1234-fix-crash + $ python release.py --stage snapshot + +- Publish a snapshot from a feature branch (same as before, just switch branchs with git): + + $ git branch + master + * 1234-fix-crash + $ python release.py --stage snapshot + +- Publish a beta from a pre-release branch: + + $ git branch + master + * release-android-420-beta1 + $ python release.py --stage beta --version 4.2.0-beta.1 + +- Publish a beta from a release branch: + + $ git branch + master + * release-android-420 + $ python release.py --stage final --version 4.2.0 + +TODO: + +- Add a flag to wait until the release has been built (CircleCI) and published (Maven). + +''' + +import click +import json +import os +import requests +import subprocess + +# Three stages, from less stable to more stable +ALLOWED_STAGES = ['snapshot', 'beta', 'final'] + +# Get the version from GRADLE_PROPERTIES_PATH below +CURRENT_VERSION_TAG = 'current' + +# You can add your API token on https://circleci.com/account/api +CIRCLECI_API_TOKEN_ENV_VAR = 'CIRCLECI_API_TOKEN' + +# In the future we might want to consider alpha, or rc. +ALLOWED_PRE_RELEASE = ['beta'] + +# We get the default version from here +MAPBOX_GL_ANDROID_SDK_PATH = '../MapboxGLAndroidSDK' +GRADLE_PROPERTIES_PATH = '%s/gradle.properties' % MAPBOX_GL_ANDROID_SDK_PATH +GRADLE_TOKEN = 'VERSION_NAME=' + +# Triggers a new build, returns a summary of the build +URL_CIRCLECI = 'https://circleci.com/api/v1.1/project/github/mapbox/mapbox-gl-native/tree/' # + :branch + +# We support three parameters: stage, branch, and version +@click.command() +@click.option('--stage', default=ALLOWED_STAGES[0], type=click.Choice(ALLOWED_STAGES), prompt='Set stage', help='The release stage.') +@click.option('--version', default=CURRENT_VERSION_TAG, prompt='Set version', help='The version you want to publish. E.g: 4.2.0-SNAPSHOT, 4.2.0-beta.1, or 4.2.0. If you set the version to "%s", the script will default to the current SNAPSHOT version.' % CURRENT_VERSION_TAG) +def release(stage, version): + # Validate params + final_stage = validate_stage(stage=stage) + final_branch = validate_branch(stage=final_stage) + final_version = validate_version(stage=final_stage, branch=final_branch, version=version) + + # Get user confirmation + click.echo('\n===== Build information =====') + click.echo('- Stage: %s' % final_stage) + click.echo('- Branch: %s' % final_branch) + click.echo('- Version: %s' % final_version) + click.confirm('\nDoes it look right?', abort=True) + + # Proceed + if (final_stage == 'snapshot'): + publish_snapshot(branch=final_branch, version=final_version) + elif (final_stage == 'beta'): + publish_beta(branch=final_branch, version=final_version) + elif (final_stage == 'final'): + publish_final(branch=final_branch, version=final_version) + +def validate_stage(stage): + if stage not in ALLOWED_STAGES: + abort_with_message('Invalid stage: %s' % stage) + return stage + +def validate_branch(stage): + branch = git_get_current_branch() + if not branch: + abort_with_message('The current folder is not a git repository.') + if branch == 'master' and stage != 'snapshot': + abort_with_message('You need to swtich to a release branch for a beta or a final release.') + return branch + +def validate_version(stage, branch, version): + if stage == 'snapshot' and branch == 'master' and version != CURRENT_VERSION_TAG: + abort_with_message('You cannot specify a custom version if you are building a snapshot from master.') + + if not version or version == CURRENT_VERSION_TAG: + version = get_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN) + + if stage == 'snapshot': + if not 'SNAPSHOT' in version: + abort_with_message('Version should contain the word SNAPSHOT: %s' % version) + elif stage == 'beta': + if not ALLOWED_PRE_RELEASE[0] in version: + abort_with_message('Version should contain the word %s: %s' % (ALLOWED_PRE_RELEASE[0], version)) + elif stage == 'final': + if not version or 'SNAPSHOT' in version or ALLOWED_PRE_RELEASE[0] in version: + abort_with_message('Version cannot be empty, or contain the words SNAPSHOT or %s: %s' % (ALLOWED_PRE_RELEASE[0], version)) + + return version + +def publish_snapshot(branch, version): + click.echo('Publishing snapshot for branch: %s (version: %s).' % (branch, version)) + if branch != 'master': + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + git_commit_and_push(branch=branch, version=version) + do_circleci_request(branch=branch) + +def publish_beta(branch, version): + click.echo('Publishing beta from branch: %s (version: %s).' % (branch, version)) + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + git_commit_and_push(branch=branch, version=version) + do_circleci_request(branch=branch) + +def publish_final(branch, version): + click.echo('Publishing final release from branch: %s (version: %s).' % (branch, version)) + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + if dirty_gradle: + git_commit_and_push(branch=branch, version=version) + do_circleci_request(branch=branch) + +# +# Utils +# + +def abort_with_message(message): + click.echo(message) + click.get_current_context().abort() + +def execute_call(command): + click.echo('Executing: %s' % command) + result = subprocess.call(command, shell=True) + if result != 0: + abort_with_message('Command failed: %s' % command) + +# +# CircleCI +# + +def get_circleci_api_token(): + circleci_api_token = os.environ.get(CIRCLECI_API_TOKEN_ENV_VAR) + if not circleci_api_token: + abort_with_message('You need to set the CIRCLECI_API_TOKEN environment variable.') + click.echo('Found CircleCI API token.') + return circleci_api_token + +def do_circleci_request(branch): + url = URL_CIRCLECI + branch + params = {'circle-token': get_circleci_api_token()} + click.echo('CircleCI request to %s (params: %s)' % (url, json.dumps(params))) + click.confirm('\nDo you want to start a build?', abort=True) + + r = requests.post(url, params=params) + click.echo('- CircleCI response code: %s' % r.status_code) + +# +# Git +# + +def git_get_current_branch(): + return subprocess.check_output('git symbolic-ref --short HEAD'.split(' ')).strip() + +def git_add(path): + execute_call(command='git add %s' % path) + +def git_commit_and_push(branch, version): + message = '[android] [auto] Update properties to version %s in preparation for build.' % version + commands = [ + 'git commit -m "%s"' % message, + 'git push -u origin %s' % branch] + for command in commands: + execute_call(command=command) + +# +# Read and update properties files +# + +def get_current_version(file_path, file_var): + click.echo('Getting current version from %s.' % file_path) + with open(file_path, 'r') as f: + for line in f: + if line.startswith(file_var): + version_name = line[len(file_var):].strip() + click.echo('Current version is %s.' % version_name) + return version_name + return None + +def update_current_version(file_path, file_var, version): + dirty = False + click.echo('Updating file to version %s: %s.' % (version, file_path)) + with open(file_path, 'r') as f: + file_lines = f.readlines() + for line_number in range(len(file_lines)): + if file_lines[line_number].startswith(file_var): + content_old = file_lines[line_number] + content_new = '%s%s\n' % (file_var, version) + if (content_old != content_new): + click.echo('%s -> %s' % (content_old.strip(), content_new.strip())) + file_lines[line_number] = content_new + dirty = True + if dirty: + with open(file_path, 'w') as f: + f.writelines(file_lines) + else: + click.echo('File already has the right version.') + return dirty + +if __name__ == '__main__': + release() diff --git a/scripts/run-render-test.py b/scripts/run-render-test.py new file mode 100644 index 000000000..940ae7a3d --- /dev/null +++ b/scripts/run-render-test.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +import os +import shutil + +catPath = os.getcwd() + "/platform/android/build/render-test/" +failCounter = 0 +testCounter = 0 +for cat in os.listdir(catPath): + testPath = catPath + cat + "/" + for test in os.listdir(testPath): + inputPath = os.getcwd() + "/mapbox-gl-js/test/integration/render-tests/" + cat + "/" + test + outputPath = testPath + test + + expected = outputPath + "/expected.png" + actual = outputPath + "/actual.png" + output = outputPath + "/output.png" + + shutil.copyfile(inputPath + "/expected.png", expected) + shutil.copyfile(inputPath + "/style.json", outputPath + "/style.json") + pixelmatchCommand = "node_modules/pixelmatch/bin/pixelmatch " + actual + " " + expected + " " + output + " 0.1" + + print "Pixel match " + cat + " " + test + + with os.popen(pixelmatchCommand) as f: + for line_terminated in f: + line = line_terminated.rstrip('\n') + pair = line.split(": ") + if pair[0] == "error": + testCounter += 1 + currentError = pair[1] + if currentError != "0%": + failCounter += 1 + # below deletes successful results + # print cat + " " + test + " " + currentError + # else: + # try: + # if os.path.isdir(outputPath): + # shutil.rmtree(outputPath) + # except OSError, e: + # print ("Error: %s - %s." % (e.filename, e.strerror)) +print +print str(failCounter) + "/" + str(testCounter) diff --git a/scripts/validate-license.py b/scripts/validate-license.py new file mode 100644 index 000000000..1c9a153b8 --- /dev/null +++ b/scripts/validate-license.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +from subprocess import call +from subprocess import Popen, PIPE +import sys + +## Run license generation +call('cd ../../ && make android-license', shell=True) + +## Git diff changes +p = Popen(['git', 'diff', '--name-only', 'LICENSE.md'], stdin=PIPE, stdout=PIPE, stderr=PIPE) +output, err = p.communicate(b"input data that is passed to subprocess' stdin") +if b"platform/android/LICENSE.md" in output: + raise ValueError("""An error ocurred while validating the license generation. + Changes were detected to the license generation output + but weren't commited. Run make android-license and + commit the changeset to make this validation pass.""") \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..c0315fed0 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':MapboxGLAndroidSDK', ':MapboxGLAndroidSDKTestApp', ':MapboxGLAndroidSDKLint' \ No newline at end of file diff --git a/src/android_renderer_backend.cpp b/src/android_renderer_backend.cpp new file mode 100755 index 000000000..e2d064838 --- /dev/null +++ b/src/android_renderer_backend.cpp @@ -0,0 +1,67 @@ +#include "android_renderer_backend.hpp" + +#include +#include +#include + +#include + +#include + +namespace mbgl { +namespace android { + +class AndroidGLRenderableResource final : public mbgl::gl::RenderableResource { +public: + AndroidGLRenderableResource(AndroidRendererBackend& backend_) : backend(backend_) { + } + + void bind() override { + assert(gfx::BackendScope::exists()); + backend.setFramebufferBinding(0); + backend.setViewport(0, 0, backend.getSize()); + } + +private: + AndroidRendererBackend& backend; +}; + +AndroidRendererBackend::AndroidRendererBackend() + : gl::RendererBackend(gfx::ContextMode::Unique), + mbgl::gfx::Renderable({ 64, 64 }, std::make_unique(*this)) { +} + +AndroidRendererBackend::~AndroidRendererBackend() = default; + +gl::ProcAddress AndroidRendererBackend::getExtensionFunctionPointer(const char* name) { + assert(gfx::BackendScope::exists()); + return eglGetProcAddress(name); +} + +void AndroidRendererBackend::updateViewPort() { + assert(gfx::BackendScope::exists()); + setViewport(0, 0, size); +} + +void AndroidRendererBackend::resizeFramebuffer(int width, int height) { + size = { static_cast(width), static_cast(height) }; +} + +PremultipliedImage AndroidRendererBackend::readFramebuffer() { + assert(gfx::BackendScope::exists()); + return gl::RendererBackend::readFramebuffer(size); +} + +void AndroidRendererBackend::updateAssumedState() { + assumeFramebufferBinding(0); + assumeViewport(0, 0, size); +} + +void AndroidRendererBackend::markContextLost() { + if (context) { + getContext().setCleanupOnDestruction(false); + } +} + +} // namespace android +} // namspace mbgl diff --git a/src/android_renderer_backend.hpp b/src/android_renderer_backend.hpp new file mode 100755 index 000000000..f06f38e68 --- /dev/null +++ b/src/android_renderer_backend.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class AndroidRendererBackend : public gl::RendererBackend, public mbgl::gfx::Renderable { +public: + AndroidRendererBackend(); + ~AndroidRendererBackend() override; + + void updateViewPort(); + + // Ensures the current context is not cleaned up when destroyed + void markContextLost(); + + void resizeFramebuffer(int width, int height); + PremultipliedImage readFramebuffer(); + + // mbgl::gfx::RendererBackend implementation +public: + mbgl::gfx::Renderable& getDefaultRenderable() override { + return *this; + } + +protected: + void activate() override { + // no-op + } + void deactivate() override { + // no-op + } + + // mbgl::gl::RendererBackend implementation +protected: + mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override; + void updateAssumedState() override; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/android_renderer_frontend.cpp b/src/android_renderer_frontend.cpp new file mode 100644 index 000000000..d1a2624f0 --- /dev/null +++ b/src/android_renderer_frontend.cpp @@ -0,0 +1,143 @@ +#include "android_renderer_frontend.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "android_renderer_backend.hpp" + +namespace mbgl { +namespace android { + +// Forwards RendererObserver signals to the given +// Delegate RendererObserver on the given RunLoop +class ForwardingRendererObserver : public RendererObserver { +public: + ForwardingRendererObserver(util::RunLoop& mapRunLoop, RendererObserver& delegate_) + : mailbox(std::make_shared(mapRunLoop)) + , delegate(delegate_, mailbox) { + } + + ~ForwardingRendererObserver() { + mailbox->close(); + } + + void onInvalidate() override { + delegate.invoke(&RendererObserver::onInvalidate); + } + + void onResourceError(std::exception_ptr err) override { + delegate.invoke(&RendererObserver::onResourceError, err); + } + + void onWillStartRenderingMap() override { + delegate.invoke(&RendererObserver::onWillStartRenderingMap); + } + + void onWillStartRenderingFrame() override { + delegate.invoke(&RendererObserver::onWillStartRenderingFrame); + } + + void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) override { + delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged); + } + + void onDidFinishRenderingMap() override { + delegate.invoke(&RendererObserver::onDidFinishRenderingMap); + } + + void onStyleImageMissing(const std::string& id, StyleImageMissingCallback done) override { + delegate.invoke(&RendererObserver::onStyleImageMissing, id, done); + } + + void onRemoveUnusedStyleImages(const std::vector& ids) override { + delegate.invoke(&RendererObserver::onRemoveUnusedStyleImages, ids); + } + +private: + std::shared_ptr mailbox; + ActorRef delegate; +}; + +AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_) + : mapRenderer(mapRenderer_) + , mapRunLoop(util::RunLoop::Get()) + , updateAsyncTask(std::make_unique([this]() { + mapRenderer.update(std::move(updateParams)); + mapRenderer.requestRender(); + })) { +} + +AndroidRendererFrontend::~AndroidRendererFrontend() = default; + +void AndroidRendererFrontend::reset() { + mapRenderer.reset(); +} + +void AndroidRendererFrontend::setObserver(RendererObserver& observer) { + assert (util::RunLoop::Get()); + // Don't call the Renderer directly, but use MapRenderer#setObserver to make sure + // the Renderer may be re-initialised without losing the RendererObserver reference. + mapRenderer.setObserver(std::make_unique(*mapRunLoop, observer)); +} + +void AndroidRendererFrontend::update(std::shared_ptr params) { + updateParams = std::move(params); + updateAsyncTask->send(); +} + +void AndroidRendererFrontend::reduceMemoryUse() { + mapRenderer.actor().invoke(&Renderer::reduceMemoryUse); +} + +std::vector AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID, + const SourceQueryOptions& options) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get(); +} + +std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box, + const RenderedQueryOptions& options) const { + + // Select the right overloaded method + std::vector (Renderer::*fn)(const ScreenBox&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; + + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(fn, box, options).get(); +} + +std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenCoordinate& point, + const RenderedQueryOptions& options) const { + + // Select the right overloaded method + std::vector (Renderer::*fn)(const ScreenCoordinate&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; + + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(fn, point, options).get(); +} + +AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& box) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get(); +} + +AnnotationIDs AndroidRendererFrontend::queryShapeAnnotations(const ScreenBox& box) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::queryShapeAnnotations, box).get(); +} + +FeatureExtensionValue AndroidRendererFrontend::queryFeatureExtensions(const std::string& sourceID, + const Feature& feature, + const std::string& extension, + const std::string& extensionField, + const optional>& args) const { + return mapRenderer.actor().ask(&Renderer::queryFeatureExtensions, sourceID, feature, extension, extensionField, args).get(); +} + +} // namespace android +} // namespace mbgl + diff --git a/src/android_renderer_frontend.hpp b/src/android_renderer_frontend.hpp new file mode 100644 index 000000000..dc5f11e57 --- /dev/null +++ b/src/android_renderer_frontend.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "map_renderer.hpp" + +namespace mbgl { + +class RenderedQueryOptions; +class SourceQueryOptions; + +namespace util { + +class AsyncTask; + +} // namespace util + +namespace android { + +class AndroidRendererFrontend : public RendererFrontend { +public: + + AndroidRendererFrontend(MapRenderer&); + ~AndroidRendererFrontend() override; + + void reset() override; + void setObserver(RendererObserver&) override; + + void update(std::shared_ptr) override; + + // Feature querying + std::vector queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const; + std::vector queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const; + std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; + AnnotationIDs queryPointAnnotations(const ScreenBox& box) const; + AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const; + + + // Feature extension query + FeatureExtensionValue + queryFeatureExtensions(const std::string& sourceID, + const Feature& feature, + const std::string& extension, + const std::string& extensionField, + const optional>& args) const; + + // Memory + void reduceMemoryUse(); + +private: + MapRenderer& mapRenderer; + util::RunLoop* mapRunLoop; + std::unique_ptr updateAsyncTask; + std::shared_ptr updateParams; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/annotation/marker.cpp b/src/annotation/marker.cpp new file mode 100644 index 000000000..899f87a74 --- /dev/null +++ b/src/annotation/marker.cpp @@ -0,0 +1,23 @@ +#include "marker.hpp" + +namespace mbgl { +namespace android { + +mbgl::Point Marker::getPosition(jni::JNIEnv& env, const jni::Object& marker) { + static auto& javaClass = jni::Class::Singleton(env); + static auto positionField = javaClass.GetField>(env, "position"); + return LatLng::getGeometry(env, marker.Get(env, positionField)); +} + +std::string Marker::getIconId(jni::JNIEnv& env, const jni::Object& marker) { + static auto& javaClass = jni::Class::Singleton(env); + static auto iconIdField = javaClass.GetField(env, "iconId"); + return jni::Make(env, marker.Get(env, iconIdField)); +} + +void Marker::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/marker.hpp b/src/annotation/marker.hpp new file mode 100644 index 000000000..b38a25b4f --- /dev/null +++ b/src/annotation/marker.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include + +#include "../geometry/lat_lng.hpp" + +namespace mbgl { +namespace android { + +class Marker : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; }; + + static mbgl::Point getPosition(jni::JNIEnv&, const jni::Object&); + + static std::string getIconId(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/multi_point.hpp b/src/annotation/multi_point.hpp new file mode 100644 index 000000000..20f1b3eaf --- /dev/null +++ b/src/annotation/multi_point.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "../geometry/lat_lng.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { + +class MultiPoint : protected mbgl::util::noncopyable { + +protected: + + template + static Geometry toGeometry(JNIEnv& env, const jni::Object& pointsList) { + auto jarray = java::util::List::toArray(env, pointsList); + + std::size_t size = jarray.Length(env); + + Geometry geometry; + geometry.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + geometry.push_back(LatLng::getGeometry(env, jarray.Get(env, i))); + } + + return geometry; + } +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polygon.cpp b/src/annotation/polygon.cpp new file mode 100644 index 000000000..f22cffb10 --- /dev/null +++ b/src/annotation/polygon.cpp @@ -0,0 +1,40 @@ +#include "polygon.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, const jni::Object& polygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto points = javaClass.GetField>(env, "points"); + static auto holes = javaClass.GetField>(env, "holes"); + static auto alpha = javaClass.GetField(env, "alpha"); + static auto fillColor = javaClass.GetField(env, "fillColor"); + static auto strokeColor = javaClass.GetField(env, "strokeColor"); + + mbgl::Polygon geometry { + MultiPoint::toGeometry>(env, polygon.Get(env, points)) + }; + + auto jHoleListsArray = java::util::List::toArray(env, polygon.Get(env, holes)); + + std::size_t jHoleListsSize = jHoleListsArray.Length(env); + for (std::size_t i = 0; i < jHoleListsSize; i++) { + geometry.push_back(MultiPoint::toGeometry>(env, jHoleListsArray.Get(env, i))); + } + + mbgl::FillAnnotation annotation { geometry }; + annotation.opacity = polygon.Get(env, alpha); + annotation.color = *conversion::convert(env, polygon.Get(env, fillColor)); + annotation.outlineColor = *conversion::convert(env, polygon.Get(env, strokeColor)); + + return annotation; +} + +void Polygon::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polygon.hpp b/src/annotation/polygon.hpp new file mode 100644 index 000000000..bc21878ef --- /dev/null +++ b/src/annotation/polygon.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "multi_point.hpp" + +namespace mbgl { +namespace android { + +class Polygon : private MultiPoint { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; }; + + static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polyline.cpp b/src/annotation/polyline.cpp new file mode 100644 index 000000000..d6161e856 --- /dev/null +++ b/src/annotation/polyline.cpp @@ -0,0 +1,31 @@ +#include "polyline.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, const jni::Object& polyline) { + static auto& javaClass = jni::Class::Singleton(env); + static auto points = javaClass.GetField>(env, "points"); + static auto alpha = javaClass.GetField(env, "alpha"); + static auto color = javaClass.GetField(env, "color"); + static auto width = javaClass.GetField(env, "width"); + + mbgl::LineAnnotation annotation { + MultiPoint::toGeometry>(env, polyline.Get(env, points)) + }; + + annotation.opacity = polyline.Get(env, alpha); + annotation.color = *conversion::convert(env, polyline.Get(env, color)); + annotation.width = polyline.Get(env, width); + + return annotation; +} + +void Polyline::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polyline.hpp b/src/annotation/polyline.hpp new file mode 100644 index 000000000..6178e98cf --- /dev/null +++ b/src/annotation/polyline.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "multi_point.hpp" + +namespace mbgl { +namespace android { + +class Polyline : private MultiPoint { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; }; + + static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/asset_manager.hpp b/src/asset_manager.hpp new file mode 100644 index 000000000..b87d18951 --- /dev/null +++ b/src/asset_manager.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace mbgl { +namespace android { + +class AssetManager { +public: + static constexpr auto Name() { + return "android/content/res/AssetManager"; + }; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/asset_manager_file_source.cpp b/src/asset_manager_file_source.cpp new file mode 100644 index 000000000..b9150deef --- /dev/null +++ b/src/asset_manager_file_source.cpp @@ -0,0 +1,57 @@ +#include "asset_manager_file_source.hpp" + +#include +#include +#include +#include +#include + +#include +#include + +namespace mbgl { + +class AssetManagerFileSource::Impl { +public: + Impl(ActorRef, AAssetManager* assetManager_) : assetManager(assetManager_) { + } + + void request(const std::string& url, ActorRef req) { + // Note: AssetManager already prepends "assets" to the filename. + const std::string path = mbgl::util::percentDecode(url.substr(8)); + + Response response; + + if (AAsset* asset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER)) { + response.data = std::make_shared( + reinterpret_cast(AAsset_getBuffer(asset)), AAsset_getLength64(asset)); + AAsset_close(asset); + } else { + response.error = std::make_unique(Response::Error::Reason::NotFound, + "Could not read asset"); + } + + req.invoke(&FileSourceRequest::setResponse, response); + } + +private: + AAssetManager* assetManager; +}; + +AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, const jni::Object& assetManager_) + : assetManager(jni::NewGlobal(env, assetManager_)), + impl(std::make_unique>("AssetManagerFileSource", + AAssetManager_fromJava(&env, jni::Unwrap(assetManager.get())))) { +} + +AssetManagerFileSource::~AssetManagerFileSource() = default; + +std::unique_ptr AssetManagerFileSource::request(const Resource& resource, Callback callback) { + auto req = std::make_unique(std::move(callback)); + + impl->actor().invoke(&Impl::request, resource.url, req->actor()); + + return std::move(req); +} + +} // namespace mbgl diff --git a/src/asset_manager_file_source.hpp b/src/asset_manager_file_source.hpp new file mode 100644 index 000000000..4ec5b4c30 --- /dev/null +++ b/src/asset_manager_file_source.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "asset_manager.hpp" + +#include + +namespace mbgl { + +namespace util { +template class Thread; +} // namespace util + +class AssetManagerFileSource : public FileSource { +public: + AssetManagerFileSource(jni::JNIEnv&, const jni::Object&); + ~AssetManagerFileSource() override; + + std::unique_ptr request(const Resource&, Callback) override; + +private: + class Impl; + + jni::Global> assetManager; + std::unique_ptr> impl; +}; + +} // namespace mbgl diff --git a/src/async_task.cpp b/src/async_task.cpp new file mode 100644 index 000000000..6c14e96fa --- /dev/null +++ b/src/async_task.cpp @@ -0,0 +1,62 @@ +#include "run_loop_impl.hpp" + +#include +#include + +#include +#include + +namespace mbgl { +namespace util { + +class AsyncTask::Impl : public RunLoop::Impl::Runnable { +public: + Impl(std::function&& fn) + : queued(true), task(std::move(fn)) { + } + + ~Impl() { + loop->removeRunnable(this); + } + + void maySend() { + if (queued) { + queued = false; + loop->addRunnable(this); + } + } + + TimePoint dueTime() const override { + return due; + } + + void runTask() override { + loop->removeRunnable(this); + queued = true; + task(); + } + +private: + // Always expired, run immediately. + const TimePoint due = Clock::now(); + + RunLoop::Impl* loop = reinterpret_cast(RunLoop::getLoopHandle()); + + // TODO: Use std::atomic_flag if we ever drop + // support for ARMv5 + std::atomic queued; + std::function task; +}; + +AsyncTask::AsyncTask(std::function&& fn) + : impl(std::make_unique(std::move(fn))) { +} + +AsyncTask::~AsyncTask() = default; + +void AsyncTask::send() { + impl->maySend(); +} + +} // namespace util +} // namespace mbgl diff --git a/src/attach_env.cpp b/src/attach_env.cpp new file mode 100644 index 000000000..6da075ee3 --- /dev/null +++ b/src/attach_env.cpp @@ -0,0 +1,22 @@ +#include "attach_env.hpp" +#include "jni.hpp" + +namespace mbgl { +namespace android { + +UniqueEnv AttachEnv() { + JNIEnv* env = nullptr; + jint err = theJVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + switch (err) { + case JNI_OK: + return UniqueEnv(env, JNIEnvDeleter(*theJVM, false)); + case JNI_EDETACHED: + return UniqueEnv(jni::AttachCurrentThread(*theJVM).release(), JNIEnvDeleter(*theJVM, true)); + default: + throw std::system_error(err, jni::ErrorCategory()); + } +} + +} +} diff --git a/src/attach_env.hpp b/src/attach_env.hpp new file mode 100644 index 000000000..8a9f4a7f8 --- /dev/null +++ b/src/attach_env.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { + +class JNIEnvDeleter { +private: + jni::JavaVM* vm = nullptr; + bool detach = false; + +public: + JNIEnvDeleter() = default; + JNIEnvDeleter(jni::JavaVM& v, bool d) + : vm(&v), detach(d) {} + + void operator()(jni::JNIEnv* p) const { + if (p && detach) { + assert(vm); + vm->DetachCurrentThread(); + } + } +}; + +using UniqueEnv = std::unique_ptr; + +UniqueEnv AttachEnv(); + +} +} diff --git a/src/bitmap.cpp b/src/bitmap.cpp new file mode 100644 index 000000000..eb7c676b1 --- /dev/null +++ b/src/bitmap.cpp @@ -0,0 +1,124 @@ +#include "bitmap.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +class PixelGuard { +public: + PixelGuard(jni::JNIEnv& env_, const jni::Object& bitmap_) : env(env_), bitmap(bitmap_) { + const int result = AndroidBitmap_lockPixels(&env, jni::Unwrap(*bitmap), + reinterpret_cast(&address)); + if (result != ANDROID_BITMAP_RESULT_SUCCESS) { + throw std::runtime_error("bitmap decoding: could not lock pixels"); + } + } + + ~PixelGuard() { + const int result = AndroidBitmap_unlockPixels(&env, jni::Unwrap(*bitmap)); + if (result != ANDROID_BITMAP_RESULT_SUCCESS) { + Log::Warning(mbgl::Event::General, "Bitmap decoding: could not unlock pixels"); + } + } + + auto* get() { + return address; + } + +private: + jni::JNIEnv& env; + const jni::Object& bitmap; + uint8_t* address; +}; + +jni::Local> Bitmap::Config::Create(jni::JNIEnv& env, Value value) { + static auto& _class = jni::Class::Singleton(env); + switch (value) { + case ALPHA_8: + return _class.Get(env, _class.GetStaticField>(env, "ALPHA_8")); + case ARGB_4444: + return _class.Get(env, _class.GetStaticField>(env, "ARGB_4444")); + case ARGB_8888: + return _class.Get(env, _class.GetStaticField>(env, "ARGB_8888")); + case RGB_565: + return _class.Get(env, _class.GetStaticField>(env, "RGB_565")); + default: + throw std::runtime_error("invalid enum value for Bitmap.Config"); + } +} + +void Bitmap::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); +} + +jni::Local> Bitmap::CreateBitmap(jni::JNIEnv& env, + jni::jint width, + jni::jint height, + const jni::Object& config) { + static auto& _class = jni::Class::Singleton(env); + static auto method = _class.GetStaticMethod (jni::jint, jni::jint, jni::Object)>(env, "createBitmap"); + + return _class.Call(env, method, width, height, config); +} + +PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, const jni::Object& bitmap) { + AndroidBitmapInfo info; + const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info); + if (result != ANDROID_BITMAP_RESULT_SUCCESS) { + throw std::runtime_error("bitmap decoding: couldn't get bitmap info"); + } + if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { + return Bitmap::GetImage(env, Bitmap::Copy(env, bitmap)); + } + + PixelGuard guard(env, bitmap); + + // Copy the Android Bitmap into the PremultipliedImage. + auto pixels = + std::make_unique(info.width * info.height * PremultipliedImage::channels); + for (uint32_t y = 0; y < info.height; y++) { + auto begin = guard.get() + y * info.stride; + std::copy(begin, begin + info.width * PremultipliedImage::channels, + pixels.get() + y * info.width * PremultipliedImage::channels); + } + + return { Size{ info.width, info.height }, std::move(pixels) }; +} + +jni::Local> Bitmap::CreateBitmap(jni::JNIEnv& env, const PremultipliedImage& image) { + auto bitmap = CreateBitmap(env, image.size.width, image.size.height, Config::ARGB_8888); + + AndroidBitmapInfo info; + const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info); + if (result != ANDROID_BITMAP_RESULT_SUCCESS) { + // TODO: more specific information + throw std::runtime_error("bitmap creation: couldn't get bitmap info"); + } + + assert(info.width == image.size.width); + assert(info.height == image.size.height); + assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888); + + PixelGuard guard(env, bitmap); + + // Copy the PremultipliedImage into the Android Bitmap + for (uint32_t y = 0; y < image.size.height; y++) { + auto begin = image.data.get() + y * image.stride(); + std::copy(begin, begin + image.stride(), guard.get() + y * info.stride); + } + + return bitmap; +} + +jni::Local> Bitmap::Copy(jni::JNIEnv& env, const jni::Object& bitmap) { + static auto& klass = jni::Class::Singleton(env); + static auto copy = klass.GetMethod (jni::Object, jni::jboolean)>(env, "copy"); + + return bitmap.Call(env, copy, Bitmap::Config::Create(env, Bitmap::Config::Value::ARGB_8888), jni::jni_false); +} + +} // namespace android +} // namespace mbgl diff --git a/src/bitmap.hpp b/src/bitmap.hpp new file mode 100644 index 000000000..9d96405c2 --- /dev/null +++ b/src/bitmap.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class Bitmap { +public: + class Config { + public: + static constexpr auto Name() { return "android/graphics/Bitmap$Config"; }; + + enum Value { + ALPHA_8, + ARGB_4444, + ARGB_8888, + RGB_565, + }; + + static jni::Local> Create(jni::JNIEnv&, Value); + }; + + static constexpr auto Name() { return "android/graphics/Bitmap"; }; + static void registerNative(jni::JNIEnv&); + + static jni::Local> + CreateBitmap(jni::JNIEnv&, jni::jint width, jni::jint height, const jni::Object&); + + static jni::Local> + CreateBitmap(jni::JNIEnv& env, jni::jint width, jni::jint height, Config::Value config) { + return CreateBitmap(env, width, height, Config::Create(env, config)); + } + + static PremultipliedImage GetImage(jni::JNIEnv&, const jni::Object&); + static jni::Local> CreateBitmap(jni::JNIEnv&, const PremultipliedImage&); + static jni::Local> Copy(jni::JNIEnv&, const jni::Object&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/bitmap_factory.cpp b/src/bitmap_factory.cpp new file mode 100644 index 000000000..170bd52ea --- /dev/null +++ b/src/bitmap_factory.cpp @@ -0,0 +1,25 @@ +#include "bitmap_factory.hpp" + +namespace mbgl { +namespace android { + +void BitmapFactory::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> BitmapFactory::DecodeByteArray(jni::JNIEnv& env, + jni::Array& data, + jni::jint offset, + jni::jint length) { + static auto& _class = jni::Class::Singleton(env); + + // Images are loaded with ARGB_8888 config, and premultiplied by default, which is exactly + // what we want, so we're not providing a BitmapFactory.Options object. + using Signature = jni::Object (jni::Array, jni::jint, jni::jint); + static auto method = _class.GetStaticMethod(env, "decodeByteArray"); + + return _class.Call(env, method, data, offset, length); +} + +} // namespace android +} // namespace mbgl diff --git a/src/bitmap_factory.hpp b/src/bitmap_factory.hpp new file mode 100644 index 000000000..f73b7a290 --- /dev/null +++ b/src/bitmap_factory.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "bitmap.hpp" + +namespace mbgl { +namespace android { + +class BitmapFactory { +public: + static constexpr auto Name() { return "android/graphics/BitmapFactory"; }; + static void registerNative(jni::JNIEnv&); + + static jni::Local> + DecodeByteArray(jni::JNIEnv&, jni::Array& data, jni::jint offset, jni::jint length); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/connectivity_listener.cpp b/src/connectivity_listener.cpp new file mode 100644 index 000000000..9c13f1f74 --- /dev/null +++ b/src/connectivity_listener.cpp @@ -0,0 +1,41 @@ +#include "connectivity_listener.hpp" + +#include +#include + +#include + +namespace mbgl { +namespace android { + + /** + * Invoked when the construction is initiated from the jvm + */ + ConnectivityListener::ConnectivityListener(jni::JNIEnv&) {} + + ConnectivityListener::~ConnectivityListener() {} + + void ConnectivityListener::onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean connected) { + NetworkStatus::Set(connected ? NetworkStatus::Status::Online : NetworkStatus::Status::Offline); + } + + void ConnectivityListener::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + std::make_unique, + "initialize", + "finalize", + METHOD(&ConnectivityListener::onConnectivityStateChanged, "nativeOnConnectivityStateChanged") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/connectivity_listener.hpp b/src/connectivity_listener.hpp new file mode 100644 index 000000000..a09507c0f --- /dev/null +++ b/src/connectivity_listener.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class ConnectivityListener : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/net/NativeConnectivityListener"; }; + + static void registerNative(jni::JNIEnv&); + + /* + * Called when a Java object was created from the jvm side + */ + ConnectivityListener(jni::JNIEnv&); + + ~ConnectivityListener(); + + void onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean); + +}; + +} // namespace android +} // namespace mbgl diff --git a/src/conversion/collection.cpp b/src/conversion/collection.cpp new file mode 100644 index 000000000..954a161ba --- /dev/null +++ b/src/conversion/collection.cpp @@ -0,0 +1,32 @@ +#include "collection.hpp" +#include "constant.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector toVector(JNIEnv& env, const jni::Array& array) { + std::size_t len = array.Length(env); + std::vector vector; + vector.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + vector.push_back(jni::Make(env, array.Get(env, i))); + } + + return vector; +} + +jni::Local> toArray(JNIEnv& env, const std::vector& vector) { + auto result = jni::Array::New(env, vector.size()); + + for (std::size_t i = 0; i < vector.size(); i++) { + result.Set(env, i, jni::Make(env, vector.at(i))); + } + + return result; +} + +} +} +} diff --git a/src/conversion/collection.hpp b/src/conversion/collection.hpp new file mode 100644 index 000000000..322ebb62e --- /dev/null +++ b/src/conversion/collection.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "conversion.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector toVector(JNIEnv& env, const jni::Array& array); +jni::Local> toArray(JNIEnv& env, const std::vector&); + +} +} +} diff --git a/src/conversion/color.cpp b/src/conversion/color.cpp new file mode 100644 index 000000000..ce85943e6 --- /dev/null +++ b/src/conversion/color.cpp @@ -0,0 +1,17 @@ +#include "color.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result Converter::operator()(jni::JNIEnv&, const int& color) const { + float r = (color >> 16) & 0xFF; + float g = (color >> 8) & 0xFF; + float b = (color) & 0xFF; + float a = (color >> 24) & 0xFF; + return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/conversion/color.hpp b/src/conversion/color.hpp new file mode 100644 index 000000000..2b4144b93 --- /dev/null +++ b/src/conversion/color.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "conversion.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter { + Result operator()(jni::JNIEnv&, const int& color) const; +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/conversion/constant.cpp b/src/conversion/constant.cpp new file mode 100644 index 000000000..a409e5dfd --- /dev/null +++ b/src/conversion/constant.cpp @@ -0,0 +1,57 @@ +#include "constant.hpp" +#include "collection.hpp" +#include "../style/formatted.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, bool>::operator()(jni::JNIEnv& env, const bool& value) const { + return jni::Box(env, value ? jni::jni_true : jni::jni_false); +} + +Result>> Converter>, float>::operator()(jni::JNIEnv& env, const float& value) const { + return jni::Box(env, value); +} + +Result>> Converter>, double>::operator()(jni::JNIEnv& env, const double& value) const { + return jni::Box(env, value); +} + +Result>> Converter>, std::string>::operator()(jni::JNIEnv& env, const std::string& value) const { + return jni::Make(env, value); +} + +Result>> Converter>, Color>::operator()(jni::JNIEnv& env, const Color& value) const { + return jni::Make(env, value.stringify()); +} + +Result>> Converter>, style::expression::Formatted>::operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const { + return Formatted::New(env, value); +} + +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + + for (std::size_t i = 0; i < value.size(); i++) { + result.Set(env, i, jni::Make(env, value.at(i))); + } + + return result; +} + +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + + for (std::size_t i = 0; i < value.size(); i++) { + result.Set(env, i, jni::Box(env, value.at(i))); + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/conversion/constant.hpp b/src/conversion/constant.hpp new file mode 100644 index 000000000..839e6e84d --- /dev/null +++ b/src/conversion/constant.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "conversion.hpp" + +#include +#include + +#include + +#include + +#include +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter>, bool> { + Result>> operator()(jni::JNIEnv& env, const bool& value) const; +}; + +template <> +struct Converter>, float> { + Result>> operator()(jni::JNIEnv& env, const float& value) const; +}; + +template <> +struct Converter>, double> { + Result>> operator()(jni::JNIEnv& env, const double& value) const; +}; + +/** + * All integrals. java is limited to 64 bit signed, so... + * TODO: use BigDecimal for > 64 / unsigned? + */ +template +struct Converter>, T, typename std::enable_if::value>::type> { + Result>> operator()(jni::JNIEnv& env, const T& value) const { + return jni::Box(env, jni::jlong(value)); + } +}; + +// TODO: convert integral types to primitive jni types + +template <> +struct Converter>, std::string> { + Result>> operator()(jni::JNIEnv& env, const std::string& value) const; +}; + +template <> +struct Converter>, Color> { + Result>> operator()(jni::JNIEnv& env, const Color& value) const; +}; + +template <> +struct Converter>, style::expression::Formatted> { + Result>> operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const; +}; + +template +struct Converter>, std::array> { + Result>> operator()(jni::JNIEnv& env, const std::array& value) const { + std::vector v; + for (const float& id : value) { + v.push_back(id); + } + return convert>, std::vector>(env, v); + } +}; + +template <> +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; +}; + +template <> +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; +}; + +template +struct Converter>, T, typename std::enable_if_t::value>> { + Result>> operator()(jni::JNIEnv& env, const T& value) const { + return convert>, std::string>(env, Enum::toString(value)); + } +}; + +template +struct Converter>, std::vector, typename std::enable_if_t::value>> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + for (std::size_t i = 0; i < value.size(); ++i) { + result.Set(env, i, jni::Make(env, Enum::toString(value.at(i)))); + } + return result; + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/src/conversion/conversion.hpp b/src/conversion/conversion.hpp new file mode 100644 index 000000000..d1766f975 --- /dev/null +++ b/src/conversion/conversion.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +struct Error { std::string message; }; + +template +class Result : private variant { +public: + using variant::variant; + + explicit operator bool() const { + return this->template is(); + } + + T& operator*() { + assert(this->template is()); + return this->template get(); + } + + const T& operator*() const { + assert(this->template is()); + return this->template get(); + } + + const Error& error() const { + assert(this->template is()); + return this->template get(); + } +}; + +template +struct Converter; + +template +Result convert(jni::JNIEnv& env, const V& value, Args&&...args) { + return Converter()(env, value, std::forward(args)...); +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/src/example_custom_layer.cpp b/src/example_custom_layer.cpp new file mode 100644 index 000000000..e80553254 --- /dev/null +++ b/src/example_custom_layer.cpp @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include + +// DEBUGGING + +const char* LOG_TAG = "Custom Layer Example"; + +const char* stringFromError(GLenum err) { + switch (err) { + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; +#endif + +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; +#endif + +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; +#endif + +#ifdef GL_CONTEXT_LOST + case GL_CONTEXT_LOST: + return "GL_CONTEXT_LOST"; +#endif + + default: + return "GL_UNKNOWN"; + } +} + +struct Error : std::runtime_error { + using std::runtime_error::runtime_error; +}; + +void checkError(const char *cmd, const char *file, int line) { + + GLenum err = GL_NO_ERROR; + if ((err = glGetError()) != GL_NO_ERROR) { + std::ostringstream message; + message << cmd << ": Error " << stringFromError(err); + + // Check for further errors + while ((err = glGetError()) != GL_NO_ERROR) { + message << ", " << stringFromError(err); + } + + message << " at " << file << ":" << line; + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, message.str().c_str()); + throw Error(message.str()); + } +} + +#ifndef NDEBUG +#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) +#else +#define GL_CHECK_ERROR(cmd) (cmd) +#endif + +void checkLinkStatus(GLuint program) { + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + GLchar infoLog[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &infoLog[0]); + throw Error(infoLog); + } + +} + +void checkCompileStatus(GLuint shader) { + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + GLchar errorLog[maxLength]; + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &errorLog[0]); + throw Error(errorLog); + } +} + +// /DEBUGGING + +static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; +static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; + +class ExampleCustomLayer: mbgl::style::CustomLayerHost { +public: + ~ExampleCustomLayer() { + } + + void initialize() { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Initialize"); + + // Debug info + int maxAttrib; + GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Max vertex attributes: %i", maxAttrib); + + program = GL_CHECK_ERROR(glCreateProgram()); + vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); + fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); + + GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(vertexShader)); + checkCompileStatus(vertexShader); + GL_CHECK_ERROR(glAttachShader(program, vertexShader)); + GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(fragmentShader)); + checkCompileStatus(fragmentShader); + GL_CHECK_ERROR(glAttachShader(program, fragmentShader)); + GL_CHECK_ERROR(glLinkProgram(program)); + checkLinkStatus(program); + + a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color")); + + GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; + GL_CHECK_ERROR(glGenBuffers(1, &buffer)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); + } + + void render(const mbgl::style::CustomLayerRenderParameters&) { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); + glUseProgram(program); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glUniform4fv(fill_color, 1, color); + + GL_CHECK_ERROR(glUseProgram(program)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); + GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL)); + GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); + GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST)); + GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color)); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + + } + + void contextLost() { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "ContextLost"); + program = 0; + } + + void deinitialize() { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "DeInitialize"); + if (program) { + glDeleteBuffers(1, &buffer); + glDetachShader(program, vertexShader); + glDetachShader(program, fragmentShader); + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + glDeleteProgram(program); + } + } + + GLuint program = 0; + GLuint vertexShader = 0; + GLuint fragmentShader = 0; + GLuint buffer = 0; + GLuint a_pos = 0; + GLuint fill_color = 0; + + static GLfloat color[]; +}; + +GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; + +jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); + auto exampleCustomLayer = std::make_unique(); + return reinterpret_cast(exampleCustomLayer.release()); +} + +void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); + ExampleCustomLayer::color[0] = red; + ExampleCustomLayer::color[1] = green; + ExampleCustomLayer::color[2] = blue; + ExampleCustomLayer::color[3] = alpha; +} + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); + + JNIEnv *env = nullptr; + vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + jclass customLayerClass = env->FindClass("com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer"); + + JNINativeMethod methods[] = { + {"createContext", "()J", reinterpret_cast(&nativeCreateContext)}, + {"setColor", "(FFFF)V", reinterpret_cast(&nativeSetColor)} + }; + + if (env->RegisterNatives(customLayerClass, methods, 2) < 0) { + env->ExceptionDescribe(); + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} + +extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *, void *) { +} diff --git a/src/file_source.cpp b/src/file_source.cpp new file mode 100644 index 000000000..05b57e5d1 --- /dev/null +++ b/src/file_source.cpp @@ -0,0 +1,202 @@ +#include "file_source.hpp" +#include "attach_env.hpp" + +#include +#include +#include +#include +#include + +#include + +#include "asset_manager_file_source.hpp" + +namespace mbgl { + +std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { + auto* assetFileSource = reinterpret_cast(options.platformContext()); + auto fileSource = std::make_shared(options.cachePath(), std::unique_ptr(assetFileSource)); + fileSource->setAccessToken(options.accessToken()); + return fileSource; +} + +namespace android { + +// FileSource // + +FileSource::FileSource(jni::JNIEnv& _env, + const jni::String& accessToken, + const jni::String& _cachePath, + const jni::Object& assetManager) { + std::string path = jni::Make(_env, _cachePath); + mapbox::sqlite::setTempPath(path); + + resourceOptions + .withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE) + .withPlatformContext(reinterpret_cast(new AssetManagerFileSource(_env, assetManager))); + + // Create a core default file source + fileSource = std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(resourceOptions)); +} + +FileSource::~FileSource() { +} + +jni::Local FileSource::getAccessToken(jni::JNIEnv& env) { + return jni::Make(env, fileSource->getAccessToken()); +} + +void FileSource::setAccessToken(jni::JNIEnv& env, const jni::String& token) { + fileSource->setAccessToken(token ? jni::Make(env, token) : ""); +} + +void FileSource::setAPIBaseUrl(jni::JNIEnv& env, const jni::String& url) { + fileSource->setAPIBaseURL(jni::Make(env, url)); +} + +void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object& transformCallback) { + if (transformCallback) { + auto global = jni::NewGlobal(env, transformCallback); + resourceTransform = std::make_unique>(*Scheduler::GetCurrent(), + // Capture the ResourceTransformCallback object as a managed global into + // the lambda. It is released automatically when we're setting a new ResourceTransform in + // a subsequent call. + // Note: we're converting it to shared_ptr because this lambda is converted to a std::function, + // which requires copyability of its captured variables. + [callback = std::make_shared(std::move(global))] + (mbgl::Resource::Kind kind, const std::string&& url_) { + android::UniqueEnv _env = android::AttachEnv(); + return FileSource::ResourceTransformCallback::onURL(*_env, *callback, int(kind), url_); + }); + fileSource->setResourceTransform(resourceTransform->self()); + } else { + // Reset the callback + resourceTransform.reset(); + fileSource->setResourceTransform({}); + } +} + +void FileSource::setResourceCachePath(jni::JNIEnv& env, const jni::String& path, + const jni::Object& _callback) { + if (pathChangeCallback) { + FileSource::ResourcesCachePathChangeCallback::onError(env, _callback, jni::Make(env, "Another resources cache path change is in progress")); + return; + } + + std::string newPath = jni::Make(env, path); + mapbox::sqlite::setTempPath(newPath); + + auto global = jni::NewGlobal(env, _callback); + pathChangeCallback = std::make_unique>(*Scheduler::GetCurrent(), + [this, callback = std::make_shared(std::move(global)), newPath] { + android::UniqueEnv _env = android::AttachEnv(); + FileSource::ResourcesCachePathChangeCallback::onSuccess(*_env, *callback, jni::Make(*_env, newPath)); + pathChangeCallback.reset(); + }); + + fileSource->setResourceCachePath(newPath + DATABASE_FILE, pathChangeCallback->self()); +} + +void FileSource::resume(jni::JNIEnv&) { + if (!activationCounter) { + activationCounter = optional(1) ; + return; + } + + activationCounter.value()++; + if (activationCounter == 1) { + fileSource->resume(); + } +} + +void FileSource::pause(jni::JNIEnv&) { + if (activationCounter) { + activationCounter.value()--; + if (activationCounter == 0) { + fileSource->pause(); + } + } +} + +jni::jboolean FileSource::isResumed(jni::JNIEnv&) { + if (activationCounter) { + return (jboolean) (activationCounter > 0); + } + return (jboolean) false; +} + +FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object& jFileSource) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "nativePtr"); + return reinterpret_cast(jFileSource.Get(env, field)); +} + +mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object& jFileSource) { + FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); + assert(fileSource != nullptr); + return fileSource->resourceOptions.clone(); +} + +// FileSource::ResourcesCachePathChangeCallback // + +void FileSource::ResourcesCachePathChangeCallback::onSuccess(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& path) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onSuccess"); + + callback.Call(env, method, path); +} + +void FileSource::ResourcesCachePathChangeCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& message) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, message); +} + +void FileSource::registerNative(jni::JNIEnv& env) { + // Ensure the classes are cached. If they're requested for the + // first time on a background thread, Android's class loader heuristics will fail. + // https://developer.android.com/training/articles/perf-jni#faq_FindClass + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&FileSource::getAccessToken, "getAccessToken"), + METHOD(&FileSource::setAccessToken, "setAccessToken"), + METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), + METHOD(&FileSource::setResourceTransform, "setResourceTransform"), + METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), + METHOD(&FileSource::resume, "activate"), + METHOD(&FileSource::pause, "deactivate"), + METHOD(&FileSource::isResumed, "isActivated") + ); +} + + +// FileSource::ResourceTransformCallback // + +std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, const jni::Object& callback, int kind, std::string url_) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onURL"); + + return jni::Make(env, + callback.Call(env, method, kind, + jni::Make(env, url_))); +} + +} // namespace android +} // namespace mbgl diff --git a/src/file_source.hpp b/src/file_source.hpp new file mode 100644 index 000000000..f3ad33eb3 --- /dev/null +++ b/src/file_source.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include +#include + +#include "asset_manager.hpp" + +#include + +namespace mbgl { + +template class Actor; +class ResourceTransform; +using mbgl::PathChangeCallback; + +namespace android { + +/** + * Peer class for the Android FileSource holder. Ensures that a single DefaultFileSource is used + */ +class FileSource { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; }; + + struct ResourceTransformCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; } + + static std::string onURL(jni::JNIEnv&, const jni::Object&, int, std::string); + }; + + struct ResourcesCachePathChangeCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourcesCachePathChangeCallback";} + + static void onSuccess(jni::JNIEnv&, + const jni::Object&, + const jni::String&); + + static void onError(jni::JNIEnv&, + const jni::Object&, + const jni::String&); + }; + + FileSource(jni::JNIEnv&, const jni::String&, const jni::String&, const jni::Object&); + + ~FileSource(); + + jni::Local getAccessToken(jni::JNIEnv&); + + void setAccessToken(jni::JNIEnv&, const jni::String&); + + void setAPIBaseUrl(jni::JNIEnv&, const jni::String&); + + void setResourceTransform(jni::JNIEnv&, const jni::Object&); + + void setResourceCachePath(jni::JNIEnv&, const jni::String&, const jni::Object&); + + void resume(jni::JNIEnv&); + + void pause(jni::JNIEnv&); + + jni::jboolean isResumed(jni::JNIEnv&); + + static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object&); + + static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); + +private: + const std::string DATABASE_FILE = "/mbgl-offline.db"; + optional activationCounter; + mbgl::ResourceOptions resourceOptions; + std::unique_ptr> resourceTransform; + std::unique_ptr> pathChangeCallback; + std::shared_ptr fileSource; +}; + + +} // namespace android +} // namespace mbgl diff --git a/src/geojson/feature.cpp b/src/geojson/feature.cpp new file mode 100644 index 000000000..8d30404a5 --- /dev/null +++ b/src/geojson/feature.cpp @@ -0,0 +1,79 @@ +#include "feature.hpp" +#include "geometry.hpp" +#include "../gson/json_object.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +using namespace gson; + +mbgl::Feature Feature::convert(jni::JNIEnv& env, const jni::Object& jFeature) { + static auto& javaClass = jni::Class::Singleton(env); + static auto id = javaClass.GetMethod(env, "id"); + static auto geometry = javaClass.GetMethod ()>(env, "geometry"); + static auto properties = javaClass.GetMethod ()>(env, "properties"); + + auto jId = jFeature.Call(env, id); + + using mbid = mapbox::feature::identifier; + + return mbgl::Feature { + Geometry::convert(env, jFeature.Call(env, geometry)), + JsonObject::convert(env, jFeature.Call(env, properties)), + jId ? mbid { jni::Make(env, jId) } : mbid { mapbox::feature::null_value } + }; +} + +/** + * Turn feature identifier into std::string + */ +class FeatureIdVisitor { +public: + template + std::string operator()(const T& i) const { + return util::toString(i); + } + + std::string operator()(const std::string& i) const { + return i; + } + + std::string operator()(const std::nullptr_t&) const { + return {}; + } + + std::string operator()(const mapbox::feature::null_value_t&) const { + return {}; + } +}; + +jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::Feature& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); + + return javaClass.Call(env, method, + Geometry::New(env, value.geometry), + JsonObject::New(env, value.properties), + jni::Make(env, value.id.is() ? std::string {} : value.id.match(FeatureIdVisitor()))); +} + +jni::Local>> Feature::convert(jni::JNIEnv& env, const std::vector& value) { + auto features = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); i = i + 1) { + features.Set(env, i, convertFeature(env, value.at(i))); + } + + return features; +} + +void Feature::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/src/geojson/feature.hpp b/src/geojson/feature.hpp new file mode 100644 index 000000000..fdf5d977b --- /dev/null +++ b/src/geojson/feature.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Feature { +public: + static constexpr auto Name() { return "com/mapbox/geojson/Feature"; }; + + static mbgl::Feature convert(jni::JNIEnv&, const jni::Object&); + static jni::Local>> convert(jni::JNIEnv&, const std::vector&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/feature_collection.cpp b/src/geojson/feature_collection.cpp new file mode 100644 index 000000000..f90d5226b --- /dev/null +++ b/src/geojson/feature_collection.cpp @@ -0,0 +1,37 @@ +#include "feature_collection.hpp" + +#include "feature.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, const jni::Object& jCollection) { + auto collection = mbgl::FeatureCollection(); + + if (jCollection) { + auto jFeatureList = FeatureCollection::features(env, jCollection); + auto jFeatures = java::util::List::toArray(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + collection.reserve(size); + + for (size_t i = 0; i < size; i++) { + collection.push_back(Feature::convert(env, jFeatures.Get(env, i))); + } + } + return collection; +} + +jni::Local> FeatureCollection::features(jni::JNIEnv& env, const jni::Object& jCollection) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "features"); + return jCollection.Call(env, method); +} + +void FeatureCollection::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/feature_collection.hpp b/src/geojson/feature_collection.hpp new file mode 100644 index 000000000..66e92eaca --- /dev/null +++ b/src/geojson/feature_collection.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../java/util.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class FeatureCollection { +public: + static constexpr auto Name() { return "com/mapbox/geojson/FeatureCollection"; }; + + static mbgl::FeatureCollection convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> features(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry.cpp b/src/geojson/geometry.cpp new file mode 100644 index 000000000..0598b9fc5 --- /dev/null +++ b/src/geojson/geometry.cpp @@ -0,0 +1,97 @@ +#include "geometry.hpp" + +#include "point.hpp" +#include "multi_point.hpp" +#include "line_string.hpp" +#include "multi_line_string.hpp" +#include "polygon.hpp" +#include "multi_polygon.hpp" +#include "geometry_collection.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +/** + * Turn mapbox::geometry type into Java GeoJson Geometries + */ +class GeometryEvaluator { +public: + + jni::JNIEnv& env; + + jni::Local> operator()(const mbgl::EmptyGeometry &) const { + // FIXME: mapbox-java needs to have its own Empty type. + return GeometryCollection::New(env, {}); + } + + jni::Local> operator()(const mbgl::Point &geometry) const { + return Point::New(env, geometry); + } + + jni::Local> operator()(const mbgl::LineString &geometry) const { + return LineString::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiLineString &geometry) const { + return MultiLineString::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiPoint &geometry) const { + return MultiPoint::New(env, geometry); + } + + jni::Local> operator()(const mbgl::Polygon &geometry) const { + return Polygon::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiPolygon &geometry) const { + return MultiPolygon::New(env, geometry); + } + + jni::Local> operator()(const mapbox::geometry::geometry_collection &geometry) const { + return GeometryCollection::New(env, geometry); + } +}; + +jni::Local> Geometry::New(jni::JNIEnv& env, mbgl::Geometry geometry) { + GeometryEvaluator evaluator { env } ; + return mbgl::Geometry::visit(geometry, evaluator); +} + +mbgl::Geometry Geometry::convert(jni::JNIEnv &env, const jni::Object& jGeometry) { + auto type = Geometry::getType(env, jGeometry); + if (type == Point::Type()) { + return { Point::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiPoint::Type()) { + return { MultiPoint::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == LineString::Type()) { + return { LineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiLineString::Type()) { + return { MultiLineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == Polygon::Type()) { + return { Polygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiPolygon::Type()) { + return { MultiPolygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == GeometryCollection::Type()) { + return { GeometryCollection::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } + + throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); +} + +std::string Geometry::getType(jni::JNIEnv &env, const jni::Object& jGeometry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "type"); + return jni::Make(env, jGeometry.Call(env, method)); +} + +void Geometry::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/src/geojson/geometry.hpp b/src/geojson/geometry.hpp new file mode 100644 index 000000000..4bf55c858 --- /dev/null +++ b/src/geojson/geometry.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Geometry { +public: + static constexpr auto Name() { return "com/mapbox/geojson/Geometry"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::Geometry); + + static mbgl::Geometry convert(jni::JNIEnv&, const jni::Object&); + + static std::string getType(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry_collection.cpp b/src/geojson/geometry_collection.cpp new file mode 100644 index 000000000..cca909126 --- /dev/null +++ b/src/geojson/geometry_collection.cpp @@ -0,0 +1,47 @@ +#include "geometry_collection.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> GeometryCollection::New(jni::JNIEnv& env, const mapbox::geometry::geometry_collection& collection) { + // Create an array of geometries + auto jarray = jni::Array>::New(env, collection.size()); + + for (size_t i = 0; i < collection.size(); i++) { + jarray.Set(env, i, Geometry::New(env, collection.at(i))); + } + + // create the GeometryCollection + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromGeometries"); + return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); +} + +mapbox::geometry::geometry_collection GeometryCollection::convert(jni::JNIEnv &env, const jni::Object& jCollection) { + // Get geometries + static auto& javaClass = jni::Class::Singleton(env); + static auto getGeometries = javaClass.GetMethod ()>(env, "geometries"); + + // Turn into array + auto jarray = java::util::List::toArray(env, jCollection.Call(env, getGeometries)); + + // Convert each geometry + mapbox::geometry::geometry_collection collection{}; + + auto size = jarray.Length(env); + for (jni::jsize i = 0; i < size; i++) { + collection.push_back(Geometry::convert(env, jarray.Get(env, i))); + } + + return collection; +} + +void GeometryCollection::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry_collection.hpp b/src/geojson/geometry_collection.hpp new file mode 100644 index 000000000..9f02ac848 --- /dev/null +++ b/src/geojson/geometry_collection.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class GeometryCollection { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/GeometryCollection"; }; + static constexpr auto Type() { return "GeometryCollection"; }; + + static jni::Local> New(jni::JNIEnv&, const mapbox::geometry::geometry_collection&); + + static mapbox::geometry::geometry_collection convert(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/line_string.cpp b/src/geojson/line_string.cpp new file mode 100644 index 000000000..ae1345c95 --- /dev/null +++ b/src/geojson/line_string.cpp @@ -0,0 +1,55 @@ +#include "line_string.hpp" +#include "point.hpp" +#include "util.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> LineString::New(jni::JNIEnv& env, const mbgl::LineString& lineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsList(env, lineString)); +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object& jLineString) { + mapbox::geojson::line_string lineString; + + if (jLineString) { + lineString = LineString::convert(env, LineString::coordinates(env, jLineString)); + } + + return lineString; +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object*/>& jPointList) { + mapbox::geojson::line_string lineString; + + if (jPointList) { + auto jPointArray = java::util::List::toArray(env, jPointList); + auto size = jPointArray.Length(env); + lineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + lineString.push_back(Point::convert(env, jPointArray.Get(env, i))); + } + } + + return lineString; +} + +jni::Local> LineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jLineString.Call(env, method); +} + +void LineString::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/line_string.hpp b/src/geojson/line_string.hpp new file mode 100644 index 000000000..906d809fa --- /dev/null +++ b/src/geojson/line_string.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + + +class LineString { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/LineString"; }; + static constexpr auto Type() { return "LineString"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::LineString&); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object&); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_line_string.cpp b/src/geojson/multi_line_string.cpp new file mode 100644 index 000000000..1aaf53c01 --- /dev/null +++ b/src/geojson/multi_line_string.cpp @@ -0,0 +1,56 @@ +#include "multi_line_string.hpp" + +#include "line_string.hpp" +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiLineString::New(jni::JNIEnv& env, const mbgl::MultiLineString& multiLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsListsList(env, multiLineString)); +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object& jMultiLineString) { + mapbox::geojson::multi_line_string multiLineString; + + if (jMultiLineString) { + multiLineString = MultiLineString::convert(env, MultiLineString::coordinates(env, jMultiLineString)); + } + + return multiLineString; +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { + mapbox::geojson::multi_line_string multiLineString; + + if (jPointListsList) { + auto jPositionListsArray = java::util::List::toArray(env, jPointListsList); + + auto size = jPositionListsArray.Length(env); + multiLineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + multiLineString.push_back(LineString::convert(env, jPositionListsArray.Get(env, i))); + } + } + + return multiLineString; +} + +jni::Local> MultiLineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jLineString.Call(env, method); +} + +void MultiLineString::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_line_string.hpp b/src/geojson/multi_line_string.hpp new file mode 100644 index 000000000..65ce43bd1 --- /dev/null +++ b/src/geojson/multi_line_string.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "../java/util.hpp" +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiLineString { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiLineString"; }; + static constexpr auto Type() { return "MultiLineString"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiLineString&); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object&); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object>*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_point.cpp b/src/geojson/multi_point.cpp new file mode 100644 index 000000000..d530ef721 --- /dev/null +++ b/src/geojson/multi_point.cpp @@ -0,0 +1,41 @@ +#include "multi_point.hpp" + +#include "line_string.hpp" + +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiPoint::New(JNIEnv& env, const mbgl::MultiPoint& multiPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsList(env, multiPoint)); +} + +mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv& env, const jni::Object& jMultiPoint) { + mapbox::geojson::multi_point multiPoint; + + if (jMultiPoint) { + multiPoint = convertExplicit( + LineString::convert(env, MultiPoint::coordinates(env, jMultiPoint))); + } + + return multiPoint; +} + +jni::Local> MultiPoint::coordinates(jni::JNIEnv& env, const jni::Object& jMultiPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jMultiPoint.Call(env, method); +} + +void MultiPoint::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_point.hpp b/src/geojson/multi_point.hpp new file mode 100644 index 000000000..a3ca49b73 --- /dev/null +++ b/src/geojson/multi_point.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPoint { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPoint"; }; + static constexpr auto Type() { return "MultiPoint"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPoint&); + + static mapbox::geojson::multi_point convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_polygon.cpp b/src/geojson/multi_polygon.cpp new file mode 100644 index 000000000..3c5c3ec33 --- /dev/null +++ b/src/geojson/multi_polygon.cpp @@ -0,0 +1,53 @@ +#include "multi_polygon.hpp" + +#include "polygon.hpp" +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiPolygon::New(JNIEnv& env, const mbgl::MultiPolygon& multiPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + auto jarray = jni::Array>::New(env, multiPolygon.size()); + + for (size_t i = 0; i < multiPolygon.size(); i++) { + jarray.Set(env, i, asPointsListsList(env, multiPolygon.at(i))); + } + + return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); +} + +mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv& env, const jni::Object& jMultiPolygon) { + mapbox::geojson::multi_polygon multiPolygon; + + if (jMultiPolygon) { + auto jPointListsListList = MultiPolygon::coordinates(env, jMultiPolygon); + auto jPointListsListArray = java::util::List::toArray(env, jPointListsListList); + + auto size = jPointListsListArray.Length(env); + multiPolygon.reserve(size); + + for (size_t i = 0; i < size; i++) { + multiPolygon.push_back(Polygon::convert(env, jPointListsListArray.Get(env, i))); + } + } + + return multiPolygon; +} + +jni::Local> MultiPolygon::coordinates(jni::JNIEnv& env, const jni::Object& jPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jPolygon.Call(env, method); +} + +void MultiPolygon::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_polygon.hpp b/src/geojson/multi_polygon.hpp new file mode 100644 index 000000000..fd7b08016 --- /dev/null +++ b/src/geojson/multi_polygon.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "../java/util.hpp" +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPolygon { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPolygon"; }; + static constexpr auto Type() { return "MultiPolygon"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPolygon&); + + static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/point.cpp b/src/geojson/point.cpp new file mode 100644 index 000000000..2000447c0 --- /dev/null +++ b/src/geojson/point.cpp @@ -0,0 +1,34 @@ +#include "point.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> Point::New(jni::JNIEnv& env, const mbgl::Point& point) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::jdouble, jni::jdouble)>(env, "fromLngLat"); + return javaClass.Call(env, method, point.x, point.y); +} + +mbgl::Point Point::convert(jni::JNIEnv &env, const jni::Object& jPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto longitude = javaClass.GetMethod(env, "longitude"); + static auto latitude = javaClass.GetMethod(env, "latitude"); + + if (!jPoint) { + return {}; + } + + return { + jPoint.Call(env, longitude), + jPoint.Call(env, latitude) + }; +} + +void Point::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/src/geojson/point.hpp b/src/geojson/point.hpp new file mode 100644 index 000000000..b5d71ecae --- /dev/null +++ b/src/geojson/point.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Point { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/Point"; }; + static constexpr auto Type() { return "Point"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Point&); + static mbgl::Point convert(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/polygon.cpp b/src/geojson/polygon.cpp new file mode 100644 index 000000000..4437d134a --- /dev/null +++ b/src/geojson/polygon.cpp @@ -0,0 +1,55 @@ +#include "polygon.hpp" + +#include "multi_line_string.hpp" + +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> Polygon::New(jni::JNIEnv& env, const mbgl::Polygon& polygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsListsList(env, polygon)); +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object& jPolygon) { + mapbox::geojson::polygon polygon; + + if (jPolygon) { + polygon = Polygon::convert(env, Polygon::coordinates(env, jPolygon)); + } + + return polygon; +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { + mapbox::geojson::polygon polygon; + + if (jPointListsList) { + auto multiLine = MultiLineString::convert(env, jPointListsList); + polygon.reserve(multiLine.size()); + for (auto&& line : multiLine) { + polygon.emplace_back(convertExplicit(std::move(line))); + } + } + + return polygon; +} + + +jni::Local> Polygon::coordinates(jni::JNIEnv &env, const jni::Object& jPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jPolygon.Call(env, method); +} + +void Polygon::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/polygon.hpp b/src/geojson/polygon.hpp new file mode 100644 index 000000000..8e1761fed --- /dev/null +++ b/src/geojson/polygon.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + + +namespace mbgl { +namespace android { +namespace geojson { + +class Polygon { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/Polygon"; }; + static constexpr auto Type() { return "Polygon"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Polygon&); + + static mapbox::geojson::polygon convert(jni::JNIEnv &, const jni::Object&); + + static mapbox::geojson::polygon convert(jni::JNIEnv&, const jni::Object>*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv &); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/util.hpp b/src/geojson/util.hpp new file mode 100644 index 000000000..59154516f --- /dev/null +++ b/src/geojson/util.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "point.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +// Clang 3.8 fails to implicitly convert matching types, so we'll have to do it explicitly. +template +To convertExplicit(From&& src) { + static_assert(std::is_same::container_type, + typename To::container_type>::value, + "container types do not match"); + static_assert(std::is_rvalue_reference::value, + "argument must be rvalue reference"); + return *reinterpret_cast>(&src); +} + +/** + * Geometry -> List + */ +template +static jni::Local> asPointsList(jni::JNIEnv& env, const T& pointsList) { + auto jarray = jni::Array>::New(env, pointsList.size()); + + for (jni::jsize i = 0; i < pointsList.size(); i++) { + jarray.Set(env, i, Point::New(env, pointsList.at(i))); + } + + return java::util::Arrays::asList(env, jarray); +} + +/** + * Geometry -> List> + */ +template +static jni::Local> asPointsListsList(JNIEnv& env, const SHAPE& value) { + auto jarray = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); i++) { + jarray.Set(env, i, asPointsList(env, value[i])); + } + + return java::util::Arrays::asList(env, jarray); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/src/geometry/lat_lng.cpp b/src/geometry/lat_lng.cpp new file mode 100644 index 000000000..5d8313cb2 --- /dev/null +++ b/src/geometry/lat_lng.cpp @@ -0,0 +1,29 @@ +#include "lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLng::New(jni::JNIEnv& env, const mbgl::LatLng& latLng) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, latLng.latitude(), latLng.longitude()); +} + +mbgl::Point LatLng::getGeometry(jni::JNIEnv& env, const jni::Object& latLng) { + static auto& javaClass = jni::Class::Singleton(env); + static auto latitudeField = javaClass.GetField(env, "latitude"); + static auto longitudeField = javaClass.GetField(env, "longitude"); + return mbgl::Point(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField)); +} + +mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, const jni::Object& latLng) { + auto point = LatLng::getGeometry(env, latLng); + return mbgl::LatLng(point.y, point.x); +} + +void LatLng::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng.hpp b/src/geometry/lat_lng.hpp new file mode 100644 index 000000000..30b7db1ef --- /dev/null +++ b/src/geometry/lat_lng.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include + +namespace mbgl { +namespace android { + +class LatLng : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::LatLng&); + + static mbgl::Point getGeometry(jni::JNIEnv&, const jni::Object&); + + static mbgl::LatLng getLatLng(jni::JNIEnv&, const jni::Object&); + + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_bounds.cpp b/src/geometry/lat_lng_bounds.cpp new file mode 100644 index 000000000..cf534a06e --- /dev/null +++ b/src/geometry/lat_lng_bounds.cpp @@ -0,0 +1,30 @@ +#include "lat_lng_bounds.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west()); +} + +mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, const jni::Object& bounds) { + static auto& javaClass = jni::Class::Singleton(env); + static auto swLatField = javaClass.GetField(env, "latitudeSouth"); + static auto swLonField = javaClass.GetField(env, "longitudeWest"); + static auto neLatField = javaClass.GetField(env, "latitudeNorth"); + static auto neLonField = javaClass.GetField(env, "longitudeEast"); + + mbgl::LatLng sw = { bounds.Get(env, swLatField), bounds.Get(env, swLonField) }; + mbgl::LatLng ne = { bounds.Get(env, neLatField), bounds.Get(env, neLonField) }; + + return mbgl::LatLngBounds::hull(sw, ne); +} + +void LatLngBounds::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_bounds.hpp b/src/geometry/lat_lng_bounds.hpp new file mode 100644 index 000000000..d51026711 --- /dev/null +++ b/src/geometry/lat_lng_bounds.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +namespace mbgl { +namespace android { + +class LatLngBounds : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::LatLngBounds); + + static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_quad.cpp b/src/geometry/lat_lng_quad.cpp new file mode 100644 index 000000000..1a1e49048 --- /dev/null +++ b/src/geometry/lat_lng_quad.cpp @@ -0,0 +1,37 @@ +#include "lat_lng_quad.hpp" +#include "lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLngQuad::New(jni::JNIEnv& env, std::array coordinates) { + static auto& javaClass = jni::Class::Singleton(env); + static auto quadConstructor = javaClass.GetConstructor, jni::Object, jni::Object, jni::Object>(env); + return javaClass.New(env, quadConstructor, + LatLng::New(env, coordinates[0]), + LatLng::New(env, coordinates[1]), + LatLng::New(env, coordinates[2]), + LatLng::New(env, coordinates[3])); +} + +std::array LatLngQuad::getLatLngArray(jni::JNIEnv& env, const jni::Object& quad) { + static auto& javaClass = jni::Class::Singleton(env); + static auto topLeftField = javaClass.GetField >(env, "topLeft"); + static auto topRightField = javaClass.GetField >(env, "topRight"); + static auto bottomRightField = javaClass.GetField >(env, "bottomRight"); + static auto bottomLeftField = javaClass.GetField >(env, "bottomLeft"); + + return std::array < mbgl::LatLng, 4 > {{ + LatLng::getLatLng(env, quad.Get(env, topLeftField)), + LatLng::getLatLng(env, quad.Get(env, topRightField)), + LatLng::getLatLng(env, quad.Get(env, bottomRightField)), + LatLng::getLatLng(env, quad.Get(env, bottomLeftField)) + }}; +} + +void LatLngQuad::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_quad.hpp b/src/geometry/lat_lng_quad.hpp new file mode 100644 index 000000000..f6560b57b --- /dev/null +++ b/src/geometry/lat_lng_quad.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace android { + +class LatLngQuad : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngQuad"; }; + + static jni::Local> New(jni::JNIEnv&, std::array); + + static std::array getLatLngArray(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/projected_meters.cpp b/src/geometry/projected_meters.cpp new file mode 100644 index 000000000..e079de006 --- /dev/null +++ b/src/geometry/projected_meters.cpp @@ -0,0 +1,17 @@ +#include "projected_meters.hpp" + +namespace mbgl { +namespace android { + +jni::Local> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, northing, easting); +} + +void ProjectedMeters::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/projected_meters.hpp b/src/geometry/projected_meters.hpp new file mode 100644 index 000000000..baad1efc8 --- /dev/null +++ b/src/geometry/projected_meters.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { + +class ProjectedMeters : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; }; + + static jni::Local> New(jni::JNIEnv&, double, double); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gl_functions.cpp b/src/gl_functions.cpp new file mode 100644 index 000000000..637788e4a --- /dev/null +++ b/src/gl_functions.cpp @@ -0,0 +1,156 @@ +#include + +#define GL_GLEXT_PROTOTYPES +#include +#include + +namespace mbgl { +namespace platform { + +void (* const glActiveTexture)(GLenum) = ::glActiveTexture; +void (* const glAttachShader)(GLuint, GLuint) = ::glAttachShader; +void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar *) = ::glBindAttribLocation; +void (* const glBindBuffer)(GLenum, GLuint) = ::glBindBuffer; +void (* const glBindFramebuffer)(GLenum, GLuint) = ::glBindFramebuffer; +void (* const glBindRenderbuffer)(GLenum, GLuint) = ::glBindRenderbuffer; +void (* const glBindTexture)(GLenum, GLuint) = ::glBindTexture; +void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glBlendColor; +void (* const glBlendEquation)(GLenum) = ::glBlendEquation; +void (* const glBlendEquationSeparate)(GLenum, GLenum) = ::glBlendEquationSeparate; +void (* const glBlendFunc)(GLenum, GLenum) = ::glBlendFunc; +void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glBlendFuncSeparate; +void (* const glBufferData)(GLenum, GLsizeiptr, const void *, GLenum) = ::glBufferData; +void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void *) = ::glBufferSubData; +GLenum (* const glCheckFramebufferStatus)(GLenum) = ::glCheckFramebufferStatus; +void (* const glClear)(GLbitfield) = ::glClear; +void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glClearColor; +void (* const glClearDepthf)(GLfloat) = ::glClearDepthf; +void (* const glClearStencil)(GLint) = ::glClearStencil; +void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean) = ::glColorMask; +void (* const glCompileShader)(GLuint) = ::glCompileShader; +void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void *) = ::glCompressedTexImage2D; +void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void *) = ::glCompressedTexSubImage2D; +void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) = ::glCopyTexImage2D; +void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) = ::glCopyTexSubImage2D; +GLuint (* const glCreateProgram)() = ::glCreateProgram; +GLuint (* const glCreateShader)(GLenum) = ::glCreateShader; +void (* const glCullFace)(GLenum) = ::glCullFace; +void (* const glDeleteBuffers)(GLsizei, const GLuint *) = ::glDeleteBuffers; +void (* const glDeleteFramebuffers)(GLsizei, const GLuint *) = ::glDeleteFramebuffers; +void (* const glDeleteProgram)(GLuint) = ::glDeleteProgram; +void (* const glDeleteRenderbuffers)(GLsizei, const GLuint *) = ::glDeleteRenderbuffers; +void (* const glDeleteShader)(GLuint) = ::glDeleteShader; +void (* const glDeleteTextures)(GLsizei, const GLuint *) = ::glDeleteTextures; +void (* const glDepthFunc)(GLenum) = ::glDepthFunc; +void (* const glDepthMask)(GLboolean) = ::glDepthMask; +void (* const glDepthRangef)(GLfloat, GLfloat) = ::glDepthRangef; +void (* const glDetachShader)(GLuint, GLuint) = ::glDetachShader; +void (* const glDisable)(GLenum) = ::glDisable; +void (* const glDisableVertexAttribArray)(GLuint) = ::glDisableVertexAttribArray; +void (* const glDrawArrays)(GLenum, GLint, GLsizei) = ::glDrawArrays; +void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void *) = ::glDrawElements; +void (* const glEnable)(GLenum) = ::glEnable; +void (* const glEnableVertexAttribArray)(GLuint) = ::glEnableVertexAttribArray; +void (* const glFinish)() = ::glFinish; +void (* const glFlush)() = ::glFlush; +void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint) = ::glFramebufferRenderbuffer; +void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint) = ::glFramebufferTexture2D; +void (* const glFrontFace)(GLenum) = ::glFrontFace; +void (* const glGenBuffers)(GLsizei, GLuint *) = ::glGenBuffers; +void (* const glGenerateMipmap)(GLenum) = ::glGenerateMipmap; +void (* const glGenFramebuffers)(GLsizei, GLuint *) = ::glGenFramebuffers; +void (* const glGenRenderbuffers)(GLsizei, GLuint *) = ::glGenRenderbuffers; +void (* const glGenTextures)(GLsizei, GLuint *) = ::glGenTextures; +void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveAttrib; +void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveUniform; +void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei *, GLuint *) = ::glGetAttachedShaders; +GLint (* const glGetAttribLocation)(GLuint, const GLchar *) = ::glGetAttribLocation; +void (* const glGetBooleanv)(GLenum, GLboolean *) = ::glGetBooleanv; +void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetBufferParameteriv; +GLenum (* const glGetError)() = ::glGetError; +void (* const glGetFloatv)(GLenum, GLfloat *) = ::glGetFloatv; +void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint *) = ::glGetFramebufferAttachmentParameteriv; +void (* const glGetIntegerv)(GLenum, GLint *) = ::glGetIntegerv; +void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetProgramInfoLog; +void (* const glGetProgramiv)(GLuint, GLenum, GLint *) = ::glGetProgramiv; +void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetRenderbufferParameteriv; +void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderInfoLog; +void (* const glGetShaderiv)(GLuint, GLenum, GLint *) = ::glGetShaderiv; +void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderSource; +const GLubyte *(*glGetString)(GLenum) = ::glGetString; +void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat *) = ::glGetTexParameterfv; +void (* const glGetTexParameteriv)(GLenum, GLenum, GLint *) = ::glGetTexParameteriv; +void (* const glGetUniformfv)(GLuint, GLint, GLfloat *) = ::glGetUniformfv; +void (* const glGetUniformiv)(GLuint, GLint, GLint *) = ::glGetUniformiv; +GLint (* const glGetUniformLocation)(GLuint, const GLchar *) = ::glGetUniformLocation; +void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat *) = ::glGetVertexAttribfv; +void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint *) = ::glGetVertexAttribiv; +void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void **) = ::glGetVertexAttribPointerv; +void (* const glHint)(GLenum, GLenum) = ::glHint; +GLboolean (* const glIsBuffer)(GLuint) = ::glIsBuffer; +GLboolean (* const glIsEnabled)(GLenum) = ::glIsEnabled; +GLboolean (* const glIsFramebuffer)(GLuint) = ::glIsFramebuffer; +GLboolean (* const glIsProgram)(GLuint) = ::glIsProgram; +GLboolean (* const glIsRenderbuffer)(GLuint) = ::glIsRenderbuffer; +GLboolean (* const glIsShader)(GLuint) = ::glIsShader; +GLboolean (* const glIsTexture)(GLuint) = ::glIsTexture; +void (* const glLineWidth)(GLfloat) = ::glLineWidth; +void (* const glLinkProgram)(GLuint) = ::glLinkProgram; +void (* const glPixelStorei)(GLenum, GLint) = ::glPixelStorei; +void (* const glPolygonOffset)(GLfloat, GLfloat) = ::glPolygonOffset; +void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void *) = ::glReadPixels; +void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei) = ::glRenderbufferStorage; +void (* const glSampleCoverage)(GLfloat, GLboolean) = ::glSampleCoverage; +void (* const glScissor)(GLint, GLint, GLsizei, GLsizei) = ::glScissor; + +// Some implementations use `const GLchar* const*` and others `const GLchar**`. +void (* const glShaderSource)(GLuint, GLsizei, const GLchar * const*, const GLint *) = [](GLuint shader, GLsizei count, const GLchar * const * string, const GLint *length) { + ::glShaderSource(shader, count, const_cast(string), length); +}; + +void (* const glStencilFunc)(GLenum, GLint, GLuint) = ::glStencilFunc; +void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint) = ::glStencilFuncSeparate; +void (* const glStencilMask)(GLuint) = ::glStencilMask; +void (* const glStencilMaskSeparate)(GLenum, GLuint) = ::glStencilMaskSeparate; +void (* const glStencilOp)(GLenum, GLenum, GLenum) = ::glStencilOp; +void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glStencilOpSeparate; +void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *) = ::glTexImage2D; +void (* const glTexParameterf)(GLenum, GLenum, GLfloat) = ::glTexParameterf; +void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat *) = ::glTexParameterfv; +void (* const glTexParameteri)(GLenum, GLenum, GLint) = ::glTexParameteri; +void (* const glTexParameteriv)(GLenum, GLenum, const GLint *) = ::glTexParameteriv; +void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *) = ::glTexSubImage2D; +void (* const glUniform1f)(GLint, GLfloat) = ::glUniform1f; +void (* const glUniform1fv)(GLint, GLsizei, const GLfloat *) = ::glUniform1fv; +void (* const glUniform1i)(GLint, GLint) = ::glUniform1i; +void (* const glUniform1iv)(GLint, GLsizei, const GLint *) = ::glUniform1iv; +void (* const glUniform2f)(GLint, GLfloat, GLfloat) = ::glUniform2f; +void (* const glUniform2fv)(GLint, GLsizei, const GLfloat *) = ::glUniform2fv; +void (* const glUniform2i)(GLint, GLint, GLint) = ::glUniform2i; +void (* const glUniform2iv)(GLint, GLsizei, const GLint *) = ::glUniform2iv; +void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat) = ::glUniform3f; +void (* const glUniform3fv)(GLint, GLsizei, const GLfloat *) = ::glUniform3fv; +void (* const glUniform3i)(GLint, GLint, GLint, GLint) = ::glUniform3i; +void (* const glUniform3iv)(GLint, GLsizei, const GLint *) = ::glUniform3iv; +void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glUniform4f; +void (* const glUniform4fv)(GLint, GLsizei, const GLfloat *) = ::glUniform4fv; +void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint) = ::glUniform4i; +void (* const glUniform4iv)(GLint, GLsizei, const GLint *) = ::glUniform4iv; +void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix2fv; +void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix3fv; +void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix4fv; +void (* const glUseProgram)(GLuint) = ::glUseProgram; +void (* const glValidateProgram)(GLuint) = ::glValidateProgram; +void (* const glVertexAttrib1f)(GLuint, GLfloat) = ::glVertexAttrib1f; +void (* const glVertexAttrib1fv)(GLuint, const GLfloat *) = ::glVertexAttrib1fv; +void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat) = ::glVertexAttrib2f; +void (* const glVertexAttrib2fv)(GLuint, const GLfloat *) = ::glVertexAttrib2fv; +void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib3f; +void (* const glVertexAttrib3fv)(GLuint, const GLfloat *) = ::glVertexAttrib3fv; +void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib4f; +void (* const glVertexAttrib4fv)(GLuint, const GLfloat *) = ::glVertexAttrib4fv; +void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *) = ::glVertexAttribPointer; +void (* const glViewport)(GLint, GLint, GLsizei, GLsizei) = ::glViewport; + +} // namespace platform +} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/pointf.cpp b/src/graphics/pointf.cpp new file mode 100644 index 000000000..2fc762d6e --- /dev/null +++ b/src/graphics/pointf.cpp @@ -0,0 +1,25 @@ +#include +#include "pointf.hpp" + +namespace mbgl { +namespace android { + +jni::Local> PointF::New(jni::JNIEnv& env, float x, float y) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, x, y); +} + +mbgl::ScreenCoordinate PointF::getScreenCoordinate(jni::JNIEnv& env, const jni::Object& point) { + static auto& javaClass = jni::Class::Singleton(env); + static auto xField = javaClass.GetField(env, "x"); + static auto yField = javaClass.GetField(env, "y"); + return mbgl::ScreenCoordinate{point.Get(env, xField), point.Get(env, yField)}; +} + +void PointF::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/pointf.hpp b/src/graphics/pointf.hpp new file mode 100644 index 000000000..899468b8e --- /dev/null +++ b/src/graphics/pointf.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class PointF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/PointF"; }; + + static jni::Local> New(jni::JNIEnv&, float, float); + + static mbgl::ScreenCoordinate getScreenCoordinate(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/rectf.cpp b/src/graphics/rectf.cpp new file mode 100644 index 000000000..8f418da03 --- /dev/null +++ b/src/graphics/rectf.cpp @@ -0,0 +1,35 @@ +#include "rectf.hpp" + +namespace mbgl { +namespace android { + +float RectF::getLeft(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "left"); + return rectf.Get(env, field); +} + +float RectF::getTop(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "top"); + return rectf.Get(env, field); +} + +float RectF::getRight(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "right"); + return rectf.Get(env, field); +} + +float RectF::getBottom(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "bottom"); + return rectf.Get(env, field); +} + +void RectF::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/rectf.hpp b/src/graphics/rectf.hpp new file mode 100644 index 000000000..ba611f226 --- /dev/null +++ b/src/graphics/rectf.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class RectF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/RectF"; }; + + static float getLeft(jni::JNIEnv&, const jni::Object&); + + static float getTop(jni::JNIEnv&, const jni::Object&); + + static float getRight(jni::JNIEnv&, const jni::Object&); + + static float getBottom(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_array.cpp b/src/gson/json_array.cpp new file mode 100644 index 000000000..8ffa658b7 --- /dev/null +++ b/src/gson/json_array.cpp @@ -0,0 +1,50 @@ +#include "json_array.hpp" +#include "json_element.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +jni::Local> JsonArray::New(jni::JNIEnv& env, const std::vector& values){ + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + static auto addMethod = javaClass.GetMethod)>(env, "add"); + + auto jsonArray = javaClass.New(env, constructor); + + for (const auto &v : values) { + jsonArray.Call(env, addMethod, JsonElement::New(env, v)); + } + + return jsonArray; +} + +std::vector JsonArray::convert(jni::JNIEnv& env, const jni::Object& jsonArray) { + std::vector values; + + if (jsonArray) { + static auto& javaClass = jni::Class::Singleton(env); + static auto getMethod = javaClass.GetMethod (jni::jint)>(env, "get"); + static auto sizeMethod = javaClass.GetMethod(env, "size"); + + int size = jsonArray.Call(env, sizeMethod); + values.reserve(uint(size)); + + for (int i = 0; i < size; i++) { + auto entry = jsonArray.Call(env, getMethod, i); + if (entry) { + values.push_back(JsonElement::convert(env, entry)); + } + } + } + + return values; +} + +void JsonArray::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_array.hpp b/src/gson/json_array.hpp new file mode 100644 index 000000000..24d5d3d29 --- /dev/null +++ b/src/gson/json_array.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonArray { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonArray"; }; + + static jni::Local> New(jni::JNIEnv&, const std::vector&); + static std::vector convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_element.cpp b/src/gson/json_element.cpp new file mode 100644 index 000000000..ba22304d0 --- /dev/null +++ b/src/gson/json_element.cpp @@ -0,0 +1,88 @@ +#include "json_element.hpp" +#include "json_array.hpp" +#include "json_object.hpp" +#include "json_primitive.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +jni::Local> JsonElement::New(jni::JNIEnv& env, const mbgl::Value& value) { + static auto& primitive = jni::Class::Singleton(env); + static auto stringConstructor = primitive.GetConstructor(env); + static auto numberConstructor = primitive.GetConstructor(env); + static auto booleanConstructor = primitive.GetConstructor(env); + + return value.match( + [&] (const mbgl::NullValue&) { + return jni::Local>(); + }, + [&] (const std::string& value) { + return primitive.New(env, stringConstructor, jni::Make(env, value)); + }, + [&] (const double value) { + return primitive.New(env, numberConstructor, jni::Box(env, value)); + }, + [&] (const int64_t value) { + return primitive.New(env, numberConstructor, jni::Box(env, value)); + }, + [&] (const uint64_t value) { + return primitive.New(env, numberConstructor, jni::Box(env, int64_t(value))); // TODO: should use BigInteger + }, + [&] (const bool value) { + return primitive.New(env, booleanConstructor, jni::Box(env, value ? jni::jni_true : jni::jni_false)); + }, + [&] (const std::vector& values) { + return JsonArray::New(env, values); + }, + [&] (const mbgl::PropertyMap& values) { + return JsonObject::New(env, values); + } + ); +} + +mbgl::Value JsonElement::convert(jni::JNIEnv &env, const jni::Object& jsonElement) { + if (!jsonElement) { + return mbgl::NullValue(); + } + + static auto& elementClass = jni::Class::Singleton(env); + static auto isJsonObject = elementClass.GetMethod(env, "isJsonObject"); + static auto isJsonArray = elementClass.GetMethod(env, "isJsonArray"); + static auto isJsonPrimitive = elementClass.GetMethod(env, "isJsonPrimitive"); + + static auto& primitiveClass = jni::Class::Singleton(env); + static auto isBoolean = primitiveClass.GetMethod(env, "isBoolean"); + static auto isString = primitiveClass.GetMethod(env, "isString"); + static auto isNumber = primitiveClass.GetMethod(env, "isNumber"); + static auto getAsBoolean = primitiveClass.GetMethod(env, "getAsBoolean"); + static auto getAsString = primitiveClass.GetMethod(env, "getAsString"); + static auto getAsDouble = primitiveClass.GetMethod(env, "getAsDouble"); + + if (jsonElement.Call(env, isJsonPrimitive)) { + auto primitive = jni::Cast(env, primitiveClass, jsonElement); + if (primitive.Call(env, isBoolean)) { + return bool(primitive.Call(env, getAsBoolean)); + } else if (primitive.Call(env, isNumber)) { + return primitive.Call(env, getAsDouble); + } else if (primitive.Call(env, isString)) { + return jni::Make(env, primitive.Call(env, getAsString)); + } else { + return mbgl::NullValue(); + } + } else if (jsonElement.Call(env, isJsonObject)) { + return JsonObject::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); + } else if (jsonElement.Call(env, isJsonArray)) { + return JsonArray::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); + } else { + return mbgl::NullValue(); + } +} + +void JsonElement::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_element.hpp b/src/gson/json_element.hpp new file mode 100644 index 000000000..e3b8a0268 --- /dev/null +++ b/src/gson/json_element.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonElement { +public: + using SuperTag = jni::ObjectTag; + static constexpr auto Name() { return "com/google/gson/JsonElement"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Value&); + static mbgl::Value convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_object.cpp b/src/gson/json_object.cpp new file mode 100644 index 000000000..10d244ee4 --- /dev/null +++ b/src/gson/json_object.cpp @@ -0,0 +1,65 @@ +#include "json_object.hpp" + +#include "json_element.hpp" + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace gson { + + +jni::Local> JsonObject::New(jni::JNIEnv& env, const mbgl::PropertyMap& values) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + static auto addMethod = javaClass.GetMethod)>(env, "add"); + + auto jsonObject = javaClass.New(env, constructor); + + for (auto &item : values) { + jsonObject.Call(env, addMethod, + jni::Make(env, item.first), + JsonElement::New(env, item.second)); + } + + return jsonObject; +} + +template // void (jni::String, jni::Object) +static void iterateEntrySet(jni::JNIEnv& env, const jni::Object& jsonObject, F callback) { + // Get Set> + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "entrySet"); + + auto entryArray = java::util::Set::toArray(env, jsonObject.Call(env, method)); + + size_t size = entryArray.Length(env); + for (size_t i = 0; i < size; i++) { + auto entry = entryArray.Get(env, i); + if (entry) { + callback( + java::util::Map::Entry::getKey(env, entry), + java::util::Map::Entry::getValue(env, entry)); + } + } +} + +mbgl::PropertyMap JsonObject::convert(jni::JNIEnv& env, const jni::Object& jsonObject) { + mbgl::PropertyMap map; + + if (jsonObject) { + iterateEntrySet(env, jsonObject, [&map, &env](const jni::String& jId, const jni::Object& jsonElement) { + map[jni::Make(env, jId)] = JsonElement::convert(env, jsonElement); + }); + } + + return map; +} + +void JsonObject::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_object.hpp b/src/gson/json_object.hpp new file mode 100644 index 000000000..b8916f8ae --- /dev/null +++ b/src/gson/json_object.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonObject { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonObject"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::PropertyMap&); + static mbgl::PropertyMap convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_primitive.cpp b/src/gson/json_primitive.cpp new file mode 100644 index 000000000..79d6b0761 --- /dev/null +++ b/src/gson/json_primitive.cpp @@ -0,0 +1,13 @@ +#include "json_primitive.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +void JsonPrimitive::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_primitive.hpp b/src/gson/json_primitive.hpp new file mode 100644 index 000000000..36f138d90 --- /dev/null +++ b/src/gson/json_primitive.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonPrimitive { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; }; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/http_file_source.cpp b/src/http_file_source.cpp new file mode 100644 index 000000000..7066918fe --- /dev/null +++ b/src/http_file_source.cpp @@ -0,0 +1,194 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "attach_env.hpp" + +namespace mbgl { + +class HTTPFileSource::Impl { +public: + android::UniqueEnv env { android::AttachEnv() }; +}; + +class HTTPRequest : public AsyncRequest { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/NativeHttpRequest"; }; + + HTTPRequest(jni::JNIEnv&, const Resource&, FileSource::Callback); + ~HTTPRequest(); + + void onFailure(jni::JNIEnv&, int type, const jni::String& message); + void onResponse(jni::JNIEnv&, int code, + const jni::String& etag, const jni::String& modified, + const jni::String& cacheControl, const jni::String& expires, + const jni::String& retryAfter, const jni::String& xRateLimitReset, + const jni::Array& body); + + jni::Global> javaRequest; + +private: + Resource resource; + FileSource::Callback callback; + Response response; + + util::AsyncTask async { [this] { + // Calling `callback` may result in deleting `this`. Copy data to temporaries first. + auto callback_ = callback; + auto response_ = response; + callback_(response_); + } }; + + static const int connectionError = 0; + static const int temporaryError = 1; + static const int permanentError = 2; +}; + +namespace android { + +void RegisterNativeHTTPRequest(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&HTTPRequest::onFailure, "nativeOnFailure"), + METHOD(&HTTPRequest::onResponse, "nativeOnResponse")); +} + +} // namespace android + +HTTPRequest::HTTPRequest(jni::JNIEnv& env, const Resource& resource_, FileSource::Callback callback_) + : resource(resource_), + callback(callback_) { + std::string etagStr; + std::string modifiedStr; + + if (resource.priorEtag) { + etagStr = *resource.priorEtag; + } else if (resource.priorModified) { + modifiedStr = util::rfc1123(*resource.priorModified); + } + + jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 10); + + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = + javaClass.GetConstructor(env); + + javaRequest = jni::NewGlobal(env, + javaClass.New(env, constructor, + reinterpret_cast(this), + jni::Make(env, resource.url), + jni::Make(env, etagStr), + jni::Make(env, modifiedStr), + (jboolean) (resource_.usage == Resource::Usage::Offline) + ) + ); +} + +HTTPRequest::~HTTPRequest() { + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto cancel = javaClass.GetMethod(*env, "cancel"); + + javaRequest.Call(*env, cancel); +} + +void HTTPRequest::onResponse(jni::JNIEnv& env, int code, + const jni::String& etag, const jni::String& modified, + const jni::String& cacheControl, const jni::String& expires, + const jni::String& jRetryAfter, const jni::String& jXRateLimitReset, + const jni::Array& body) { + + using Error = Response::Error; + + if (etag) { + response.etag = jni::Make(env, etag); + } + + if (modified) { + response.modified = util::parseTimestamp(jni::Make(env, modified).c_str()); + } + + if (cacheControl) { + const auto cc = http::CacheControl::parse(jni::Make(env, cacheControl).c_str()); + response.expires = cc.toTimePoint(); + response.mustRevalidate = cc.mustRevalidate; + } + + if (expires) { + response.expires = util::parseTimestamp(jni::Make(env, expires).c_str()); + } + + if (code == 200) { + if (body) { + auto data = std::make_shared(body.Length(env), char()); + jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast(&(*data)[0])); + response.data = data; + } else { + response.data = std::make_shared(); + } + } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) { + response.noContent = true; + } else if (code == 304) { + response.notModified = true; + } else if (code == 404) { + response.error = std::make_unique(Error::Reason::NotFound, "HTTP status code 404"); + } else if (code == 429) { + optional retryAfter; + optional xRateLimitReset; + if (jRetryAfter) { + retryAfter = jni::Make(env, jRetryAfter); + } + if (jXRateLimitReset) { + xRateLimitReset = jni::Make(env, jXRateLimitReset); + } + response.error = std::make_unique(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset)); + } else if (code >= 500 && code < 600) { + response.error = std::make_unique(Error::Reason::Server, std::string{ "HTTP status code " } + util::toString(code)); + } else { + response.error = std::make_unique(Error::Reason::Other, std::string{ "HTTP status code " } + util::toString(code)); + } + + async.send(); +} + +void HTTPRequest::onFailure(jni::JNIEnv& env, int type, const jni::String& message) { + std::string messageStr = jni::Make(env, message); + + using Error = Response::Error; + + switch (type) { + case connectionError: + response.error = std::make_unique(Error::Reason::Connection, messageStr); + break; + case temporaryError: + response.error = std::make_unique(Error::Reason::Server, messageStr); + break; + default: + response.error = std::make_unique(Error::Reason::Other, messageStr); + } + + async.send(); +} + +HTTPFileSource::HTTPFileSource() + : impl(std::make_unique()) { +} + +HTTPFileSource::~HTTPFileSource() = default; + +std::unique_ptr HTTPFileSource::request(const Resource& resource, Callback callback) { + return std::make_unique(*impl->env, resource, callback); +} + +} // namespace mbgl diff --git a/src/image.cpp b/src/image.cpp new file mode 100644 index 000000000..31515ff16 --- /dev/null +++ b/src/image.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include + +#include "attach_env.hpp" +#include "bitmap_factory.hpp" + +namespace mbgl { + +PremultipliedImage decodeImage(const std::string& string) { + auto env{ android::AttachEnv() }; + + auto array = jni::Array::New(*env, string.size()); + jni::SetArrayRegion(*env, *array, 0, string.size(), + reinterpret_cast(string.data())); + + return android::Bitmap::GetImage(*env, android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size())); +} + +} // namespace mbgl diff --git a/src/java/util.cpp b/src/java/util.cpp new file mode 100644 index 000000000..b3aebb36c --- /dev/null +++ b/src/java/util.cpp @@ -0,0 +1,19 @@ +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +void registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); +} + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/java/util.hpp b/src/java/util.hpp new file mode 100644 index 000000000..9b0c01459 --- /dev/null +++ b/src/java/util.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +class List : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/List"; }; + + template + static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { + static auto& javaClass = jni::Class::Singleton(env); + static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); + + return jni::Local>>(env, list.Call(env, toArray).release()); + }; +}; + +class Arrays : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Arrays"; }; + + template + static jni::Local> asList(jni::JNIEnv& env, const jni::Array>& array) { + static auto& javaClass = jni::Class::Singleton(env); + static auto asList = javaClass.GetStaticMethod(jni::Array>)>(env, "asList"); + + auto typeErasedArray = jni::Local>>(env, jni::NewLocal(env, array).release()); + return javaClass.Call(env, asList, typeErasedArray); + } +}; + +class Set : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Set"; }; + + template + static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { + static auto& javaClass = jni::Class::Singleton(env); + static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); + + return jni::Local>>(env, list.Call(env, toArray).release()); + }; +}; + +class Map : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Map"; }; + + class Entry : private mbgl::util::noncopyable { + public: + static constexpr auto Name() { return "java/util/Map$Entry"; }; + + template + static jni::Local> getKey(jni::JNIEnv& env, const jni::Object& entry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "getKey"); + return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); + } + + template + static jni::Local> getValue(jni::JNIEnv& env, const jni::Object& entry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "getValue"); + return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); + } + }; +}; + +void registerNative(jni::JNIEnv&); + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/java_types.cpp b/src/java_types.cpp new file mode 100644 index 000000000..7a1ba93a5 --- /dev/null +++ b/src/java_types.cpp @@ -0,0 +1,49 @@ +#include "java_types.hpp" + +namespace mbgl { +namespace android { +namespace java { + + jni::jclass* ObjectArray::jclass; + + jni::jclass* String::jclass; + + jni::jclass* Boolean::jclass; + jni::jmethodID* Boolean::booleanValueMethodId; + + jni::jclass* Number::jclass; + jni::jmethodID* Number::floatValueMethodId; + jni::jmethodID* Number::doubleValueMethodId; + jni::jmethodID* Number::longValueMethodId; + + jni::jclass* Map::jclass; + jni::jmethodID* Map::getMethodId; + jni::jmethodID* Map::keySetMethodId; + + jni::jclass* Set::jclass; + jni::jmethodID* Set::toArrayMethodId; + + void registerNatives(JNIEnv& env) { + ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release(); + + String::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); + + Boolean::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); + Boolean::booleanValueMethodId = &jni::GetMethodID(env, *Boolean::jclass, "booleanValue", "()Z"); + + Number::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Number")).release(); + Number::floatValueMethodId = &jni::GetMethodID(env, *Number::jclass, "floatValue", "()F"); + Number::doubleValueMethodId = &jni::GetMethodID(env, *Number::jclass, "doubleValue", "()D"); + Number::longValueMethodId = &jni::GetMethodID(env, *Number::jclass, "longValue", "()J"); + + Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release(); + Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); + Map::keySetMethodId = &jni::GetMethodID(env, *Map::jclass, "keySet", "()Ljava/util/Set;"); + + Set::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Set")).release(); + Set::toArrayMethodId = &jni::GetMethodID(env, *Set::jclass, "toArray", "()[Ljava/lang/Object;"); + } + +} +} +} diff --git a/src/java_types.hpp b/src/java_types.hpp new file mode 100644 index 000000000..c7c93ce71 --- /dev/null +++ b/src/java_types.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { +namespace java { + + struct ObjectArray { + static jni::jclass* jclass; + }; + + struct String { + static jni::jclass* jclass; + }; + + struct Boolean { + static jni::jclass* jclass; + static jni::jmethodID* booleanValueMethodId; + }; + + struct Number { + static jni::jclass* jclass; + static jni::jmethodID* floatValueMethodId; + static jni::jmethodID* doubleValueMethodId; + static jni::jmethodID* longValueMethodId; + }; + + struct Map { + static jni::jclass* jclass; + static jni::jmethodID* getMethodId; + static jni::jmethodID* keySetMethodId; + }; + + struct Set { + static jni::jclass* jclass; + static jni::jmethodID* toArrayMethodId; + }; + + void registerNatives(JNIEnv&); +} +} +} diff --git a/src/jni.cpp b/src/jni.cpp new file mode 100755 index 000000000..189ec29dc --- /dev/null +++ b/src/jni.cpp @@ -0,0 +1,54 @@ +#include "jni.hpp" + +#include + +namespace mbgl { +namespace android { + +JavaVM* theJVM; + +//TODO: remove +bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) { + assert(vm != nullptr); + assert(env != nullptr); + + JavaVMAttachArgs args = {JNI_VERSION_1_2, threadName.c_str(), NULL}; + + jint ret; + *env = nullptr; + bool detach = false; + ret = vm->GetEnv(reinterpret_cast(env), JNI_VERSION_1_6); + if (ret != JNI_OK) { + if (ret != JNI_EDETACHED) { + mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); + throw std::runtime_error("GetEnv() failed"); + } else { + ret = vm->AttachCurrentThread(env, &args); + if (ret != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret); + throw std::runtime_error("AttachCurrentThread() failed"); + } + detach = true; + } + } + + return detach; +} + +//TODO: remove +void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) { + if (detach) { + assert(vm != nullptr); + assert(env != nullptr); + + jint ret; + if ((ret = vm->DetachCurrentThread()) != JNI_OK) { + mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret); + throw std::runtime_error("DetachCurrentThread() failed"); + } + } + *env = nullptr; +} + +} // namespace android +} // namespace mbgl diff --git a/src/jni.hpp b/src/jni.hpp new file mode 100644 index 000000000..9bfe2ce5b --- /dev/null +++ b/src/jni.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include +#include + +typedef struct _jmethodID* jmethodID; +typedef struct _JavaVM JavaVM; +typedef struct _JNIEnv JNIEnv; + +namespace mbgl { +namespace android { + +extern JavaVM* theJVM; + +extern std::string cachePath; +extern std::string dataPath; + +bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName); +void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach); + +} // namespace android +} // namespace mbgl diff --git a/src/jni_native.cpp b/src/jni_native.cpp new file mode 100755 index 000000000..df96ba975 --- /dev/null +++ b/src/jni_native.cpp @@ -0,0 +1,164 @@ +#include "jni_native.hpp" + +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "bitmap.hpp" +#include "bitmap_factory.hpp" +#include "connectivity_listener.hpp" +#include "conversion/conversion.hpp" +#include "conversion/collection.hpp" +#include "file_source.hpp" +#include "geojson/feature.hpp" +#include "geojson/feature_collection.hpp" +#include "geojson/geometry.hpp" +#include "geojson/geometry_collection.hpp" +#include "geojson/line_string.hpp" +#include "geojson/multi_line_string.hpp" +#include "geojson/multi_point.hpp" +#include "geojson/multi_polygon.hpp" +#include "geojson/point.hpp" +#include "geojson/polygon.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "geometry/lat_lng_quad.hpp" +#include "geometry/projected_meters.hpp" +#include "graphics/pointf.hpp" +#include "graphics/rectf.hpp" +#include "gson/json_array.hpp" +#include "gson/json_element.hpp" +#include "gson/json_object.hpp" +#include "gson/json_primitive.hpp" +#include "java_types.hpp" +#include "map_renderer.hpp" +#include "map_renderer_runnable.hpp" +#include "native_map_view.hpp" +#ifndef MBGL_MODULE_OFFLINE_DISABLE +#include "offline/offline_manager.hpp" +#include "offline/offline_region.hpp" +#include "offline/offline_region_definition.hpp" +#include "offline/offline_region_error.hpp" +#include "offline/offline_region_status.hpp" +#endif +#include "style/transition_options.hpp" +#include "style/layers/layer_manager.hpp" +#include "style/sources/source.hpp" +#include "style/light.hpp" +#include "style/formatted.hpp" +#include "style/formatted_section.hpp" +#ifndef MBGL_MODULE_SNAPSHOT_DISABLE +#include "snapshotter/map_snapshotter.hpp" +#include "snapshotter/map_snapshot.hpp" +#endif +#include "text/collator_jni.hpp" +#include "text/local_glyph_rasterizer_jni.hpp" +#include "text/format_number_jni.hpp" +#include "logger.hpp" + +namespace mbgl { +namespace android { + +void RegisterNativeHTTPRequest(JNIEnv&); + +void registerNatives(JavaVM *vm) { + theJVM = vm; + + jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6); + + // For the DefaultFileSource + static mbgl::util::RunLoop mainRunLoop; + FileSource::registerNative(env); + + // Basic types + java::registerNatives(env); + java::util::registerNative(env); + PointF::registerNative(env); + RectF::registerNative(env); + + // GeoJSON + geojson::Feature::registerNative(env); + geojson::FeatureCollection::registerNative(env); + geojson::Geometry::registerNative(env); + geojson::GeometryCollection::registerNative(env); + geojson::LineString::registerNative(env); + geojson::MultiLineString::registerNative(env); + geojson::MultiPoint::registerNative(env); + geojson::MultiPolygon::registerNative(env); + geojson::Point::registerNative(env); + geojson::Polygon::registerNative(env); + + // Geometry + LatLng::registerNative(env); + LatLngBounds::registerNative(env); + LatLngQuad::registerNative(env); + ProjectedMeters::registerNative(env); + + // GSon + gson::JsonArray::registerNative(env); + gson::JsonElement::registerNative(env); + gson::JsonObject::registerNative(env); + gson::JsonPrimitive::registerNative(env); + + //Annotation + Marker::registerNative(env); + Polygon::registerNative(env); + Polyline::registerNative(env); + + // Map + MapRenderer::registerNative(env); + MapRendererRunnable::registerNative(env); + NativeMapView::registerNative(env); + + // Http + RegisterNativeHTTPRequest(env); + + // Bitmap + Bitmap::registerNative(env); + BitmapFactory::registerNative(env); + + // Style + TransitionOptions::registerNative(env); + LayerManagerAndroid::get()->registerNative(env); + Source::registerNative(env); + Light::registerNative(env); + Position::registerNative(env); + Formatted::registerNative(env); + FormattedSection::registerNative(env); + + // Map + CameraPosition::registerNative(env); + Image::registerNative(env); + + // Connectivity + ConnectivityListener::registerNative(env); + + // Offline +#ifndef MBGL_MODULE_OFFLINE_DISABLE + OfflineManager::registerNative(env); + OfflineRegion::registerNative(env); + OfflineRegionDefinition::registerNative(env); + OfflineTilePyramidRegionDefinition::registerNative(env); + OfflineGeometryRegionDefinition::registerNative(env); + OfflineRegionError::registerNative(env); + OfflineRegionStatus::registerNative(env); +#endif + + // Snapshotter +#ifndef MBGL_MODULE_SNAPSHOT_DISABLE + MapSnapshotter::registerNative(env); + MapSnapshot::registerNative(env); +#endif + + // text + LocalGlyphRasterizer::registerNative(env); + Locale::registerNative(env); + Collator::registerNative(env); + StringUtils::registerNative(env); + NumberFormat::registerNative(env); + + // Logger + Logger::registerNative(env); +} + +} // namespace android +} // namespace mbgl diff --git a/src/jni_native.hpp b/src/jni_native.hpp new file mode 100644 index 000000000..c8e284a52 --- /dev/null +++ b/src/jni_native.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "jni.hpp" + +namespace mbgl { +namespace android { + +MBGL_PUBLIC void registerNatives(JavaVM* vm); + +} // namespace android +} // namespace mbgl diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 000000000..f5d78cc83 --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,34 @@ +#include "logger.hpp" +#include "java_types.hpp" + +namespace mbgl { +namespace android { + +void Logger::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +void Logger::log(jni::JNIEnv& env, EventSeverity severity, const std::string &msg) { + static auto& _class = jni::Class::Singleton(env); + + auto tag = jni::Make(env, "Mbgl"); + auto message = jni::Make(env, msg); + using Signature = void(jni::String, jni::String); + + if (severity == EventSeverity::Debug) { + auto static debug = _class.GetStaticMethod(env, "d"); + _class.Call(env, debug, tag, message); + } else if (severity == EventSeverity::Info) { + auto static info = _class.GetStaticMethod(env, "i"); + _class.Call(env, info, tag, message); + } else if(severity == EventSeverity::Warning) { + auto static warning = _class.GetStaticMethod(env, "w"); + _class.Call(env, warning, tag, message); + } else { + auto static error = _class.GetStaticMethod(env, "e"); + _class.Call(env, error, tag, message); + } +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/logger.hpp b/src/logger.hpp new file mode 100644 index 000000000..7481ecb26 --- /dev/null +++ b/src/logger.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include "bitmap.hpp" + +namespace mbgl { +namespace android { + +class Logger { +public: + static constexpr auto Name() { + return "com/mapbox/mapboxsdk/log/Logger"; + }; + static void registerNative(jni::JNIEnv&); + + static void log(jni::JNIEnv&, EventSeverity severity, const std::string &msg); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/logging_android.cpp b/src/logging_android.cpp new file mode 100644 index 000000000..130136728 --- /dev/null +++ b/src/logging_android.cpp @@ -0,0 +1,13 @@ +#include + +#include "logger.hpp" +#include "attach_env.hpp" + +namespace mbgl { + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + auto env{ android::AttachEnv() }; + android::Logger::log(*env, severity, msg); +} + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 000000000..9b5c6c197 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,9 @@ +#include "jni.hpp" +#include "jni_native.hpp" +#include + +extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { + assert(vm != nullptr); + mbgl::android::registerNatives(vm); + return JNI_VERSION_1_6; +} diff --git a/src/map/camera_position.cpp b/src/map/camera_position.cpp new file mode 100644 index 000000000..03aca79bd --- /dev/null +++ b/src/map/camera_position.cpp @@ -0,0 +1,68 @@ +#include "camera_position.hpp" +#include "../geometry/lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options, float pixelRatio) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, double, double, double, jni::Array>(env); + + // wrap LatLng values coming from core + auto center = options.center.value(); + center.wrap(); + + // convert bearing, measured in radians counterclockwise from true north. + // Wrapped to [−π rad, π rad). Android binding from 0 to 360 degrees + double bearing_degrees = options.bearing.value_or(0); + while (bearing_degrees > 360) { + bearing_degrees -= 360; + } + while (bearing_degrees < 0) { + bearing_degrees += 360; + } + + // convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60 + double tilt_degrees = options.pitch.value_or(0); + + std::vector paddingVect; + auto insets = options.padding.value_or(EdgeInsets {0, 0, 0, 0}); + auto padding = jni::Array::New(env, 4); + paddingVect.push_back(insets.left() * pixelRatio); + paddingVect.push_back(insets.top() * pixelRatio); + paddingVect.push_back(insets.right() * pixelRatio); + paddingVect.push_back(insets.bottom() * pixelRatio); + padding.SetRegion>(env, 0, paddingVect); + + return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees, padding); +} + +mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object& position, float pixelRatio) { + static auto& javaClass = jni::Class::Singleton(env); + static auto bearing = javaClass.GetField(env, "bearing"); + static auto target = javaClass.GetField>(env, "target"); + static auto tilt = javaClass.GetField(env, "tilt"); + static auto zoom = javaClass.GetField(env, "zoom"); + static auto paddingField = javaClass.GetField>(env, "padding"); + static auto padding = position.Get(env, paddingField); + + auto center = LatLng::getLatLng(env, position.Get(env, target)); + + return mbgl::CameraOptions { + center, + EdgeInsets {padding.Get(env, 1) * pixelRatio, padding.Get(env, 0) * pixelRatio, + padding.Get(env, 3) * pixelRatio, padding.Get(env, 2) * pixelRatio}, + {}, + position.Get(env, zoom), + position.Get(env, bearing), + position.Get(env, tilt) + }; +} + +void CameraPosition::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mb + diff --git a/src/map/camera_position.hpp b/src/map/camera_position.hpp new file mode 100644 index 000000000..b677f04ea --- /dev/null +++ b/src/map/camera_position.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { + +class CameraPosition : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::CameraOptions, float pixelRatio); + + static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object&, float pixelRatio); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/map/image.cpp b/src/map/image.cpp new file mode 100644 index 000000000..a91cc938e --- /dev/null +++ b/src/map/image.cpp @@ -0,0 +1,41 @@ +#include +#include +#include "image.hpp" + +namespace mbgl { +namespace android { + +mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& image) { + static auto& javaClass = jni::Class::Singleton(env); + static auto widthField = javaClass.GetField(env, "width"); + static auto heightField = javaClass.GetField(env, "height"); + static auto pixelRatioField = javaClass.GetField(env, "pixelRatio"); + static auto bufferField = javaClass.GetField>(env, "buffer"); + static auto nameField = javaClass.GetField(env, "name"); + static auto sdfField = javaClass.GetField(env, "sdf"); + + auto height = image.Get(env, heightField); + auto width = image.Get(env, widthField); + auto pixelRatio = image.Get(env, pixelRatioField); + auto pixels = image.Get(env, bufferField); + auto name = jni::Make(env, image.Get(env, nameField)); + auto sdf = (bool) image.Get(env, sdfField); + + jni::NullCheck(env, pixels.get()); + std::size_t size = pixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(width), static_cast(height) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf}; +} + +void Image::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mb diff --git a/src/map/image.hpp b/src/map/image.hpp new file mode 100644 index 000000000..7549bc646 --- /dev/null +++ b/src/map/image.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { +namespace android { + +class Image : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/Image"; }; + + static mbgl::style::Image getImage(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/map_renderer.cpp b/src/map_renderer.cpp new file mode 100644 index 000000000..6be708b99 --- /dev/null +++ b/src/map_renderer.cpp @@ -0,0 +1,236 @@ +#include "map_renderer.hpp" + +#include +#include +#include + +#include + +#include "attach_env.hpp" +#include "android_renderer_backend.hpp" +#include "map_renderer_runnable.hpp" + +namespace mbgl { +namespace android { + +MapRenderer::MapRenderer(jni::JNIEnv& _env, + const jni::Object& obj, + jni::jfloat pixelRatio_, + const jni::String& localIdeographFontFamily_) + : javaPeer(_env, obj) + , pixelRatio(pixelRatio_) + , localIdeographFontFamily(localIdeographFontFamily_ ? jni::Make(_env, localIdeographFontFamily_) : optional{}) + , mailbox(std::make_shared(*this)) { +} + +MapRenderer::~MapRenderer() = default; + +void MapRenderer::reset() { + destroyed = true; + + if (renderer) { + // Make sure to destroy the renderer on the GL Thread + auto self = ActorRef(*this, mailbox); + self.ask(&MapRenderer::resetRenderer).wait(); + } + + // Lock to make sure there is no concurrent initialisation on the gl thread + std::lock_guard lock(initialisationMutex); + rendererObserver.reset(); +} + +ActorRef MapRenderer::actor() const { + return *rendererRef; +} + +void MapRenderer::schedule(std::weak_ptr scheduled) { + // Create a runnable + android::UniqueEnv _env = android::AttachEnv(); + auto runnable = std::make_unique(*_env, std::move(scheduled)); + + // Obtain ownership of the peer (gets transferred to the MapRenderer on the JVM for later GC) + auto peer = runnable->peer(); + + // Queue the event on the Java Peer + static auto& javaClass = jni::Class::Singleton(*_env); + static auto queueEvent = javaClass.GetMethod)>(*_env, "queueEvent"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, queueEvent, peer); + } + + // Release the c++ peer as it will be destroyed on GC of the Java Peer + runnable.release(); +} + +void MapRenderer::requestRender() { + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onInvalidate = javaClass.GetMethod(*_env, "requestRender"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onInvalidate); + } +} + +void MapRenderer::update(std::shared_ptr params) { + // Lock on the parameters + std::lock_guard lock(updateMutex); + updateParameters = std::move(params); +} + +void MapRenderer::setObserver(std::shared_ptr _rendererObserver) { + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(initialisationMutex); + + rendererObserver = std::move(_rendererObserver); + + // Set the new observer on the Renderer implementation + if (renderer) { + renderer->setObserver(rendererObserver.get()); + } +} + +void MapRenderer::requestSnapshot(SnapshotCallback callback) { + auto self = ActorRef(*this, mailbox); + self.invoke( + &MapRenderer::scheduleSnapshot, + std::make_unique([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) { + runloop->invoke([callback=std::move(callback), image=std::move(image), renderer=std::move(this)]() mutable { + if (renderer && !renderer->destroyed) { + callback(std::move(image)); + } + }); + snapshotCallback.reset(); + }) + ); +} + +// Called on OpenGL thread // + +void MapRenderer::resetRenderer() { + renderer.reset(); +} + +void MapRenderer::scheduleSnapshot(std::unique_ptr callback) { + snapshotCallback = std::move(callback); + requestRender(); +} + +void MapRenderer::render(JNIEnv&) { + assert (renderer); + + std::shared_ptr params; + { + // Lock on the parameters + std::unique_lock lock(updateMutex); + if (!updateParameters) return; + + // Hold on to the update parameters during render + params = updateParameters; + } + + // Activate the backend + gfx::BackendScope backendGuard { *backend }; + + // Ensure that the "current" scheduler on the render thread is + // this scheduler. + Scheduler::SetCurrent(this); + + if (framebufferSizeChanged) { + backend->updateViewPort(); + framebufferSizeChanged = false; + } + + renderer->render(*params); + + // Deliver the snapshot if requested + if (snapshotCallback) { + snapshotCallback->operator()(backend->readFramebuffer()); + snapshotCallback.reset(); + } +} + +void MapRenderer::onSurfaceCreated(JNIEnv&) { + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(initialisationMutex); + + // The GL context is already active if get a new surface. + gfx::BackendScope backendGuard { *backend, gfx::BackendScope::ScopeType::Implicit }; + + // The android system will have already destroyed the underlying + // GL resources if this is not the first initialization and an + // attempt to clean them up will fail + if (backend) backend->markContextLost(); + if (renderer) renderer->markContextLost(); + + // Reset in opposite order + renderer.reset(); + backend.reset(); + + // Create the new backend and renderer + backend = std::make_unique(); + renderer = std::make_unique(*backend, pixelRatio, localIdeographFontFamily); + rendererRef = std::make_unique>(*renderer, mailbox); + + // Set the observer on the new Renderer implementation + if (rendererObserver) { + renderer->setObserver(rendererObserver.get()); + } +} + +void MapRenderer::onSurfaceChanged(JNIEnv& env, jint width, jint height) { + if (!renderer) { + // In case the surface has been destroyed (due to app back-grounding) + onSurfaceCreated(env); + } + + backend->resizeFramebuffer(width, height); + framebufferSizeChanged = true; + requestRender(); +} + +void MapRenderer::onRendererReset(JNIEnv&) { + // Make sure to destroy the renderer on the GL Thread + auto self = ActorRef(*this, mailbox); + self.ask(&MapRenderer::resetRenderer).wait(); +} + +// needs to be called on GL thread +void MapRenderer::onSurfaceDestroyed(JNIEnv&) { + resetRenderer(); +} + +// Static methods // + +void MapRenderer::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + jni::MakePeer&, jni::jfloat, const jni::String&>, + "nativeInitialize", "finalize", + METHOD(&MapRenderer::render, "nativeRender"), + METHOD(&MapRenderer::onRendererReset, "nativeReset"), + METHOD(&MapRenderer::onSurfaceCreated, + "nativeOnSurfaceCreated"), + METHOD(&MapRenderer::onSurfaceChanged, + "nativeOnSurfaceChanged"), + METHOD(&MapRenderer::onSurfaceDestroyed, + "nativeOnSurfaceDestroyed")); +} + +MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, const jni::Object& jObject) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "nativePtr"); + MapRenderer* mapRenderer = reinterpret_cast(jObject.Get(env, field)); + assert(mapRenderer != nullptr); + return *mapRenderer; +} + +} // namespace android +} // namespace mbgl diff --git a/src/map_renderer.hpp b/src/map_renderer.hpp new file mode 100644 index 000000000..5a8ddeeb9 --- /dev/null +++ b/src/map_renderer.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace mbgl { + +template +class ActorRef; +class Mailbox; +class Renderer; +class RendererBackend; +class RendererObserver; +class ThreadPool; +class UpdateParameters; + +namespace android { + +class AndroidRendererBackend; + +/** + * The MapRenderer is a peer class that encapsulates the actions + * performed on the GL Thread. + * + * The public methods are safe to call from the main thread, others are not. + */ +class MapRenderer : public Scheduler { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRenderer"; }; + + static void registerNative(jni::JNIEnv&); + + static MapRenderer& getNativePeer(JNIEnv&, const jni::Object&); + + MapRenderer(jni::JNIEnv& _env, + const jni::Object&, + jni::jfloat pixelRatio, + const jni::String& localIdeographFontFamily); + + ~MapRenderer() override; + + // Resets the renderer to clean up on the calling thread + void reset(); + + // Takes the RendererObserver by shared_ptr so we + // don't have to make the header public. Use + // this instead of Renderer#setObserver directly + void setObserver(std::shared_ptr); + + // Sets the new update parameters to use on subsequent + // renders. Be sure to trigger a render with + // requestRender(). + void update(std::shared_ptr); + + // Gives a handle to the Renderer to enable actions on + // any thread. + ActorRef actor() const; + + // From Scheduler. Schedules by using callbacks to the + // JVM to process the mailbox on the right thread. + void schedule(std::weak_ptr scheduled) override; + + void requestRender(); + + // Snapshot - requires a RunLoop on the calling thread + using SnapshotCallback = std::function; + void requestSnapshot(SnapshotCallback); + +protected: + // Called from the GL Thread // + + void scheduleSnapshot(std::unique_ptr); + +private: + // Called from the GL Thread // + + // Resets the renderer + void resetRenderer(); + + // Renders a frame. + void render(JNIEnv&); + + void onSurfaceCreated(JNIEnv&); + + void onSurfaceChanged(JNIEnv&, jint width, jint height); + + void onSurfaceDestroyed(JNIEnv&); + +private: + // Called on either Main or GL thread // + void onRendererReset(JNIEnv&); + +private: + jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; + + float pixelRatio; + optional localIdeographFontFamily; + + std::shared_ptr threadPool; + std::shared_ptr mailbox; + + std::mutex initialisationMutex; + std::shared_ptr rendererObserver; + + std::unique_ptr backend; + std::unique_ptr renderer; + std::unique_ptr> rendererRef; + + std::shared_ptr updateParameters; + std::mutex updateMutex; + + bool framebufferSizeChanged = false; + std::atomic destroyed {false}; + + std::unique_ptr snapshotCallback; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/map_renderer_runnable.cpp b/src/map_renderer_runnable.cpp new file mode 100644 index 000000000..77c3aa301 --- /dev/null +++ b/src/map_renderer_runnable.cpp @@ -0,0 +1,50 @@ +#include "map_renderer_runnable.hpp" + +#include + +namespace mbgl { +namespace android { + +MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr mailbox_) + : mailbox(std::move(mailbox_)) { + + // Create the Java peer and hold on to a global reference + // Not using a weak reference here as this might oerflow + // the weak reference table on some devices + jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5); + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + auto instance = javaClass.New(env, constructor, reinterpret_cast(this)); + javaPeer = jni::NewGlobal(env, instance); +} + +MapRendererRunnable::~MapRendererRunnable() = default; + +void MapRendererRunnable::run(jni::JNIEnv&) { + Mailbox::maybeReceive(mailbox); +} + +jni::Global> MapRendererRunnable::peer() { + return std::move(javaPeer); +} + +// Static methods // + +void MapRendererRunnable::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + std::make_unique, + "nativeInitialize", + "finalize", + METHOD(&MapRendererRunnable::run, "run")); +} + +} // namespace android +} // namespace mbgl diff --git a/src/map_renderer_runnable.hpp b/src/map_renderer_runnable.hpp new file mode 100644 index 000000000..21c4369b6 --- /dev/null +++ b/src/map_renderer_runnable.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include +#include + +#include + +namespace mbgl { +namespace android { + +/** + * The MapRendererRunnable is a peer class that encapsulates + * a scheduled mailbox in a Java Runnable so it can be + * scheduled on the map renderer thread. + * + */ +class MapRendererRunnable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable"; }; + + static void registerNative(jni::JNIEnv&); + + MapRendererRunnable(jni::JNIEnv&, std::weak_ptr); + + // Only for jni registration, unused + MapRendererRunnable(jni::JNIEnv&) { + assert(false); + } + + ~MapRendererRunnable(); + + void run(jni::JNIEnv&); + + // Transfers ownership of the Peer object to the caller + jni::Global> peer(); + +private: + jni::Global> javaPeer; + std::weak_ptr mailbox; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/native_map_view.cpp b/src/native_map_view.cpp new file mode 100755 index 000000000..8ef757de1 --- /dev/null +++ b/src/native_map_view.cpp @@ -0,0 +1,1153 @@ +#include "native_map_view.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Java -> C++ conversion +#include "style/android_conversion.hpp" +#include +#include + +// C++ -> Java conversion +#include "conversion/conversion.hpp" +#include "conversion/collection.hpp" +#include "style/conversion/filter.hpp" +#include "geojson/feature.hpp" + +#include "jni.hpp" +#include "attach_env.hpp" +#include "map_renderer.hpp" +#include "android_renderer_frontend.hpp" +#include "file_source.hpp" +#include "bitmap.hpp" +#include "run_loop_impl.hpp" +#include "java/util.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "map/camera_position.hpp" +#include "map/image.hpp" +#include "style/light.hpp" +#include "bitmap_factory.hpp" + +namespace mbgl { +namespace android { + +NativeMapView::NativeMapView(jni::JNIEnv& _env, + const jni::Object& _obj, + const jni::Object& jFileSource, + const jni::Object& jMapRenderer, + jni::jfloat _pixelRatio, + jni::jboolean _crossSourceCollisions) + : javaPeer(_env, _obj) + , mapRenderer(MapRenderer::getNativePeer(_env, jMapRenderer)) + , pixelRatio(_pixelRatio) { + + // Get a reference to the JavaVM for callbacks + if (_env.GetJavaVM(&vm) < 0) { + _env.ExceptionDescribe(); + return; + } + + // Create a renderer frontend + rendererFrontend = std::make_unique(mapRenderer); + + // Create Map options + MapOptions options; + options.withMapMode(MapMode::Continuous) + .withSize(mbgl::Size{ static_cast(width), static_cast(height) }) + .withPixelRatio(pixelRatio) + .withConstrainMode(ConstrainMode::HeightOnly) + .withViewportMode(ViewportMode::Default) + .withCrossSourceCollisions(_crossSourceCollisions); + + // Create the core map + map = std::make_unique( + *rendererFrontend, *this, options, + mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource)); +} + +/** + * Called through NativeMapView#destroy() + */ +NativeMapView::~NativeMapView() { + map.reset(); + vm = nullptr; +} + +void NativeMapView::onCameraWillChange(MapObserver::CameraChangeMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraWillChange = javaClass.GetMethod(*_env, "onCameraWillChange"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraWillChange, (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); + } +} + + +void NativeMapView::onCameraIsChanging() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraIsChanging = javaClass.GetMethod(*_env, "onCameraIsChanging"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraIsChanging); + } +} + +void NativeMapView::onCameraDidChange(MapObserver::CameraChangeMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraDidChange = javaClass.GetMethod(*_env, "onCameraDidChange"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraDidChange, + (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); + } +} + +void NativeMapView::onWillStartLoadingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartLoadingMap = javaClass.GetMethod(*_env, "onWillStartLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartLoadingMap); + } +} + +void NativeMapView::onDidFinishLoadingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishLoadingMap = javaClass.GetMethod(*_env, "onDidFinishLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishLoadingMap); + } +} + +void NativeMapView::onDidFailLoadingMap(MapLoadError, const std::string& error) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFailLoadingMap = javaClass.GetMethod(*_env, "onDidFailLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFailLoadingMap, jni::Make(*_env, error)); + } +} + +void NativeMapView::onWillStartRenderingFrame() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartRenderingFrame = javaClass.GetMethod(*_env, "onWillStartRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartRenderingFrame); + } +} + +void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode, bool) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingFrame = javaClass.GetMethod(*_env, "onDidFinishRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (mode != MapObserver::RenderMode::Partial)); + } +} + + +void NativeMapView::onWillStartRenderingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartRenderingMap = javaClass.GetMethod(*_env, "onWillStartRenderingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartRenderingMap); + } +} + +void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingMap = javaClass.GetMethod(*_env, "onDidFinishRenderingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishRenderingMap, (jboolean) (mode != MapObserver::RenderMode::Partial)); + } +} + +void NativeMapView::onDidBecomeIdle() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidBecomeIdle = javaClass.GetMethod(*_env, "onDidBecomeIdle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidBecomeIdle); + } +} + +void NativeMapView::onDidFinishLoadingStyle() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishLoadingStyle = javaClass.GetMethod(*_env, "onDidFinishLoadingStyle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishLoadingStyle); + } +} + +void NativeMapView::onSourceChanged(mbgl::style::Source& source) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onSourceChanged = javaClass.GetMethod(*_env, "onSourceChanged"); + auto sourceId = jni::Make(*_env, source.getID()); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSourceChanged, sourceId); + } +} + +void NativeMapView::onStyleImageMissing(const std::string& imageId) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onStyleImageMissing = javaClass.GetMethod(*_env, "onStyleImageMissing"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onStyleImageMissing, jni::Make(*_env, imageId)); + } +} + +bool NativeMapView::onCanRemoveUnusedStyleImage(const std::string& imageId) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCanRemoveUnusedStyleImage = javaClass.GetMethod(*_env, "onCanRemoveUnusedStyleImage"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + return weakReference.Call(*_env, onCanRemoveUnusedStyleImage, jni::Make(*_env, imageId)); + } + + return true; +} + +// JNI Methods // + +void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) { + width = util::max(64, w); + height = util::max(64, h); + map->setSize({ static_cast(width), static_cast(height) }); +} + +jni::Local NativeMapView::getStyleUrl(jni::JNIEnv& env) { + return jni::Make(env, map->getStyle().getURL()); +} + +void NativeMapView::setStyleUrl(jni::JNIEnv& env, const jni::String& url) { + map->getStyle().loadURL(jni::Make(env, url)); +} + +jni::Local NativeMapView::getStyleJson(jni::JNIEnv& env) { + return jni::Make(env, map->getStyle().getJSON()); +} + +void NativeMapView::setStyleJson(jni::JNIEnv& env, const jni::String& json) { + map->getStyle().loadJSON(jni::Make(env, json)); +} + +void NativeMapView::setLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds) { + mbgl::BoundOptions bounds; + if (jBounds) { + bounds.withLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds)); + } else { + bounds.withLatLngBounds(mbgl::LatLngBounds::unbounded()); + } + map->setBounds(bounds); +} + +void NativeMapView::cancelTransitions(jni::JNIEnv&) { + map->cancelTransitions(); +} + +void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) { + map->setGestureInProgress(inProgress); +} + +void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::jlong duration) { + mbgl::AnimationOptions animationOptions; + if (duration > 0) { + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + animationOptions.easing.emplace(mbgl::util::UnitBezier {0.25, 0.46, 0.45, 0.94}); + } + map->moveBy({dx, dy}, animationOptions); +} + +void NativeMapView::jumpTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { + mbgl::CameraOptions options; + if (bearing != -1) { + options.bearing = bearing; + } + options.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + options.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + options.pitch = pitch; + } + if (zoom != -1) { + options.zoom = zoom; + } + + map->jumpTo(options); +} + +void NativeMapView::easeTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding, jni::jboolean easing) { + mbgl::CameraOptions cameraOptions; + if (bearing != -1) { + cameraOptions.bearing = bearing; + } + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + cameraOptions.pitch = pitch; + } + if (zoom != -1) { + cameraOptions.zoom = zoom; + } + + mbgl::AnimationOptions animationOptions; + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + if (!easing) { + // add a linear interpolator instead of easing + animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 }); + } + + map->easeTo(cameraOptions, animationOptions); +} + +void NativeMapView::flyTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { + mbgl::CameraOptions cameraOptions; + if (bearing != -1) { + cameraOptions.bearing = bearing; + } + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + cameraOptions.pitch = pitch; + } + if (zoom != -1) { + cameraOptions.zoom = zoom; + } + + mbgl::AnimationOptions animationOptions; + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + map->flyTo(cameraOptions, animationOptions); +} + +jni::Local> NativeMapView::getLatLng(JNIEnv& env) { + return LatLng::New(env, *map->getCameraOptions(mbgl::nullopt).center); +} + +void NativeMapView::setLatLng(jni::JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude, const jni::Array& padding, jni::jlong duration) { + mbgl::CameraOptions cameraOptions; + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + map->easeTo(cameraOptions, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +jni::Local> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds, double top, double left, double bottom, double right, double bearing, double tilt) { + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt), pixelRatio); +} + +jni::Local> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, const jni::Object& jGeometry, double top, double left, double bottom, double right, double bearing, double tilt) { + auto geometry = geojson::Geometry::convert(env, jGeometry); + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt), pixelRatio); +} + +void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) { + if (reachable) { + mbgl::NetworkStatus::Reachable(); + } +} + +void NativeMapView::resetPosition(jni::JNIEnv&) { + map->jumpTo(mbgl::CameraOptions().withCenter(mbgl::LatLng {}).withZoom(0.0).withBearing(0.0).withPitch(0.0)); +} + +jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) { + return *map->getCameraOptions().pitch; +} + +void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withPitch(pitch), + mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); +} + +void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jdouble x, jni::jdouble y, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate{ x, y }), + mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); +} + +jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) { + return *map->getCameraOptions().zoom; +} + +void NativeMapView::resetZoom(jni::JNIEnv&) { + map->jumpTo(mbgl::CameraOptions().withZoom(0.0)); +} + +void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setBounds(BoundOptions().withMinZoom(zoom)); +} + +jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) { + return *map->getBounds().minZoom; +} + +void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setBounds(BoundOptions().withMaxZoom(zoom)); +} + +jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) { + return *map->getBounds().maxZoom; +} + +void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) { + mbgl::ScreenCoordinate first(sx, sy); + mbgl::ScreenCoordinate second(ex, ey); + map->rotateBy(first, second, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withBearing(degrees), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) { + mbgl::ScreenCoordinate anchor(cx, cy); + map->easeTo(mbgl::CameraOptions().withBearing(degrees).withAnchor(anchor), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) { + return *map->getCameraOptions().bearing; +} + +void NativeMapView::resetNorth(jni::JNIEnv&) { + map->easeTo(mbgl::CameraOptions().withBearing(0.0), mbgl::AnimationOptions {{mbgl::Milliseconds(500)}}); +} + +void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, const jni::Array>& coordinates, const jni::Object& padding, jdouble direction, jni::jlong duration) { + NullCheck(env, &coordinates); + std::size_t count = coordinates.Length(env); + + std::vector latLngs; + latLngs.reserve(count); + + for (std::size_t i = 0; i < count; i++) { + latLngs.push_back(LatLng::getLatLng(env, coordinates.Get(env, i))); + } + + mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) }; + mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets); + if (direction >= 0) { + cameraOptions.bearing = direction; + } + + mbgl::AnimationOptions animationOptions; + if (duration > 0) { + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + // equivalent to kCAMediaTimingFunctionDefault in iOS + animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 }); + } + + map->easeTo(cameraOptions, animationOptions); +} + +void NativeMapView::scheduleSnapshot(jni::JNIEnv&) { + mapRenderer.requestSnapshot([&](PremultipliedImage image) { + auto _env = android::AttachEnv(); + // Convert image to bitmap + auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image)); + + // invoke Mapview#OnSnapshotReady + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotReady, bitmap); + } + }); +} + +jni::Local> NativeMapView::getCameraPosition(jni::JNIEnv& env) { + return CameraPosition::New(env, map->getCameraOptions(mbgl::nullopt), pixelRatio); +} + +void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, const jni::String& jid) { + if (markerId == -1) { + return; + } + + std::string iconId = jni::Make(env, jid); + // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. + map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point(lon, lat), iconId }); +} + +jni::Local> NativeMapView::addMarkers(jni::JNIEnv& env, const jni::Array>& jmarkers) { + jni::NullCheck(env, &jmarkers); + std::size_t len = jmarkers.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + auto marker = jmarkers.Get(env, i); + ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation { + Marker::getPosition(env, marker), + Marker::getIconId(env, marker) + })); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +void NativeMapView::onLowMemory(JNIEnv&) { + rendererFrontend->reduceMemoryUse(); +} + +using DebugOptions = mbgl::MapDebugOptions; + +void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) { + DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision + : DebugOptions::NoDebug; + map->setDebug(debugOptions); +} + +void NativeMapView::cycleDebugOptions(JNIEnv&) { + map->cycleDebugOptions(); +} + +jni::jboolean NativeMapView::getDebug(JNIEnv&) { + return map->getDebug() != DebugOptions::NoDebug; +} + +jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) { + return map->isFullyLoaded(); +} + +jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) { + return mbgl::Projection::getMetersPerPixelAtLatitude(lat, zoom); +} + +jni::Local> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) { + mbgl::ProjectedMeters projectedMeters = mbgl::Projection::projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); + return ProjectedMeters::New(env, projectedMeters.northing(), projectedMeters.easting()); +} + +jni::Local> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) { + return LatLng::New(env, mbgl::Projection::latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting))); +} + +jni::Local> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) { + mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude)); + return PointF::New(env, static_cast(pixel.x), static_cast(pixel.y)); +} + +jni::Local> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) { + return LatLng::New(env, map->latLngForPixel(mbgl::ScreenCoordinate(x, y))); +} + +jni::Local> NativeMapView::addPolylines(JNIEnv& env, const jni::Array>& polylines) { + NullCheck(env, &polylines); + std::size_t len = polylines.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polylines.Get(env, i)); + ids.push_back(map->addAnnotation(annotation)); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + + +jni::Local> NativeMapView::addPolygons(JNIEnv& env, const jni::Array>& polygons) { + NullCheck(env, &polygons); + std::size_t len = polygons.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygons.Get(env, i)); + ids.push_back(map->addAnnotation(annotation)); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, const jni::Object& polyline) { + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline); + map->updateAnnotation(polylineId, annotation); +} + +void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, const jni::Object& polygon) { + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon); + map->updateAnnotation(polygonId, annotation); +} + +void NativeMapView::removeAnnotations(JNIEnv& env, const jni::Array& ids) { + NullCheck(env, &ids); + std::size_t len = ids.Length(env); + auto elements = jni::GetArrayElements(env, *ids); + jlong* jids = std::get<0>(elements).get(); + + for (std::size_t i = 0; i < len; i++) { + if(jids[i] == -1L) { + continue; + } + map->removeAnnotation(jids[i]); + } +} + +void NativeMapView::addAnnotationIcon(JNIEnv& env, const jni::String& symbol, jint w, jint h, jfloat scale, const jni::Array& jpixels) { + const std::string symbolName = jni::Make(env, symbol); + + NullCheck(env, &jpixels); + std::size_t size = jpixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(w), static_cast(h) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + map->addAnnotationImage(std::make_unique( + symbolName, std::move(premultipliedImage), float(scale))); +} + +void NativeMapView::removeAnnotationIcon(JNIEnv& env, const jni::String& symbol) { + const std::string symbolName = jni::Make(env, symbol); + map->removeAnnotationImage(symbolName); +} + +jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, const jni::String& symbolName) { + return map->getTopOffsetPixelsForAnnotationImage(jni::Make(env, symbolName)); +} + +jni::Local> NativeMapView::getTransitionOptions(JNIEnv& env) { + const auto transitionOptions = map->getStyle().getTransitionOptions(); + const auto duration = std::chrono::duration_cast(transitionOptions.duration.value_or(mbgl::Duration::zero())).count(); + const auto delay = std::chrono::duration_cast(transitionOptions.delay.value_or(mbgl::Duration::zero())).count(); + const auto enablePlacementTransitions = (jboolean) transitionOptions.enablePlacementTransitions; + return TransitionOptions::fromTransitionOptions(env, duration, delay, enablePlacementTransitions); +} + +void NativeMapView::setTransitionOptions(JNIEnv& env, const jni::Object& options) { + const mbgl::style::TransitionOptions transitionOptions( + Duration(mbgl::Milliseconds(TransitionOptions::getDuration(env, options))), + Duration(mbgl::Milliseconds(TransitionOptions::getDelay(env, options))), + TransitionOptions::isEnablePlacementTransitions(env, options) + ); + map->getStyle().setTransitionOptions(transitionOptions); +} + +jni::Local> NativeMapView::queryPointAnnotations(JNIEnv& env, const jni::Object& rect) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + // Convert input + mbgl::ScreenBox box = { + { RectF::getLeft(env, rect), RectF::getTop(env, rect) }, + { RectF::getRight(env, rect), RectF::getBottom(env, rect) }, + }; + + // Assume only points for now + mbgl::AnnotationIDs ids = rendererFrontend->queryPointAnnotations(box); + + // Convert result + std::vector longIds(ids.begin(), ids.end()); + auto result = jni::Array::New(env, ids.size()); + result.SetRegion>(env, 0, longIds); + + return result; +} + +jni::Local> NativeMapView::queryShapeAnnotations(JNIEnv& env, const jni::Object& rect) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + // Convert input + mbgl::ScreenBox box = { + {RectF::getLeft(env, rect), RectF::getTop(env, rect)}, + {RectF::getRight(env, rect), RectF::getBottom(env, rect)}, + }; + + mbgl::AnnotationIDs ids = rendererFrontend->queryShapeAnnotations(box); + + // Convert result + std::vector longIds(ids.begin(), ids.end()); + auto result = jni::Array::New(env, ids.size()); + result.SetRegion>(env, 0, longIds); + + return result; +} + +jni::Local>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, + const jni::Array& layerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + mbgl::optional> layers; + if (layerIds && layerIds.Length(env) > 0) { + layers = android::conversion::toVector(env, layerIds); + } + mapbox::geometry::point point = {x, y}; + + return Feature::convert( + env, + rendererFrontend->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) })); +} + +jni::Local>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, + jni::jfloat right, jni::jfloat bottom, const jni::Array& layerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + mbgl::optional> layers; + if (layerIds && layerIds.Length(env) > 0) { + layers = toVector(env, layerIds); + } + mapbox::geometry::box box = { + mapbox::geometry::point{ left, top}, + mapbox::geometry::point{ right, bottom } + }; + + return Feature::convert( + env, + rendererFrontend->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) })); +} + +jni::Local> NativeMapView::getLight(JNIEnv& env) { + mbgl::style::Light* light = map->getStyle().getLight(); + if (light) { + return Light::createJavaLightPeer(env, *map, *light); + } else { + return jni::Local>(); + } +} + +jni::Local>> NativeMapView::getLayers(JNIEnv& env) { + + // Get the core layers + std::vector layers = map->getStyle().getLayers(); + + // Convert + auto jLayers = jni::Array>::New(env, layers.size()); + int index = 0; + for (auto layer : layers) { + jLayers.Set(env, index, LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, *layer)); + index++; + } + + return jLayers; +} + +jni::Local> NativeMapView::getLayer(JNIEnv& env, const jni::String& layerId) { + + // Find the layer + mbgl::style::Layer* coreLayer = map->getStyle().getLayer(jni::Make(env, layerId)); + if (!coreLayer) { + mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); + return jni::Local>(); + } + + // Create and return the layer's native peer + return LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, *coreLayer); +} + +void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, const jni::String& before) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + try { + layer->addToMap(*map, before ? mbgl::optional(jni::Make(env, before)) : mbgl::optional()); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, const jni::String& above) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + + // Find the sibling + auto layers = map->getStyle().getLayers(); + auto siblingId = jni::Make(env, above); + + size_t index = 0; + for (auto l : layers) { + if (l->getID() == siblingId) { + break; + } + index++; + } + + // Check if we found a sibling to place before + mbgl::optional before; + if (index + 1 > layers.size()) { + // Not found + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Could not find layer: ").append(siblingId).c_str()); + return; + } else if (index + 1 < layers.size()) { + // Place before the sibling + before = { layers.at(index + 1)->getID() }; + } + + // Add the layer + try { + layer->addToMap(*map, before); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + auto layers = map->getStyle().getLayers(); + + // Check index + int numLayers = layers.size() - 1; + if (index > numLayers || index < 0) { + Log::Error(Event::JNI, "Index out of range: %i", index); + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Invalid index").c_str()); + return; + } + + // Insert it below the current at that index + try { + layer->addToMap(*map, layers.at(index)->getID()); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + + +/** + * Remove layer at index. + */ +jni::jboolean NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) { + auto layers = map->getStyle().getLayers(); + + // Check index + int numLayers = layers.size() - 1; + if (index > numLayers || index < 0) { + Log::Warning(Event::JNI, "Index out of range: %i", index); + return jni::jni_false; + } + + std::unique_ptr coreLayer = map->getStyle().removeLayer(layers.at(index)->getID()); + if (coreLayer) { + jni::Local> layerObj = + LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, std::move(coreLayer)); + return jni::jni_true; + } + return jni::jni_false; +} + +/** + * Remove with wrapper object id. Ownership is transferred back to the wrapper + */ +jni::jboolean NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) { + assert(layerPtr != 0); + + mbgl::android::Layer *layer = reinterpret_cast(layerPtr); + std::unique_ptr coreLayer = map->getStyle().removeLayer(layer->get().getID()); + if (coreLayer) { + layer->setLayer(std::move(coreLayer)); + return jni::jni_true; + } + return jni::jni_false; +} + +jni::Local>> NativeMapView::getSources(JNIEnv& env) { + // Get the core sources + std::vector sources = map->getStyle().getSources(); + + // Convert + auto jSources = jni::Array>::New(env, sources.size()); + int index = 0; + for (auto source : sources) { + jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend)); + index++; + } + + return jSources; +} + +jni::Local> NativeMapView::getSource(JNIEnv& env, const jni::String& sourceId) { + // Find the source + mbgl::style::Source* coreSource = map->getStyle().getSource(jni::Make(env, sourceId)); + if (!coreSource) { + mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); + return jni::Local>(); + } + + // Create and return the source's native peer + return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend)); +} + +void NativeMapView::addSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { + assert(sourcePtr != 0); + + Source *source = reinterpret_cast(sourcePtr); + try { + source->addToMap(env, obj, *map, *rendererFrontend); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); + } +} + +jni::jboolean NativeMapView::removeSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { + assert(sourcePtr != 0); + + mbgl::android::Source *source = reinterpret_cast(sourcePtr); + if (source->removeFromMap(env, obj, *map)) { + source->releaseJavaPeer(); + return jni::jni_true; + } + + return jni::jni_false; +} + +void NativeMapView::addImage(JNIEnv& env, const jni::String& name, const jni::Object& bitmap, jni::jfloat scale, jni::jboolean sdf) { + jni::NullCheck(env, &bitmap); + mbgl::PremultipliedImage premultipliedImage = Bitmap::GetImage(env, bitmap); + + map->getStyle().addImage(std::make_unique( + jni::Make(env, name), + std::move(premultipliedImage), + float(scale), + sdf) + ); +} + +void NativeMapView::addImages(JNIEnv& env, const jni::Array>& jimages) { + jni::NullCheck(env, &jimages); + std::size_t len = jimages.Length(env); + + for (std::size_t i = 0; i < len; i++) { + auto image = mbgl::android::Image::getImage(env, jimages.Get(env, i)); + map->getStyle().addImage(std::make_unique(image)); + } +} + +void NativeMapView::removeImage(JNIEnv& env, const jni::String& name) { + map->getStyle().removeImage(jni::Make(env, name)); +} + +jni::Local> NativeMapView::getImage(JNIEnv& env, const jni::String& name) { + const mbgl::style::Image *image = map->getStyle().getImage(jni::Make(env, name)); + if (image) { + return Bitmap::CreateBitmap(env, image->getImage()); + } else { + return jni::Local>(); + } +} + +void NativeMapView::setPrefetchTiles(JNIEnv&, jni::jboolean enable) { + map->setPrefetchZoomDelta(enable ? util::DEFAULT_PREFETCH_ZOOM_DELTA : uint8_t(0)); +} + +jni::jboolean NativeMapView::getPrefetchTiles(JNIEnv&) { + return jni::jboolean(map->getPrefetchZoomDelta() > 0); +} + +mbgl::Map& NativeMapView::getMap() { + return *map; +} + +// Static methods // + +void NativeMapView::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + jni::MakePeer&, const jni::Object&, const jni::Object&, jni::jfloat, jni::jboolean>, + "nativeInitialize", + "nativeDestroy", + METHOD(&NativeMapView::resizeView, "nativeResizeView"), + METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), + METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), + METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), + METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), + METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), + METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), + METHOD(&NativeMapView::moveBy, "nativeMoveBy"), + METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), + METHOD(&NativeMapView::easeTo, "nativeEaseTo"), + METHOD(&NativeMapView::flyTo, "nativeFlyTo"), + METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), + METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), + METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), + METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), + METHOD(&NativeMapView::setReachability, "nativeSetReachability"), + METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), + METHOD(&NativeMapView::getPitch, "nativeGetPitch"), + METHOD(&NativeMapView::setPitch, "nativeSetPitch"), + METHOD(&NativeMapView::getZoom, "nativeGetZoom"), + METHOD(&NativeMapView::setZoom, "nativeSetZoom"), + METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), + METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), + METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), + METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), + METHOD(&NativeMapView::setBearing, "nativeSetBearing"), + METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), + METHOD(&NativeMapView::getBearing, "nativeGetBearing"), + METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), + METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), + METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), + METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), + METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), + METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), + METHOD(&NativeMapView::setDebug, "nativeSetDebug"), + METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), + METHOD(&NativeMapView::getDebug, "nativeGetDebug"), + METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), + METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), + METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), + METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), + METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), + METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), + METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), + METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), + METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), + METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), + METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), + METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), + METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), + METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), + METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), + METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), + METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), + METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), + METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), + METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), + METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), + METHOD(&NativeMapView::getLight, "nativeGetLight"), + METHOD(&NativeMapView::getLayers, "nativeGetLayers"), + METHOD(&NativeMapView::getLayer, "nativeGetLayer"), + METHOD(&NativeMapView::addLayer, "nativeAddLayer"), + METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), + METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), + METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), + METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), + METHOD(&NativeMapView::getSources, "nativeGetSources"), + METHOD(&NativeMapView::getSource, "nativeGetSource"), + METHOD(&NativeMapView::addSource, "nativeAddSource"), + METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), + METHOD(&NativeMapView::addImage, "nativeAddImage"), + METHOD(&NativeMapView::addImages, "nativeAddImages"), + METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), + METHOD(&NativeMapView::getImage, "nativeGetImage"), + METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), + METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), + METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles") + ); +} + +} // namespace android +} // namespace mbgl diff --git a/src/native_map_view.hpp b/src/native_map_view.hpp new file mode 100755 index 000000000..26567a003 --- /dev/null +++ b/src/native_map_view.hpp @@ -0,0 +1,261 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "graphics/pointf.hpp" +#include "graphics/rectf.hpp" +#include "geojson/feature.hpp" +#include "geojson/geometry.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/projected_meters.hpp" +#include "style/layers/layer_manager.hpp" +#include "style/sources/source.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "map/camera_position.hpp" +#include "map/image.hpp" +#include "style/light.hpp" +#include "bitmap.hpp" + +#include +#include +#include +#include +#include +#include + +namespace mbgl { +namespace android { + +class AndroidRendererFrontend; +class FileSource; +class MapRenderer; + +class NativeMapView : public MapObserver { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; }; + + static void registerNative(jni::JNIEnv&); + + NativeMapView(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + const jni::Object&, + jni::jfloat, + jni::jboolean); + + virtual ~NativeMapView(); + + // mbgl::RendererBackend (mbgl::MapObserver) // + void onCameraWillChange(MapObserver::CameraChangeMode) override; + void onCameraIsChanging() override; + void onCameraDidChange(MapObserver::CameraChangeMode) override; + void onWillStartLoadingMap() override; + void onDidFinishLoadingMap() override; + void onDidFailLoadingMap(MapLoadError, const std::string&) override; + void onWillStartRenderingFrame() override; + void onDidFinishRenderingFrame(MapObserver::RenderMode, bool) override; + void onWillStartRenderingMap() override; + void onDidFinishRenderingMap(MapObserver::RenderMode) override; + void onDidBecomeIdle() override; + void onDidFinishLoadingStyle() override; + void onSourceChanged(mbgl::style::Source&) override; + void onStyleImageMissing(const std::string&) override; + bool onCanRemoveUnusedStyleImage(const std::string&) override; + + // JNI // + + void resizeView(jni::JNIEnv&, int, int); + + jni::Local getStyleUrl(jni::JNIEnv&); + + void setStyleUrl(jni::JNIEnv&, const jni::String&); + + jni::Local getStyleJson(jni::JNIEnv&); + + void setStyleJson(jni::JNIEnv&, const jni::String&); + + void setLatLngBounds(jni::JNIEnv&, const jni::Object&); + + void cancelTransitions(jni::JNIEnv&); + + void setGestureInProgress(jni::JNIEnv&, jni::jboolean); + + void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong); + + void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, const jni::Array&); + + void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&, jni::jboolean); + + void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&); + + jni::Local> getLatLng(JNIEnv&); + + void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, const jni::Array&, jni::jlong); + + jni::Local> getCameraForLatLngBounds(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); + + jni::Local> getCameraForGeometry(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); + + void setReachability(jni::JNIEnv&, jni::jboolean); + + void resetPosition(jni::JNIEnv&); + + jni::jdouble getPitch(jni::JNIEnv&); + + void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong); + + void setZoom(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + jni::jdouble getZoom(jni::JNIEnv&); + + void resetZoom(jni::JNIEnv&); + + void setMinZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMinZoom(jni::JNIEnv&); + + void setMaxZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMaxZoom(jni::JNIEnv&); + + void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong); + + void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + jni::jdouble getBearing(jni::JNIEnv&); + + void resetNorth(jni::JNIEnv&); + + void setVisibleCoordinateBounds(JNIEnv&, const jni::Array>&, const jni::Object&, jni::jdouble, jni::jlong); + + void scheduleSnapshot(jni::JNIEnv&); + + jni::Local> getCameraPosition(jni::JNIEnv&); + + void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, const jni::String&); + + jni::Local> addMarkers(jni::JNIEnv&, const jni::Array>&); + + void onLowMemory(JNIEnv& env); + + void setDebug(JNIEnv&, jni::jboolean); + + void cycleDebugOptions(JNIEnv&); + + jni::jboolean getDebug(JNIEnv&); + + jni::jboolean isFullyLoaded(JNIEnv&); + + jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Local> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Local> pixelForLatLng(JNIEnv&, jdouble, jdouble); + + jni::Local> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble); + + jni::Local> latLngForPixel(JNIEnv&, jfloat, jfloat); + + jni::Local> addPolylines(JNIEnv&, const jni::Array>&); + + jni::Local> addPolygons(JNIEnv&, const jni::Array>&); + + void updatePolyline(JNIEnv&, jlong, const jni::Object&); + + void updatePolygon(JNIEnv&, jlong, const jni::Object&); + + void removeAnnotations(JNIEnv&, const jni::Array&); + + void addAnnotationIcon(JNIEnv&, const jni::String&, jint, jint, jfloat, const jni::Array&); + + void removeAnnotationIcon(JNIEnv&, const jni::String&); + + jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, const jni::String&); + + jni::Local> getTransitionOptions(JNIEnv&); + + void setTransitionOptions(JNIEnv&, const jni::Object&); + + jni::Local> queryPointAnnotations(JNIEnv&, const jni::Object&); + + jni::Local> queryShapeAnnotations(JNIEnv&, const jni::Object&); + + jni::Local>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, + const jni::Array&, + const jni::Array>& jfilter); + + jni::Local>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, + jni::jfloat, const jni::Array&, + const jni::Array>& jfilter); + + jni::Local> getLight(JNIEnv&); + + jni::Local>> getLayers(JNIEnv&); + + jni::Local> getLayer(JNIEnv&, const jni::String&); + + void addLayer(JNIEnv&, jlong, const jni::String&); + + void addLayerAbove(JNIEnv&, jlong, const jni::String&); + + void addLayerAt(JNIEnv&, jni::jlong, jni::jint); + + jni::jboolean removeLayerAt(JNIEnv&, jni::jint); + + jni::jboolean removeLayer(JNIEnv&, jlong); + + jni::Local>> getSources(JNIEnv&); + + jni::Local> getSource(JNIEnv&, const jni::String&); + + void addSource(JNIEnv&, const jni::Object&, jlong nativePtr); + + jni::jboolean removeSource(JNIEnv&, const jni::Object&, jlong nativePtr); + + void addImage(JNIEnv&, const jni::String&, const jni::Object& bitmap, jni::jfloat, jni::jboolean); + + void addImages(JNIEnv&, const jni::Array>&); + + void removeImage(JNIEnv&, const jni::String&); + + jni::Local> getImage(JNIEnv&, const jni::String&); + + void setPrefetchTiles(JNIEnv&, jni::jboolean); + + jni::jboolean getPrefetchTiles(JNIEnv&); + + mbgl::Map& getMap(); + +private: + std::unique_ptr rendererFrontend; + + JavaVM *vm = nullptr; + jni::WeakReference> javaPeer; + + MapRenderer& mapRenderer; + + std::string styleUrl; + + float pixelRatio; + + // Minimum texture size according to OpenGL ES 2.0 specification. + int width = 64; + int height = 64; + + // Ensure these are initialised last + std::unique_ptr map; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_manager.cpp b/src/offline/offline_manager.cpp new file mode 100644 index 000000000..029252f78 --- /dev/null +++ b/src/offline/offline_manager.cpp @@ -0,0 +1,330 @@ +#include "offline_manager.hpp" + +#include + +#include "../attach_env.hpp" + +namespace mbgl { +namespace android { + +// OfflineManager // + +OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object& jFileSource) + : fileSource(std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} + +OfflineManager::~OfflineManager() {} + +void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { + fileSource->setOfflineMapboxTileCountLimit(limit); +} + +void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + fileSource->listOfflineRegions([ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected regions) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (regions) { + OfflineManager::ListOfflineRegionsCallback::onList( + *env, *jFileSource, *callback, *regions); + } else { + OfflineManager::ListOfflineRegionsCallback::onError( + *env, *callback, regions.error()); + } + }); +} + +void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, + const jni::Object& jFileSource_, + const jni::Object& definition_, + const jni::Array& metadata_, + const jni::Object& callback_) { + // Convert + auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); + + mbgl::OfflineRegionMetadata metadata; + if (metadata_) { + metadata = OfflineRegion::metadata(env_, metadata_); + } + + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + // Create region + fileSource->createOfflineRegion(definition, metadata, [ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected region) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (region) { + OfflineManager::CreateOfflineRegionCallback::onCreate( + *env, *jFileSource, *callback, *region + ); + } else { + OfflineManager::CreateOfflineRegionCallback::onError( + *env, *callback, region.error()); + } + }); +} + +void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, + const jni::String& jString_, + const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + auto path = jni::Make(env_, jString_); + fileSource->mergeOfflineRegions(path, [ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected regions) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (regions) { + OfflineManager::MergeOfflineRegionsCallback::onMerge( + *env, *jFileSource, *callback, *regions); + } else { + OfflineManager::MergeOfflineRegionsCallback::onError( + *env, *callback, regions.error()); + } + }); +} + +void OfflineManager::resetDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->resetDatabase([ + //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr exception) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (exception) { + OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); + } else { + OfflineManager::FileSourceCallback::onSuccess(*env, *callback); + } + }); +} + +void OfflineManager::invalidateAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->invalidateAmbientCache([ + //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr exception) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (exception) { + OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); + } else { + OfflineManager::FileSourceCallback::onSuccess(*env, *callback); + } + }); +} + +void OfflineManager::clearAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->clearAmbientCache([ + //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr exception) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (exception) { + OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); + } else { + OfflineManager::FileSourceCallback::onSuccess(*env, *callback); + } + }); +} + +void OfflineManager::setMaximumAmbientCacheSize(jni::JNIEnv& env_, const jni::jlong size_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->setMaximumAmbientCacheSize(size_, [ + //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr exception) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (exception) { + OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); + } else { + OfflineManager::FileSourceCallback::onSuccess(*env, *callback); + } + }); +} + +// FileSource::FileSourceCallback // + +void OfflineManager::FileSourceCallback::onSuccess(jni::JNIEnv& env, + const jni::Object& callback) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onSuccess"); + callback.Call(env, method); +} + +void OfflineManager::FileSourceCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& message) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + callback.Call(env, method, message); +} + +void OfflineManager::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"), + METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"), + METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"), + METHOD(&OfflineManager::mergeOfflineRegions, "mergeOfflineRegions"), + METHOD(&OfflineManager::resetDatabase, "nativeResetDatabase"), + METHOD(&OfflineManager::invalidateAmbientCache, "nativeInvalidateAmbientCache"), + METHOD(&OfflineManager::clearAmbientCache, "nativeClearAmbientCache"), + METHOD(&OfflineManager::setMaximumAmbientCacheSize, "nativeSetMaximumAmbientCacheSize"), + METHOD(&OfflineManager::putResourceWithUrl, "putResourceWithUrl")); +} + +// OfflineManager::ListOfflineRegionsCallback // + +void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegions& regions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod>)>(env, "onList"); + + std::size_t index = 0; + auto jregions = jni::Array>::New(env, regions.size()); + for (auto& region : regions) { + jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); + index++; + } + + callback.Call(env, method, jregions); +} + +// OfflineManager::CreateOfflineRegionCallback // + +void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegion& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onCreate"); + + callback.Call(env, method, OfflineRegion::New(env, jFileSource, std::move(region))); +} + +// OfflineManager::MergeOfflineRegionsCallback // + +void OfflineManager::MergeOfflineRegionsCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::MergeOfflineRegionsCallback::onMerge(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegions& regions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod>)>(env, "onMerge"); + + std::size_t index = 0; + auto jregions = jni::Array>::New(env, regions.size()); + for (auto& region : regions) { + jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); + index++; + } + + callback.Call(env, method, jregions); +} + +void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, + const jni::String& url_, + const jni::Array& arr, + jlong modified, + jlong expires, + const jni::String& eTag_, + jboolean mustRevalidate) { + auto url = jni::Make(env, url_); + auto data = std::make_shared(arr.Length(env), char()); + jni::GetArrayRegion(env, *arr, 0, data->size(), reinterpret_cast(&(*data)[0])); + mbgl::Resource resource(mbgl::Resource::Kind::Unknown, url); + mbgl::Response response; + response.data = data; + response.mustRevalidate = mustRevalidate; + if (eTag_) { + response.etag = jni::Make(env, eTag_); + } + if (modified > 0) { + response.modified = Timestamp(mbgl::Seconds(modified)); + } + if (expires > 0) { + response.expires = Timestamp(mbgl::Seconds(expires)); + } + + fileSource->put(resource, response); +} + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_manager.hpp b/src/offline/offline_manager.hpp new file mode 100644 index 000000000..058cfb5b4 --- /dev/null +++ b/src/offline/offline_manager.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +#include "../file_source.hpp" +#include "offline_region.hpp" +#include "offline_region_definition.hpp" +#include "../java_types.hpp" + +#include + +namespace mbgl { + +class DefaultFileSource; + +namespace android { + +class OfflineManager { +public: + + class ListOfflineRegionsCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";} + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onList(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegions&); + }; + + class CreateOfflineRegionCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; } + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onCreate(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegion&); + }; + + class MergeOfflineRegionsCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$MergeOfflineRegionsCallback";} + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onMerge(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegions&); + }; + + struct FileSourceCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$FileSourceCallback";} + + static void onSuccess(jni::JNIEnv&, const jni::Object&); + + static void onError(jni::JNIEnv&, const jni::Object&, const jni::String&); + }; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }; + + static void registerNative(jni::JNIEnv&); + + OfflineManager(jni::JNIEnv&, const jni::Object&); + ~OfflineManager(); + + void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit); + + void listOfflineRegions(jni::JNIEnv&, const jni::Object&, const jni::Object& callback); + + void createOfflineRegion(jni::JNIEnv&, + const jni::Object& jFileSource_, + const jni::Object& definition, + const jni::Array& metadata, + const jni::Object& callback); + + void mergeOfflineRegions(jni::JNIEnv&, + const jni::Object&, + const jni::String&, + const jni::Object&); + + void putResourceWithUrl(jni::JNIEnv&, + const jni::String& url, + const jni::Array& data, + jlong modified, + jlong expires, + const jni::String& eTag, + jboolean mustRevalidate); + + void resetDatabase(jni::JNIEnv&, const jni::Object& callback_); + + void invalidateAmbientCache(jni::JNIEnv&, const jni::Object& callback_); + + void clearAmbientCache(jni::JNIEnv&, const jni::Object& callback_); + + void setMaximumAmbientCacheSize(jni::JNIEnv&, const jni::jlong size, const jni::Object& callback_); + +private: + std::shared_ptr fileSource; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region.cpp b/src/offline/offline_region.cpp new file mode 100644 index 000000000..ac9f491ab --- /dev/null +++ b/src/offline/offline_region.cpp @@ -0,0 +1,300 @@ +#include "offline_region.hpp" + +#include +#include + +#include "offline_region_definition.hpp" +#include "offline_region_error.hpp" +#include "offline_region_status.hpp" +#include "../attach_env.hpp" + +namespace mbgl { +namespace android { + +// OfflineRegion // + +OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object& jFileSource) + : region(reinterpret_cast(offlineRegionPtr)) + , fileSource(std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} + +OfflineRegion::~OfflineRegion() {} + +void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Object& callback) { + + // Define the observer + class Observer : public mbgl::OfflineRegionObserver { + public: + Observer(jni::Global, jni::EnvAttachingDeleter> callback_) + : callback(std::move(callback_)) { + } + + void statusChanged(mbgl::OfflineRegionStatus status) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod)>(*env, "onStatusChanged"); + + callback.Call(*env, method, OfflineRegionStatus::New(*env, status)); + } + + void responseError(mbgl::Response::Error error) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod)>(*env, "onError"); + + callback.Call(*env, method, OfflineRegionError::New(*env, error)); + } + + void mapboxTileCountLimitExceeded(uint64_t limit) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod(*env, "mapboxTileCountLimitExceeded"); + + callback.Call(*env, method, jlong(limit)); + } + + jni::Global, jni::EnvAttachingDeleter> callback; + }; + + // Set the observer + fileSource->setOfflineRegionObserver(*region, std::make_unique(jni::NewGlobal(env_, callback))); +} + +void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) { + // State + mbgl::OfflineRegionDownloadState state; + switch (jState) { + case 0: + state = mbgl::OfflineRegionDownloadState::Inactive; + break; + case 1: + state = mbgl::OfflineRegionDownloadState::Active; + break; + default: + mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active)."); + return; + } + + fileSource->setOfflineRegionDownloadState(*region, state); +} + +void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->getOfflineRegionStatus(*region, [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](mbgl::expected status) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (status) { + OfflineRegionStatusCallback::onStatus(*env, *callback, std::move(*status)); + } else { + OfflineRegionStatusCallback::onError(*env, *callback, status.error()); + } + }); +} + +void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->deleteOfflineRegion(std::move(*region), [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr error) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (error) { + OfflineRegionDeleteCallback::onError(*env, *callback, error); + } else { + OfflineRegionDeleteCallback::onDelete(*env, *callback); + } + }); +} + +void OfflineRegion::invalidateOfflineRegion(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->invalidateOfflineRegion(*region, [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](std::exception_ptr error) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (error) { + OfflineRegionInvalidateCallback::onError(*env, *callback, error); + } else { + OfflineRegionInvalidateCallback::onInvalidate(*env, *callback); + } + }); +} + +void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Array& jMetadata, const jni::Object& callback_) { + auto metadata = OfflineRegion::metadata(env_, jMetadata); + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->updateOfflineMetadata(region->getID(), metadata, [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](mbgl::expected data) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (data) { + OfflineRegionUpdateMetadataCallback::onUpdate(*env, *callback, std::move(*data)); + } else { + OfflineRegionUpdateMetadataCallback::onError(*env, *callback, data.error()); + } + }); +} + +jni::Local> OfflineRegion::New(jni::JNIEnv& env, const jni::Object& jFileSource, mbgl::OfflineRegion region) { + + // Definition + auto definition = region.getDefinition().match( + [&](const mbgl::OfflineTilePyramidRegionDefinition def) { + return OfflineTilePyramidRegionDefinition::New(env, def); + }, [&](const mbgl::OfflineGeometryRegionDefinition def) { + return OfflineGeometryRegionDefinition::New(env, def); + }); + + // Create region java object + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jlong, jni::Object, jni::Array>(env); + + return javaClass.New(env, constructor, + reinterpret_cast(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap + jFileSource, + jni::jlong(region.getID()), + definition, + OfflineRegion::metadata(env, region.getMetadata())); +} + +jni::Local> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) { + std::vector convertedMetadata(metadata_.begin(), metadata_.end()); + std::size_t length = static_cast(convertedMetadata.size()); + auto metadata = jni::Array::New(env, length); + metadata.SetRegion>(env, 0, convertedMetadata); + return metadata; +} + +mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, const jni::Array& metadata_) { + std::size_t length = metadata_.Length(env); + auto metadata_tmp = std::vector(); + metadata_tmp.resize(length); + metadata_.GetRegion>(env, 0, metadata_tmp); + auto metadata = std::vector(metadata_tmp.begin(), metadata_tmp.end()); + return metadata; +} + +void OfflineRegion::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"), + METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"), + METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"), + METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"), + METHOD(&OfflineRegion::invalidateOfflineRegion, "invalidateOfflineRegion"), + METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata") + ); +} + +// OfflineRegionObserver // + +// OfflineRegionStatusCallback // + +void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env, + const jni::Object& callback, + mbgl::optional status) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onStatus"); + + callback.Call(env, method, OfflineRegionStatus::New(env, std::move(*status))); +} + +// OfflineRegionDeleteCallback // + +void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, const jni::Object& callback) { + // Trigger callback + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onDelete"); + + callback.Call(env, method); +} + +// OfflineRegionUpdateMetadataCallback // + +void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env, + const jni::Object& callback, + mbgl::optional metadata) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onUpdate"); + + callback.Call(env, method, OfflineRegion::metadata(env, std::move(*metadata))); +} + +// OfflineRegionInvalidateCallback // + +void OfflineRegion::OfflineRegionInvalidateCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionInvalidateCallback::onInvalidate(jni::JNIEnv& env, const jni::Object& callback) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onInvalidate"); + callback.Call(env, method); +} + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region.hpp b/src/offline/offline_region.hpp new file mode 100644 index 000000000..dda253469 --- /dev/null +++ b/src/offline/offline_region.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include "../file_source.hpp" + +#include + +namespace mbgl { +namespace android { + +class OfflineRegion { +public: + class OfflineRegionObserver { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; }; + }; + + class OfflineRegionStatusCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onStatus(jni::JNIEnv&, + const jni::Object&, + mbgl::optional); + }; + + class OfflineRegionDeleteCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onDelete(jni::JNIEnv&, const jni::Object&); + }; + + class OfflineRegionInvalidateCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionInvalidateCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onInvalidate(jni::JNIEnv&, const jni::Object&); + }; + + class OfflineRegionUpdateMetadataCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onUpdate(jni::JNIEnv&, + const jni::Object&, + mbgl::optional); + }; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }; + + OfflineRegion(jni::JNIEnv&, jni::jlong, const jni::Object&); + + ~OfflineRegion(); + + void setOfflineRegionObserver(jni::JNIEnv&, const jni::Object&); + + void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint); + + void getOfflineRegionStatus(jni::JNIEnv&, const jni::Object&); + + void deleteOfflineRegion(jni::JNIEnv&, const jni::Object&); + + void invalidateOfflineRegion(jni::JNIEnv&, const jni::Object&); + + void updateOfflineRegionMetadata(jni::JNIEnv&, const jni::Array&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::Object&, mbgl::OfflineRegion); + + static jni::Local> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata); + + static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, const jni::Array&); + + static void registerNative(jni::JNIEnv&); + +private: + std::unique_ptr region; + std::shared_ptr fileSource; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_definition.cpp b/src/offline/offline_region_definition.cpp new file mode 100644 index 000000000..bb9dfc8dd --- /dev/null +++ b/src/offline/offline_region_definition.cpp @@ -0,0 +1,107 @@ +#include "offline_region_definition.hpp" + +#include "../geometry/lat_lng_bounds.hpp" +#include "../geojson/geometry.hpp" + +#include + +namespace mbgl { +namespace android { + +// OfflineRegionDefinition // + +void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, + const jni::Object& jDefinition) { + if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { + return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); + } else if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { + return OfflineGeometryRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); + } + + throw std::runtime_error("Unknown offline region definition java class"); +} + +// OfflineTilePyramidRegionDefinition // + +jni::Local> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); + + return javaClass.New(env, constructor, + jni::Make(env, definition.styleURL), + LatLngBounds::New(env, definition.bounds), + definition.minZoom, + definition.maxZoom, + definition.pixelRatio, + jni::jboolean(definition.includeIdeographs)); +} + +mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { + // Field references + static auto& javaClass = jni::Class::Singleton(env); + static auto styleURLF = javaClass.GetField(env, "styleURL"); + static auto boundsF = javaClass.GetField>(env, "bounds"); + static auto minZoomF = javaClass.GetField(env, "minZoom"); + static auto maxZoomF = javaClass.GetField(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); + static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); + + return mbgl::OfflineTilePyramidRegionDefinition( + jni::Make(env, jDefinition.Get(env, styleURLF)), + LatLngBounds::getLatLngBounds(env, jDefinition.Get(env, boundsF)), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF), + jDefinition.Get(env, includeIdeographsF) + ); +} + +void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +// OfflineGeometryRegionDefinition // + +jni::Local> OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); + + return javaClass.New(env, constructor, + jni::Make(env, definition.styleURL), + geojson::Geometry::New(env, definition.geometry), + definition.minZoom, + definition.maxZoom, + definition.pixelRatio, + jni::jboolean(definition.includeIdeographs)); +} + +mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { + // Field references + static auto& javaClass = jni::Class::Singleton(env); + static auto styleURLF = javaClass.GetField(env, "styleURL"); + static auto geometryF = javaClass.GetField>(env, "geometry"); + static auto minZoomF = javaClass.GetField(env, "minZoom"); + static auto maxZoomF = javaClass.GetField(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); + static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); + + return mbgl::OfflineGeometryRegionDefinition( + jni::Make(env, jDefinition.Get(env, styleURLF)), + geojson::Geometry::convert(env, jDefinition.Get(env, geometryF)), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF), + jDefinition.Get(env, includeIdeographsF) + ); +} + +void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_definition.hpp b/src/offline/offline_region_definition.hpp new file mode 100644 index 000000000..827fac0a8 --- /dev/null +++ b/src/offline/offline_region_definition.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionDefinition { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; }; + + static void registerNative(jni::JNIEnv&); + + static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, const jni::Object& jDefinition); +}; + +class OfflineTilePyramidRegionDefinition { +public: + using SuperTag = OfflineRegionDefinition; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); + + static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +class OfflineGeometryRegionDefinition { +public: + using SuperTag = OfflineRegionDefinition; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); + + static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_error.cpp b/src/offline/offline_region_error.cpp new file mode 100644 index 000000000..199bbafa6 --- /dev/null +++ b/src/offline/offline_region_error.cpp @@ -0,0 +1,44 @@ +#include "offline_region_error.hpp" + +namespace mbgl { +namespace android { + +jni::Local> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) { + + // Handle the value of reason independently of the underlying int value + std::string reason; + switch(error.reason) { + case mbgl::Response::Error::Reason::Success: + reason = "REASON_SUCCESS"; + break; + case mbgl::Response::Error::Reason::NotFound: + reason = "REASON_NOT_FOUND"; + break; + case mbgl::Response::Error::Reason::Server: + reason = "REASON_SERVER"; + break; + case mbgl::Response::Error::Reason::Connection: + reason = "REASON_CONNECTION"; + break; + case mbgl::Response::Error::Reason::RateLimit: + reason = "REASON_RATE_LIMIT"; + break; + case mbgl::Response::Error::Reason::Other: + reason = "REASON_OTHER"; + break; + } + + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + + return javaClass.New(env, constructor, + jni::Make(env, reason), + jni::Make(env, error.message)); +} + +void OfflineRegionError::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_error.hpp b/src/offline/offline_region_error.hpp new file mode 100644 index 000000000..151e05ab1 --- /dev/null +++ b/src/offline/offline_region_error.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionError { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::Response::Error); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_status.cpp b/src/offline/offline_region_status.cpp new file mode 100644 index 000000000..5dd9f20a7 --- /dev/null +++ b/src/offline/offline_region_status.cpp @@ -0,0 +1,38 @@ +#include "offline_region_status.hpp" + +namespace mbgl { +namespace android { + +jni::Local> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) { + + // Convert to jint + jint downloadState; + switch(status.downloadState) { + case mbgl::OfflineRegionDownloadState::Inactive: + downloadState = 0; + break; + case mbgl::OfflineRegionDownloadState::Active: + downloadState = 1; + break; + } + + // Create java object + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, + downloadState, + jlong(status.completedResourceCount), + jlong(status.completedResourceSize), + jlong(status.completedTileCount), + jlong(status.completedTileSize), + jlong(status.requiredResourceCount), + jboolean(status.requiredResourceCountIsPrecise) + ); +} + +void OfflineRegionStatus::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/src/offline/offline_region_status.hpp b/src/offline/offline_region_status.hpp new file mode 100644 index 000000000..9ef48ec35 --- /dev/null +++ b/src/offline/offline_region_status.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionStatus { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/run_loop.cpp b/src/run_loop.cpp new file mode 100644 index 000000000..a9cbfb57a --- /dev/null +++ b/src/run_loop.cpp @@ -0,0 +1,256 @@ +#include "run_loop_impl.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PIPE_OUT 0 +#define PIPE_IN 1 + +namespace { + +using namespace mbgl::util; + +int looperCallbackNew(int fd, int, void* data) { + int buffer[1]; + while (read(fd, buffer, sizeof(buffer)) > 0) {} + + auto runLoopImpl = reinterpret_cast(data); + + runLoopImpl->coalesce.clear(); + ALooper_wake(runLoopImpl->loop); + + return 1; +} + +int looperCallbackDefault(int fd, int, void* data) { + int buffer[1]; + while (read(fd, buffer, sizeof(buffer)) > 0) {} + + auto runLoopImpl = reinterpret_cast(data); + + runLoopImpl->coalesce.clear(); + runLoopImpl->runLoop->runOnce(); + + if (!runLoopImpl->running) { + ALooper_wake(runLoopImpl->loop); + } + + return 1; +} + +} // namespace + +namespace mbgl { +namespace util { + +// This is needed only for the RunLoop living on the main thread because of +// how we implement timers. We sleep on `ALooper_pollAll` until the next +// timeout, but on the main thread `ALooper_pollAll` is called by the activity +// automatically, thus we cannot set the timeout. Instead we wake the loop +// with an external file descriptor event coming from this thread. +// +// Usually an actor should not carry pointers to other threads, but in +// this case the RunLoop itself owns the Alarm and calling wake() is the most +// efficient way of waking up the RunLoop and it is also thread-safe. +class Alarm { +public: + Alarm(ActorRef, RunLoop::Impl* loop_) : loop(loop_) {} + + void set(const Milliseconds& timeout) { + alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); }); + } + +private: + Timer alarm; + RunLoop::Impl* loop; +}; + +RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) { + loop = ALooper_prepare(0); + assert(loop); + + ALooper_acquire(loop); + + if (pipe(fds)) { + throw std::runtime_error("Failed to create pipe."); + } + + if (fcntl(fds[PIPE_OUT], F_SETFL, O_NONBLOCK)) { + throw std::runtime_error("Failed to set pipe read end non-blocking."); + } + + int ret = 0; + + switch (type) { + case Type::New: + ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, + ALOOPER_EVENT_INPUT, looperCallbackNew, this); + break; + case Type::Default: + ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, + ALOOPER_EVENT_INPUT, looperCallbackDefault, this); + alarm = std::make_unique>("Alarm", this); + running = true; + break; + } + + if (ret != 1) { + throw std::runtime_error("Failed to add file descriptor to Looper."); + } +} + +RunLoop::Impl::~Impl() { + alarm.reset(); + + if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) { + Log::Error(mbgl::Event::General, "Failed to remove file descriptor from Looper"); + } + + if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) { + Log::Error(mbgl::Event::General, "Failed to close file descriptor."); + } + + ALooper_release(loop); +} + +void RunLoop::Impl::wake() { + if (coalesce.test_and_set(std::memory_order_acquire)) { + return; + } + + if (write(fds[PIPE_IN], "\n", 1) == -1) { + throw std::runtime_error("Failed to write to file descriptor."); + } +} + +void RunLoop::Impl::addRunnable(Runnable* runnable) { + { + std::lock_guard lock(mutex); + runnables.push_back(runnable); + } + + wake(); +} + +void RunLoop::Impl::removeRunnable(Runnable* runnable) { + std::lock_guard lock(mutex); + runnables.remove(runnable); +} + +Milliseconds RunLoop::Impl::processRunnables() { + auto now = Clock::now(); + auto nextDue = TimePoint::max(); + std::list tmp; + { + std::lock_guard lock(mutex); + + // O(N) but in the render thread where we get tons + // of messages, the size of the list is usually 1~2. + auto it = runnables.begin(); + while (it != runnables.end()) { + Runnable* runnable = *it; + + auto const dueTime = runnable->dueTime(); + if (dueTime <= now) { + tmp.push_back(runnable); + runnables.erase(it++); + } else { + nextDue = std::min(nextDue, dueTime); + ++it; + } + } + } + + for (auto runnable : tmp) { + runnable->runTask(); + } + + if (runnables.empty() || nextDue == TimePoint::max()) { + return Milliseconds(-1); + } + + auto timeout = std::chrono::duration_cast(nextDue - now); + if (alarm) { + alarm->actor().invoke(&Alarm::set, timeout); + } + + return timeout; +} + +RunLoop* RunLoop::Get() { + assert(static_cast(Scheduler::GetCurrent())); + return static_cast(Scheduler::GetCurrent()); +} + +RunLoop::RunLoop(Type type) : impl(std::make_unique(this, type)) { + Scheduler::SetCurrent(this); +} + +RunLoop::~RunLoop() { + Scheduler::SetCurrent(nullptr); +} + +LOOP_HANDLE RunLoop::getLoopHandle() { + return Get()->impl.get(); +} + +void RunLoop::wake() { + impl->wake(); +} + +void RunLoop::run() { + MBGL_VERIFY_THREAD(tid); + + impl->running = true; + + int outFd, outEvents; + char *outData = nullptr; + + while (impl->running) { + process(); + auto timeout = impl->processRunnables().count(); + ALooper_pollAll(timeout, &outFd, &outEvents, reinterpret_cast(&outData)); + } +} + +void RunLoop::runOnce() { + MBGL_VERIFY_THREAD(tid); + + process(); + impl->processRunnables(); +} + +void RunLoop::stop() { + invoke([&] { + impl->running = false; + impl->wake(); + }); +} + +void RunLoop::addWatch(int, Event, std::function&&) { + throw std::runtime_error("Not implemented."); +} + +void RunLoop::removeWatch(int) { + throw std::runtime_error("Not implemented."); +} + +} // namespace util +} // namespace mbgl diff --git a/src/run_loop_impl.hpp b/src/run_loop_impl.hpp new file mode 100644 index 000000000..c6a1b23a7 --- /dev/null +++ b/src/run_loop_impl.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "jni.hpp" + +#include +#include + +#include +#include +#include +#include + +struct ALooper; + +namespace mbgl { +namespace util { + +template class Thread; +class Alarm; + +class RunLoop::Impl { +public: + class Runnable { + public: + virtual ~Runnable() = default; + + virtual void runTask() = 0; + virtual TimePoint dueTime() const = 0; + }; + + Impl(RunLoop*, RunLoop::Type); + ~Impl(); + + void wake(); + + void addRunnable(Runnable*); + void removeRunnable(Runnable*); + + Milliseconds processRunnables(); + + ALooper* loop = nullptr; + RunLoop* runLoop = nullptr; + std::atomic running; + std::atomic_flag coalesce = ATOMIC_FLAG_INIT; + +private: + friend RunLoop; + + int fds[2]; + + std::unique_ptr> alarm; + + std::mutex mutex; + std::list runnables; +}; + +} // namespace util +} // namespace mbgl diff --git a/src/snapshotter/map_snapshot.cpp b/src/snapshotter/map_snapshot.cpp new file mode 100644 index 000000000..1650f72dc --- /dev/null +++ b/src/snapshotter/map_snapshot.cpp @@ -0,0 +1,65 @@ +#include "map_snapshot.hpp" + +#include "../bitmap.hpp" +#include "../conversion/collection.hpp" + +#include + +namespace mbgl { +namespace android { + +MapSnapshot::MapSnapshot(float pixelRatio_, MapSnapshot::PointForFn pointForFn_, MapSnapshot::LatLngForFn latLngForFn_) + : pixelRatio(pixelRatio_) + , pointForFn(std::move(pointForFn_)) + , latLngForFn(std::move(latLngForFn_)) { +} + +MapSnapshot::~MapSnapshot() = default; + +jni::Local> MapSnapshot::pixelForLatLng(jni::JNIEnv& env, jni::Object& jLatLng) { + ScreenCoordinate point = pointForFn(LatLng::getLatLng(env, jLatLng)); + return PointF::New(env, point.x * pixelRatio, point.y * pixelRatio); +} + +jni::Local> MapSnapshot::latLngForPixel(jni::JNIEnv& env, jni::Object& jPoint) { + return LatLng::New(env, latLngForFn(PointF::getScreenCoordinate(env, jPoint))); +} + +// Static methods // + +jni::Local> MapSnapshot::New(JNIEnv& env, + PremultipliedImage&& image, + float pixelRatio, + std::vector attributions, + bool showLogo, + mbgl::MapSnapshotter::PointForFn pointForFn, + mbgl::MapSnapshotter::LatLngForFn latLngForFn) { + // Create the bitmap + auto bitmap = Bitmap::CreateBitmap(env, std::move(image)); + + // Create the Mapsnapshot peers + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::Array, jni::jboolean>(env); + auto nativePeer = std::make_unique(pixelRatio, pointForFn, latLngForFn); + return javaClass.New(env, constructor, reinterpret_cast(nativePeer.release()), bitmap, conversion::toArray(env, attributions), (jni::jboolean) showLogo); +} + +void MapSnapshot::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, + "nativePtr", + std::make_unique, + "initialize", + "finalize", + METHOD(&MapSnapshot::latLngForPixel, "latLngForPixel"), + METHOD(&MapSnapshot::pixelForLatLng, "pixelForLatLng") + ); +} + +} // namespace android +} // namespace mbgl diff --git a/src/snapshotter/map_snapshot.hpp b/src/snapshotter/map_snapshot.hpp new file mode 100644 index 000000000..6b82d0283 --- /dev/null +++ b/src/snapshotter/map_snapshot.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include + +#include "../geometry/lat_lng.hpp" +#include "../graphics/pointf.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +class MapSnapshot { +public: + + using PointForFn = mbgl::MapSnapshotter::PointForFn; + using LatLngForFn = mbgl::MapSnapshotter::LatLngForFn; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshot"; }; + + static void registerNative(jni::JNIEnv&); + + static jni::Local> New(JNIEnv& env, + PremultipliedImage&& image, + float pixelRatio, + std::vector attributions, + bool showLogo, + PointForFn pointForFn, + LatLngForFn latLngForFn); + + MapSnapshot(jni::JNIEnv&) {}; + MapSnapshot(float pixelRatio, PointForFn, LatLngForFn); + ~MapSnapshot(); + + jni::Local> pixelForLatLng(jni::JNIEnv&, jni::Object&); + jni::Local> latLngForPixel(jni::JNIEnv&, jni::Object&); + +private: + float pixelRatio; + mbgl::MapSnapshotter::PointForFn pointForFn; + mbgl::MapSnapshotter::LatLngForFn latLngForFn; +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/snapshotter/map_snapshotter.cpp b/src/snapshotter/map_snapshotter.cpp new file mode 100644 index 000000000..0b38269ad --- /dev/null +++ b/src/snapshotter/map_snapshotter.cpp @@ -0,0 +1,176 @@ +#include "map_snapshotter.hpp" + +#include +#include +#include +#include +#include + +#include "../attach_env.hpp" +#include "map_snapshot.hpp" + +namespace mbgl { +namespace android { + +MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, + const jni::Object& _obj, + const jni::Object& _jFileSource, + jni::jfloat _pixelRatio, + jni::jint width, + jni::jint height, + const jni::String& styleURL, + const jni::String& styleJSON, + const jni::Object& region, + const jni::Object& position, + jni::jboolean _showLogo, + const jni::String& _localIdeographFontFamily) + : javaPeer(_env, _obj) + , pixelRatio(_pixelRatio) { + + // Get a reference to the JavaVM for callbacks + if (_env.GetJavaVM(&vm) < 0) { + _env.ExceptionDescribe(); + return; + } + + jFileSource = FileSource::getNativePeer(_env, _jFileSource); + auto size = mbgl::Size { static_cast(width), static_cast(height) }; + + optional cameraOptions; + if (position) { + cameraOptions = CameraPosition::getCameraOptions(_env, position, pixelRatio); + } + + optional bounds; + if (region) { + bounds = LatLngBounds::getLatLngBounds(_env, region); + } + + std::pair style; + if (styleJSON) { + style = std::make_pair(true, jni::Make(_env, styleJSON)); + } else { + style = std::make_pair(false, jni::Make(_env, styleURL)); + } + + showLogo = _showLogo; + // Create the core snapshotter + snapshotter = std::make_unique(style, + size, + pixelRatio, + cameraOptions, + bounds, + _localIdeographFontFamily ? + jni::Make(_env, _localIdeographFontFamily) : + optional{}, + mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource)); +} + +MapSnapshotter::~MapSnapshotter() = default; + +void MapSnapshotter::start(JNIEnv& env) { + MBGL_VERIFY_THREAD(tid); + activateFilesource(env); + + snapshotCallback = std::make_unique>( + *Scheduler::GetCurrent(), + [this](std::exception_ptr err, PremultipliedImage image, std::vector attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn) { + MBGL_VERIFY_THREAD(tid); + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + + if (err) { + // error handler callback + static auto onSnapshotFailed = javaClass.GetMethod(*_env, "onSnapshotFailed"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotFailed, jni::Make(*_env, util::toString(err))); + } + } else { + // Create the wrapper + auto mapSnapshot = android::MapSnapshot::New(*_env, std::move(image), pixelRatio, attributions, showLogo, pointForFn, latLngForFn); + + // invoke callback + static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotReady, mapSnapshot); + } + } + + deactivateFilesource(*_env); + }); + + snapshotter->snapshot(snapshotCallback->self()); +} + +void MapSnapshotter::cancel(JNIEnv& env) { + MBGL_VERIFY_THREAD(tid); + snapshotCallback.reset(); + deactivateFilesource(env); +} + +void MapSnapshotter::setStyleUrl(JNIEnv& env, const jni::String& styleURL) { + snapshotter->setStyleURL(jni::Make(env, styleURL)); +} + +void MapSnapshotter::setStyleJson(JNIEnv& env, const jni::String& styleJSON) { + snapshotter->setStyleJSON(jni::Make(env, styleJSON)); +} + +void MapSnapshotter::setSize(JNIEnv&, jni::jint width, jni::jint height) { + auto size = mbgl::Size { static_cast(width), static_cast(height) }; + snapshotter->setSize(size); +} + +void MapSnapshotter::setCameraPosition(JNIEnv& env, const jni::Object& position) { + auto options = CameraPosition::getCameraOptions(env, position, pixelRatio); + snapshotter->setCameraOptions(options); +} + +void MapSnapshotter::setRegion(JNIEnv& env, const jni::Object& region) { + snapshotter->setRegion(LatLngBounds::getLatLngBounds(env, region)); +} + + +// Private methods // + +void MapSnapshotter::activateFilesource(JNIEnv& env) { + if (!activatedFilesource) { + activatedFilesource = true; + jFileSource->resume(env); + } +} + +void MapSnapshotter::deactivateFilesource(JNIEnv& env) { + if (activatedFilesource) { + activatedFilesource = false; + jFileSource->pause(env); + } +} + +// Static methods // + +void MapSnapshotter::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + jni::MakePeer&, const jni::Object&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object&, const jni::Object&, jni::jboolean, const jni::String&>, + "nativeInitialize", + "finalize", + METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"), + METHOD(&MapSnapshotter::setStyleJson, "setStyleJson"), + METHOD(&MapSnapshotter::setSize, "setSize"), + METHOD(&MapSnapshotter::setCameraPosition, "setCameraPosition"), + METHOD(&MapSnapshotter::setRegion, "setRegion"), + METHOD(&MapSnapshotter::start, "nativeStart"), + METHOD(&MapSnapshotter::cancel, "nativeCancel") + ); +} + +} // namespace android +} // namespace mbgl diff --git a/src/snapshotter/map_snapshotter.hpp b/src/snapshotter/map_snapshotter.hpp new file mode 100644 index 000000000..608a4c855 --- /dev/null +++ b/src/snapshotter/map_snapshotter.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +#include "../file_source.hpp" +#include "../geometry/lat_lng_bounds.hpp" +#include "../map/camera_position.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + +class SnapshotterRendererFrontend; + +class MapSnapshotter { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshotter"; }; + + static void registerNative(jni::JNIEnv&); + + MapSnapshotter(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + jni::jfloat pixelRatio, + jni::jint width, + jni::jint height, + const jni::String& styleURL, + const jni::String& styleJSON, + const jni::Object& region, + const jni::Object& position, + jni::jboolean showLogo, + const jni::String& localIdeographFontFamily); + + ~MapSnapshotter(); + + void setStyleUrl(JNIEnv&, const jni::String& styleURL); + + void setStyleJson(JNIEnv&, const jni::String& styleJSON); + + void setSize(JNIEnv&, jni::jint width, jni::jint height); + + void setCameraPosition(JNIEnv&, const jni::Object& position); + + void setRegion(JNIEnv&, const jni::Object& region); + + void start(JNIEnv&); + + void cancel(JNIEnv&); + +private: + MBGL_STORE_THREAD(tid); + + JavaVM *vm = nullptr; + jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; + + float pixelRatio; + bool showLogo; + + std::unique_ptr> snapshotCallback; + std::unique_ptr snapshotter; + + FileSource *jFileSource; + void activateFilesource(JNIEnv&); + void deactivateFilesource(JNIEnv&); + bool activatedFilesource = false; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/string_util.cpp b/src/string_util.cpp new file mode 100644 index 000000000..f02155caf --- /dev/null +++ b/src/string_util.cpp @@ -0,0 +1,25 @@ +#include +#include "attach_env.hpp" +#include + +namespace mbgl { +namespace platform { + +std::string uppercase(const std::string& str) { + auto env{ android::AttachEnv() }; + jni::Local value = jni::Make(*env, str.c_str()); + static auto toUpperCase = jni::Class::Singleton(*env).GetMethod(*env, "toUpperCase"); + auto result = value.Call(*env, toUpperCase); + return jni::Make(*env, result); +} + +std::string lowercase(const std::string& str) { + auto env{ android::AttachEnv() }; + jni::Local value = jni::Make(*env, str.c_str()); + static auto toLowerCase = jni::Class::Singleton(*env).GetMethod(*env, "toLowerCase"); + auto result = value.Call(*env, toLowerCase); + return jni::Make(*env, result); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/style/android_conversion.hpp b/src/style/android_conversion.hpp new file mode 100644 index 000000000..dc0a0acb3 --- /dev/null +++ b/src/style/android_conversion.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include "value.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +class ConversionTraits { +public: + static bool isUndefined(const mbgl::android::Value& value) { + return value.isNull(); + } + + static bool isArray(const mbgl::android::Value& value) { + return value.isArray(); + } + + static bool isObject(const mbgl::android::Value& value) { + return value.isObject(); + } + + static std::size_t arrayLength(const mbgl::android::Value& value) { + return value.getLength();; + } + + static mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { + return value.get(i); + } + + static optional objectMember(const mbgl::android::Value& value, const char* key) { + mbgl::android::Value member = value.get(key); + if (!member.isNull()) { + return member; + } else { + return {}; + } + } + + template + static optional eachMember(const mbgl::android::Value& value, Fn&& fn) { + assert(value.isObject()); + mbgl::android::Value keys = value.keyArray(); + std::size_t length = arrayLength(keys); + for(std::size_t i = 0; i < length; ++i){ + const auto k = keys.get(i).toString(); + auto v = value.get(k.c_str()); + optional result = fn(k, std::move(v)); + if (result) { + return result; + } + } + return {}; + } + + static optional toBool(const mbgl::android::Value& value) { + if (value.isBool()) { + return value.toBool(); + } else { + return {}; + } + } + + static optional toNumber(const mbgl::android::Value& value) { + if (value.isNumber()) { + auto num = value.toFloat(); + return num; + } else { + return {}; + } + } + + static optional toDouble(const mbgl::android::Value& value) { + if (value.isNumber()) { + return value.toDouble(); + } else { + return {}; + } + } + + static optional toString(const mbgl::android::Value& value) { + if (value.isString()) { + return value.toString(); + } else { + return {}; + } + } + + static optional toValue(const mbgl::android::Value& value) { + if (value.isNull()) { + return {}; + } else if (value.isBool()) { + return { value.toBool() }; + } else if (value.isString()) { + return { value.toString() }; + } else if (value.isNumber()) { + return { value.toDouble() }; + } else { + return {}; + } + } + + static optional toGeoJSON(const mbgl::android::Value &value, Error &error) { + if (value.isNull() || !value.isString()) { + error = { "no json data found" }; + return {}; + } + return parseGeoJSON(value.toString(), error); + } +}; + +template +optional convert(mbgl::android::Value&& value, Error& error, Args&&...args) { + return convert(Convertible(std::move(value)), error, std::forward(args)...); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/style/conversion/filter.cpp b/src/style/conversion/filter.cpp new file mode 100644 index 000000000..d15e2747a --- /dev/null +++ b/src/style/conversion/filter.cpp @@ -0,0 +1,26 @@ +#include "filter.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +optional toFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { + mbgl::optional filter; + if (jfilter) { + mbgl::style::conversion::Error error; + auto converted = mbgl::style::conversion::convert(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); + } + filter = std::move(*converted); + } + return filter; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/src/style/conversion/filter.hpp b/src/style/conversion/filter.hpp new file mode 100644 index 000000000..920d336a1 --- /dev/null +++ b/src/style/conversion/filter.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +optional toFilter(jni::JNIEnv&, const jni::Array>&); + +} // namespace conversion +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/conversion/position.cpp b/src/style/conversion/position.cpp new file mode 100644 index 000000000..e3c334afd --- /dev/null +++ b/src/style/conversion/position.cpp @@ -0,0 +1,24 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, mbgl::style::Position>::operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { + std::array cartPosition = value.getSpherical(); + return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); +} + +Result Converter>::operator()(jni::JNIEnv &env, const jni::Object &value) const { + float radialCoordinate = Position::getRadialCoordinate(env, value); + float azimuthalAngle = Position::getAzimuthalAngle(env, value); + float polarAngle = Position::getPolarAngle(env, value); + std::array cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; + mbgl::style::Position position{}; + position.set(cartPosition); + return position; +} + +} +} +} diff --git a/src/style/conversion/position.hpp b/src/style/conversion/position.hpp new file mode 100644 index 000000000..90409d527 --- /dev/null +++ b/src/style/conversion/position.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../position.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter>, mbgl::style::Position> { + Result>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const; +}; + +template <> +struct Converter> { + Result operator()(jni::JNIEnv &env, const jni::Object &value) const; +}; + +} +} +} diff --git a/src/style/conversion/property_expression.hpp b/src/style/conversion/property_expression.hpp new file mode 100644 index 000000000..4e26b11f9 --- /dev/null +++ b/src/style/conversion/property_expression.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../../gson/json_element.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template +struct Converter>, mbgl::style::PropertyExpression> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyExpression& value) const { + return gson::JsonElement::New(env, value.getExpression().serialize()); + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/src/style/conversion/property_value.hpp b/src/style/conversion/property_value.hpp new file mode 100644 index 000000000..317705a28 --- /dev/null +++ b/src/style/conversion/property_value.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include + +#include "../../conversion/conversion.hpp" +#include "../../conversion/constant.hpp" +#include "property_expression.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Conversion from core property value types to Java property value types + */ +template +class PropertyValueEvaluator { +public: + PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {} + + jni::Local> operator()(const mbgl::style::Undefined) const { + return jni::Local>(env, nullptr); + } + + jni::Local> operator()(const T& value) const { + return std::move(*convert>>(env, value)); + } + + jni::Local> operator()(const mbgl::style::PropertyExpression& value) const { + return std::move(*convert>>(env, value)); + } + +private: + jni::JNIEnv& env; +}; + +/** + * Convert core property values to java + */ +template +struct Converter>, mbgl::style::PropertyValue> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue& value) const { + PropertyValueEvaluator evaluator(env); + return value.evaluate(evaluator); + } +}; + +/** + * Convert core heat map color property value to java + */ +template <> +struct Converter>, mbgl::style::ColorRampPropertyValue> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue& value) const { + PropertyValueEvaluator evaluator(env); + return std::move(*convert>>(env, value.evaluate(evaluator))); + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/src/style/conversion/transition_options.cpp b/src/style/conversion/transition_options.cpp new file mode 100644 index 000000000..75d9b4cc0 --- /dev/null +++ b/src/style/conversion/transition_options.cpp @@ -0,0 +1,17 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, mbgl::style::TransitionOptions>::operator()(jni::JNIEnv& env, const mbgl::style::TransitionOptions& value) const { + return TransitionOptions::fromTransitionOptions(env, + std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())).count(), + std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())).count(), + (jboolean) value.enablePlacementTransitions + ); +} + +} +} +} diff --git a/src/style/conversion/transition_options.hpp b/src/style/conversion/transition_options.hpp new file mode 100644 index 000000000..06c042922 --- /dev/null +++ b/src/style/conversion/transition_options.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../transition_options.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template<> +struct Converter>, mbgl::style::TransitionOptions> { + Result>> operator()(jni::JNIEnv&, const mbgl::style::TransitionOptions&) const; +}; + +} +} +} diff --git a/src/style/conversion/url_or_tileset.cpp b/src/style/conversion/url_or_tileset.cpp new file mode 100644 index 000000000..2ec585675 --- /dev/null +++ b/src/style/conversion/url_or_tileset.cpp @@ -0,0 +1,30 @@ +#include "url_or_tileset.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +// This conversion is expected not to fail because it's used only in contexts where +// the value was originally a String or TileSet object on the Java side. If it fails +// to convert, it's a bug in our serialization or Java-side static typing. +variant convertURLOrTileset(mbgl::android::Value&& value) { + using namespace mbgl::style::conversion; + + const Convertible convertible(std::move(value)); + if (isObject(convertible)) { + Error error; + optional tileset = convert(convertible, error); + if (!tileset) { + throw std::logic_error(error.message); + } + return { *tileset }; + } else { + return { *toString(convertible) }; + } +} + +} +} diff --git a/src/style/conversion/url_or_tileset.hpp b/src/style/conversion/url_or_tileset.hpp new file mode 100644 index 000000000..f42a9b9a2 --- /dev/null +++ b/src/style/conversion/url_or_tileset.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +#include "../value.hpp" + +namespace mbgl { +namespace android { + +variant convertURLOrTileset(mbgl::android::Value&& value); + +} +} diff --git a/src/style/formatted.cpp b/src/style/formatted.cpp new file mode 100644 index 000000000..69c3454e2 --- /dev/null +++ b/src/style/formatted.cpp @@ -0,0 +1,54 @@ +#include "formatted.hpp" +#include "formatted_section.hpp" +#include "../conversion/conversion.hpp" +#include "../conversion/constant.hpp" + +namespace mbgl { +namespace android { + +void Formatted::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Formatted::New(jni::JNIEnv& env, const style::expression::Formatted& value) { + static auto& formatted = jni::Class::Singleton(env); + static auto formattedConstructor = formatted.GetConstructor>>(env); + static auto& formattedSectionClass = jni::Class::Singleton(env); + + auto sections = jni::Array>::New(env, value.sections.size()); + for (std::size_t i = 0; i < value.sections.size(); i++) { + auto section = value.sections.at(i); + auto text = jni::Make(env, section.text); + static auto formattedSectionConstructor = formattedSectionClass.GetConstructor(env); + auto formattedSection = formattedSectionClass.New(env, formattedSectionConstructor, text); + + if (section.fontScale) { + double fontScale = section.fontScale.value(); + static auto method = formattedSectionClass.GetMethod(env, "setFontScale"); + formattedSection.Call(env, method, jni::Box(env, fontScale)); + } + + if (section.fontStack) { + auto fontStack = jni::Array::New(env, section.fontStack.value().size()); + for (std::size_t j = 0; j < section.fontStack.value().size(); j++) { + fontStack.Set(env, j, jni::Make(env, section.fontStack.value().at(j))); + } + static auto method = formattedSectionClass.GetMethod)>(env, "setFontStack"); + formattedSection.Call(env, method, fontStack); + } + + if (section.textColor) { + using namespace mbgl::android::conversion; + auto textColor = std::move(*convert>>(env, *section.textColor)); + static auto method = formattedSectionClass.GetMethod)>(env, "setTextColor"); + formattedSection.Call(env, method, textColor); + } + + sections.Set(env, i, formattedSection); + } + + return formatted.New(env, formattedConstructor, sections); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted.hpp b/src/style/formatted.hpp new file mode 100644 index 000000000..ca91f6562 --- /dev/null +++ b/src/style/formatted.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { + namespace android { + + using SuperTag = jni::ObjectTag; + class Formatted : private mbgl::util::noncopyable { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/Formatted"; }; + + static jni::Local> + New(jni::JNIEnv&, const style::expression::Formatted &value); + + static void registerNative(jni::JNIEnv &); + }; + + } // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted_section.cpp b/src/style/formatted_section.cpp new file mode 100644 index 000000000..ddcf76f81 --- /dev/null +++ b/src/style/formatted_section.cpp @@ -0,0 +1,11 @@ +#include "formatted_section.hpp" + +namespace mbgl { +namespace android { + +void FormattedSection::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted_section.hpp b/src/style/formatted_section.hpp new file mode 100644 index 000000000..f759a94e8 --- /dev/null +++ b/src/style/formatted_section.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class FormattedSection : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/FormattedSection"; }; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/layers/background_layer.cpp b/src/style/layers/background_layer.cpp new file mode 100644 index 000000000..e28fd0798 --- /dev/null +++ b/src/style/layers/background_layer.cpp @@ -0,0 +1,145 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "background_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::BackgroundLayer& toBackgroundLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String& layerId) + : Layer(std::make_unique(jni::Make(env, layerId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + BackgroundLayer::BackgroundLayer(mbgl::Map& map, mbgl::style::BackgroundLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + BackgroundLayer::BackgroundLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + BackgroundLayer::~BackgroundLayer() = default; + + // Property getters + + jni::Local> BackgroundLayer::getBackgroundColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundColor())); + } + + jni::Local> BackgroundLayer::getBackgroundColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundColorTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundColorTransition(options); + } + + jni::Local> BackgroundLayer::getBackgroundPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundPattern())); + } + + jni::Local> BackgroundLayer::getBackgroundPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundPatternTransition(options); + } + + jni::Local> BackgroundLayer::getBackgroundOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundOpacity())); + } + + jni::Local> BackgroundLayer::getBackgroundOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundOpacityTransition(options); + } + + + // BackgroundJavaLayerPeerFactory + + BackgroundJavaLayerPeerFactory::~BackgroundJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new BackgroundLayer(map, toBackgroundLayer(layer))); + } + + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new BackgroundLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void BackgroundJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&BackgroundLayer::getBackgroundColorTransition, "nativeGetBackgroundColorTransition"), + METHOD(&BackgroundLayer::setBackgroundColorTransition, "nativeSetBackgroundColorTransition"), + METHOD(&BackgroundLayer::getBackgroundColor, "nativeGetBackgroundColor"), + METHOD(&BackgroundLayer::getBackgroundPatternTransition, "nativeGetBackgroundPatternTransition"), + METHOD(&BackgroundLayer::setBackgroundPatternTransition, "nativeSetBackgroundPatternTransition"), + METHOD(&BackgroundLayer::getBackgroundPattern, "nativeGetBackgroundPattern"), + METHOD(&BackgroundLayer::getBackgroundOpacityTransition, "nativeGetBackgroundOpacityTransition"), + METHOD(&BackgroundLayer::setBackgroundOpacityTransition, "nativeSetBackgroundOpacityTransition"), + METHOD(&BackgroundLayer::getBackgroundOpacity, "nativeGetBackgroundOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/background_layer.hpp b/src/style/layers/background_layer.hpp new file mode 100644 index 000000000..654031c6f --- /dev/null +++ b/src/style/layers/background_layer.hpp @@ -0,0 +1,58 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class BackgroundLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/BackgroundLayer"; }; + + BackgroundLayer(jni::JNIEnv&, jni::String&); + + BackgroundLayer(mbgl::Map&, mbgl::style::BackgroundLayer&); + + BackgroundLayer(mbgl::Map&, std::unique_ptr); + + ~BackgroundLayer(); + + // Properties + + jni::Local> getBackgroundColor(jni::JNIEnv&); + void setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundColorTransition(jni::JNIEnv&); + + jni::Local> getBackgroundPattern(jni::JNIEnv&); + void setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundPatternTransition(jni::JNIEnv&); + + jni::Local> getBackgroundOpacity(jni::JNIEnv&); + void setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundOpacityTransition(jni::JNIEnv&); + +}; // class BackgroundLayer + +class BackgroundJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::BackgroundLayerFactory { +public: + ~BackgroundJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class BackgroundJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/circle_layer.cpp b/src/style/layers/circle_layer.cpp new file mode 100644 index 000000000..f460031dc --- /dev/null +++ b/src/style/layers/circle_layer.cpp @@ -0,0 +1,268 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "circle_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::CircleLayer& toCircleLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + CircleLayer::CircleLayer(mbgl::Map& map, mbgl::style::CircleLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + CircleLayer::CircleLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + CircleLayer::~CircleLayer() = default; + + // Property getters + + jni::Local> CircleLayer::getCircleRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleRadius())); + } + + jni::Local> CircleLayer::getCircleRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleRadiusTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleRadiusTransition(options); + } + + jni::Local> CircleLayer::getCircleColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleColor())); + } + + jni::Local> CircleLayer::getCircleColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleColorTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleColorTransition(options); + } + + jni::Local> CircleLayer::getCircleBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleBlur())); + } + + jni::Local> CircleLayer::getCircleBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleBlurTransition(options); + } + + jni::Local> CircleLayer::getCircleOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleOpacity())); + } + + jni::Local> CircleLayer::getCircleOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleOpacityTransition(options); + } + + jni::Local> CircleLayer::getCircleTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslate())); + } + + jni::Local> CircleLayer::getCircleTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleTranslateTransition(options); + } + + jni::Local> CircleLayer::getCircleTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslateAnchor())); + } + + jni::Local> CircleLayer::getCirclePitchScale(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchScale())); + } + + jni::Local> CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchAlignment())); + } + + jni::Local> CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeWidth())); + } + + jni::Local> CircleLayer::getCircleStrokeWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeWidthTransition(options); + } + + jni::Local> CircleLayer::getCircleStrokeColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeColor())); + } + + jni::Local> CircleLayer::getCircleStrokeColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeColorTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeColorTransition(options); + } + + jni::Local> CircleLayer::getCircleStrokeOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeOpacity())); + } + + jni::Local> CircleLayer::getCircleStrokeOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeOpacityTransition(options); + } + + + // CircleJavaLayerPeerFactory + + CircleJavaLayerPeerFactory::~CircleJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new CircleLayer(map, toCircleLayer(layer))); + } + + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new CircleLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void CircleJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&CircleLayer::getCircleRadiusTransition, "nativeGetCircleRadiusTransition"), + METHOD(&CircleLayer::setCircleRadiusTransition, "nativeSetCircleRadiusTransition"), + METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"), + METHOD(&CircleLayer::getCircleColorTransition, "nativeGetCircleColorTransition"), + METHOD(&CircleLayer::setCircleColorTransition, "nativeSetCircleColorTransition"), + METHOD(&CircleLayer::getCircleColor, "nativeGetCircleColor"), + METHOD(&CircleLayer::getCircleBlurTransition, "nativeGetCircleBlurTransition"), + METHOD(&CircleLayer::setCircleBlurTransition, "nativeSetCircleBlurTransition"), + METHOD(&CircleLayer::getCircleBlur, "nativeGetCircleBlur"), + METHOD(&CircleLayer::getCircleOpacityTransition, "nativeGetCircleOpacityTransition"), + METHOD(&CircleLayer::setCircleOpacityTransition, "nativeSetCircleOpacityTransition"), + METHOD(&CircleLayer::getCircleOpacity, "nativeGetCircleOpacity"), + METHOD(&CircleLayer::getCircleTranslateTransition, "nativeGetCircleTranslateTransition"), + METHOD(&CircleLayer::setCircleTranslateTransition, "nativeSetCircleTranslateTransition"), + METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"), + METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"), + METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"), + METHOD(&CircleLayer::getCirclePitchAlignment, "nativeGetCirclePitchAlignment"), + METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"), + METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"), + METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"), + METHOD(&CircleLayer::getCircleStrokeColorTransition, "nativeGetCircleStrokeColorTransition"), + METHOD(&CircleLayer::setCircleStrokeColorTransition, "nativeSetCircleStrokeColorTransition"), + METHOD(&CircleLayer::getCircleStrokeColor, "nativeGetCircleStrokeColor"), + METHOD(&CircleLayer::getCircleStrokeOpacityTransition, "nativeGetCircleStrokeOpacityTransition"), + METHOD(&CircleLayer::setCircleStrokeOpacityTransition, "nativeSetCircleStrokeOpacityTransition"), + METHOD(&CircleLayer::getCircleStrokeOpacity, "nativeGetCircleStrokeOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/circle_layer.hpp b/src/style/layers/circle_layer.hpp new file mode 100644 index 000000000..191b3924f --- /dev/null +++ b/src/style/layers/circle_layer.hpp @@ -0,0 +1,84 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class CircleLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CircleLayer"; }; + + CircleLayer(jni::JNIEnv&, jni::String&, jni::String&); + + CircleLayer(mbgl::Map&, mbgl::style::CircleLayer&); + + CircleLayer(mbgl::Map&, std::unique_ptr); + + ~CircleLayer(); + + // Properties + + jni::Local> getCircleRadius(jni::JNIEnv&); + void setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleRadiusTransition(jni::JNIEnv&); + + jni::Local> getCircleColor(jni::JNIEnv&); + void setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleColorTransition(jni::JNIEnv&); + + jni::Local> getCircleBlur(jni::JNIEnv&); + void setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleBlurTransition(jni::JNIEnv&); + + jni::Local> getCircleOpacity(jni::JNIEnv&); + void setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleOpacityTransition(jni::JNIEnv&); + + jni::Local> getCircleTranslate(jni::JNIEnv&); + void setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleTranslateTransition(jni::JNIEnv&); + + jni::Local> getCircleTranslateAnchor(jni::JNIEnv&); + + jni::Local> getCirclePitchScale(jni::JNIEnv&); + + jni::Local> getCirclePitchAlignment(jni::JNIEnv&); + + jni::Local> getCircleStrokeWidth(jni::JNIEnv&); + void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeWidthTransition(jni::JNIEnv&); + + jni::Local> getCircleStrokeColor(jni::JNIEnv&); + void setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeColorTransition(jni::JNIEnv&); + + jni::Local> getCircleStrokeOpacity(jni::JNIEnv&); + void setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeOpacityTransition(jni::JNIEnv&); + +}; // class CircleLayer + +class CircleJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CircleLayerFactory { +public: + ~CircleJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class CircleJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/custom_layer.cpp b/src/style/layers/custom_layer.cpp new file mode 100644 index 000000000..3f44aa850 --- /dev/null +++ b/src/style/layers/custom_layer.cpp @@ -0,0 +1,70 @@ +#include "custom_layer.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + CustomLayer::CustomLayer(jni::JNIEnv& env, const jni::String& layerId, jni::jlong host) + : Layer(std::make_unique( + jni::Make(env, layerId), + std::unique_ptr(reinterpret_cast(host))) + ) { + } + + CustomLayer::CustomLayer(mbgl::Map& map, mbgl::style::CustomLayer& coreLayer) + : Layer(map, coreLayer) { + } + + CustomLayer::CustomLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + CustomLayer::~CustomLayer() = default; + + void CustomLayer::update(jni::JNIEnv&) { + Log::Debug(mbgl::Event::JNI, "Updating map"); + if (map) { + map->triggerRepaint(); + } else { + Log::Error(mbgl::Event::JNI, "No map reference, cannot update"); + } + } + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } + + CustomJavaLayerPeerFactory::~CustomJavaLayerPeerFactory() = default; + + jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + return createJavaPeer(env, new CustomLayer(map, static_cast(layer))); + } + + jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + return createJavaPeer(env, new CustomLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void CustomJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&CustomLayer::update, "nativeUpdate")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/custom_layer.hpp b/src/style/layers/custom_layer.hpp new file mode 100644 index 000000000..0d6f4a408 --- /dev/null +++ b/src/style/layers/custom_layer.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "layer.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class CustomLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CustomLayer"; }; + + static void registerNative(jni::JNIEnv&); + + CustomLayer(jni::JNIEnv&, const jni::String&, jni::jlong); + CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&); + CustomLayer(mbgl::Map&, std::unique_ptr); + ~CustomLayer(); + + void update(jni::JNIEnv&); + + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class CustomLayer + +class CustomJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CustomLayerFactory { +public: + ~CustomJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class CustomJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/fill_extrusion_layer.cpp b/src/style/layers/fill_extrusion_layer.cpp new file mode 100644 index 000000000..ddfbd7154 --- /dev/null +++ b/src/style/layers/fill_extrusion_layer.cpp @@ -0,0 +1,220 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "fill_extrusion_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::FillExtrusionLayer& toFillExtrusionLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + FillExtrusionLayer::FillExtrusionLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, mbgl::style::FillExtrusionLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + FillExtrusionLayer::~FillExtrusionLayer() = default; + + // Property getters + + jni::Local> FillExtrusionLayer::getFillExtrusionOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionOpacity())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionOpacityTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionColor())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionColorTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslate())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionTranslateTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslateAnchor())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionPattern())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionPatternTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionHeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionHeight())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionHeightTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionHeightTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionHeightTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionBase(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionBase())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionBaseTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionBaseTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionBaseTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionVerticalGradient(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionVerticalGradient())); + } + + + // FillExtrusionJavaLayerPeerFactory + + FillExtrusionJavaLayerPeerFactory::~FillExtrusionJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillExtrusionLayer(map, toFillExtrusionLayer(layer))); + } + + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillExtrusionLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void FillExtrusionJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FillExtrusionLayer::getFillExtrusionOpacityTransition, "nativeGetFillExtrusionOpacityTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionOpacityTransition, "nativeSetFillExtrusionOpacityTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionOpacity, "nativeGetFillExtrusionOpacity"), + METHOD(&FillExtrusionLayer::getFillExtrusionColorTransition, "nativeGetFillExtrusionColorTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionColorTransition, "nativeSetFillExtrusionColorTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionColor, "nativeGetFillExtrusionColor"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, "nativeGetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, "nativeSetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslate, "nativeGetFillExtrusionTranslate"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslateAnchor, "nativeGetFillExtrusionTranslateAnchor"), + METHOD(&FillExtrusionLayer::getFillExtrusionPatternTransition, "nativeGetFillExtrusionPatternTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionPatternTransition, "nativeSetFillExtrusionPatternTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionPattern, "nativeGetFillExtrusionPattern"), + METHOD(&FillExtrusionLayer::getFillExtrusionHeightTransition, "nativeGetFillExtrusionHeightTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionHeightTransition, "nativeSetFillExtrusionHeightTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionHeight, "nativeGetFillExtrusionHeight"), + METHOD(&FillExtrusionLayer::getFillExtrusionBaseTransition, "nativeGetFillExtrusionBaseTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionBaseTransition, "nativeSetFillExtrusionBaseTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionBase, "nativeGetFillExtrusionBase"), + METHOD(&FillExtrusionLayer::getFillExtrusionVerticalGradient, "nativeGetFillExtrusionVerticalGradient")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/fill_extrusion_layer.hpp b/src/style/layers/fill_extrusion_layer.hpp new file mode 100644 index 000000000..15dad67b0 --- /dev/null +++ b/src/style/layers/fill_extrusion_layer.hpp @@ -0,0 +1,74 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class FillExtrusionLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer"; }; + + FillExtrusionLayer(jni::JNIEnv&, jni::String&, jni::String&); + + FillExtrusionLayer(mbgl::Map&, mbgl::style::FillExtrusionLayer&); + + FillExtrusionLayer(mbgl::Map&, std::unique_ptr); + + ~FillExtrusionLayer(); + + // Properties + + jni::Local> getFillExtrusionOpacity(jni::JNIEnv&); + void setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionOpacityTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionColor(jni::JNIEnv&); + void setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionColorTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionTranslate(jni::JNIEnv&); + void setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionTranslateTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionTranslateAnchor(jni::JNIEnv&); + + jni::Local> getFillExtrusionPattern(jni::JNIEnv&); + void setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionPatternTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionHeight(jni::JNIEnv&); + void setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionHeightTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionBase(jni::JNIEnv&); + void setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionBaseTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionVerticalGradient(jni::JNIEnv&); + +}; // class FillExtrusionLayer + +class FillExtrusionJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillExtrusionLayerFactory { +public: + ~FillExtrusionJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class FillExtrusionJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/fill_layer.cpp b/src/style/layers/fill_layer.cpp new file mode 100644 index 000000000..c54f4cd39 --- /dev/null +++ b/src/style/layers/fill_layer.cpp @@ -0,0 +1,199 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "fill_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::FillLayer& toFillLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + FillLayer::FillLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + FillLayer::FillLayer(mbgl::Map& map, mbgl::style::FillLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + FillLayer::FillLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + FillLayer::~FillLayer() = default; + + // Property getters + + jni::Local> FillLayer::getFillAntialias(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillAntialias())); + } + + jni::Local> FillLayer::getFillOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillOpacity())); + } + + jni::Local> FillLayer::getFillOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillOpacityTransition(options); + } + + jni::Local> FillLayer::getFillColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillColor())); + } + + jni::Local> FillLayer::getFillColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillColorTransition(options); + } + + jni::Local> FillLayer::getFillOutlineColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillOutlineColor())); + } + + jni::Local> FillLayer::getFillOutlineColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOutlineColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillOutlineColorTransition(options); + } + + jni::Local> FillLayer::getFillTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillTranslate())); + } + + jni::Local> FillLayer::getFillTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillTranslateTransition(options); + } + + jni::Local> FillLayer::getFillTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillTranslateAnchor())); + } + + jni::Local> FillLayer::getFillPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillPattern())); + } + + jni::Local> FillLayer::getFillPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillPatternTransition(options); + } + + + // FillJavaLayerPeerFactory + + FillJavaLayerPeerFactory::~FillJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillLayer(map, toFillLayer(layer))); + } + + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void FillJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FillLayer::getFillAntialias, "nativeGetFillAntialias"), + METHOD(&FillLayer::getFillOpacityTransition, "nativeGetFillOpacityTransition"), + METHOD(&FillLayer::setFillOpacityTransition, "nativeSetFillOpacityTransition"), + METHOD(&FillLayer::getFillOpacity, "nativeGetFillOpacity"), + METHOD(&FillLayer::getFillColorTransition, "nativeGetFillColorTransition"), + METHOD(&FillLayer::setFillColorTransition, "nativeSetFillColorTransition"), + METHOD(&FillLayer::getFillColor, "nativeGetFillColor"), + METHOD(&FillLayer::getFillOutlineColorTransition, "nativeGetFillOutlineColorTransition"), + METHOD(&FillLayer::setFillOutlineColorTransition, "nativeSetFillOutlineColorTransition"), + METHOD(&FillLayer::getFillOutlineColor, "nativeGetFillOutlineColor"), + METHOD(&FillLayer::getFillTranslateTransition, "nativeGetFillTranslateTransition"), + METHOD(&FillLayer::setFillTranslateTransition, "nativeSetFillTranslateTransition"), + METHOD(&FillLayer::getFillTranslate, "nativeGetFillTranslate"), + METHOD(&FillLayer::getFillTranslateAnchor, "nativeGetFillTranslateAnchor"), + METHOD(&FillLayer::getFillPatternTransition, "nativeGetFillPatternTransition"), + METHOD(&FillLayer::setFillPatternTransition, "nativeSetFillPatternTransition"), + METHOD(&FillLayer::getFillPattern, "nativeGetFillPattern")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/fill_layer.hpp b/src/style/layers/fill_layer.hpp new file mode 100644 index 000000000..b021ddca1 --- /dev/null +++ b/src/style/layers/fill_layer.hpp @@ -0,0 +1,70 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class FillLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillLayer"; }; + + FillLayer(jni::JNIEnv&, jni::String&, jni::String&); + + FillLayer(mbgl::Map&, mbgl::style::FillLayer&); + + FillLayer(mbgl::Map&, std::unique_ptr); + + ~FillLayer(); + + // Properties + + jni::Local> getFillAntialias(jni::JNIEnv&); + + jni::Local> getFillOpacity(jni::JNIEnv&); + void setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillOpacityTransition(jni::JNIEnv&); + + jni::Local> getFillColor(jni::JNIEnv&); + void setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillColorTransition(jni::JNIEnv&); + + jni::Local> getFillOutlineColor(jni::JNIEnv&); + void setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillOutlineColorTransition(jni::JNIEnv&); + + jni::Local> getFillTranslate(jni::JNIEnv&); + void setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillTranslateTransition(jni::JNIEnv&); + + jni::Local> getFillTranslateAnchor(jni::JNIEnv&); + + jni::Local> getFillPattern(jni::JNIEnv&); + void setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillPatternTransition(jni::JNIEnv&); + +}; // class FillLayer + +class FillJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillLayerFactory { +public: + ~FillJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class FillJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/heatmap_layer.cpp b/src/style/layers/heatmap_layer.cpp new file mode 100644 index 000000000..509ab5d70 --- /dev/null +++ b/src/style/layers/heatmap_layer.cpp @@ -0,0 +1,161 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "heatmap_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::HeatmapLayer& toHeatmapLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HeatmapLayer::HeatmapLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HeatmapLayer::HeatmapLayer(mbgl::Map& map, mbgl::style::HeatmapLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HeatmapLayer::HeatmapLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + HeatmapLayer::~HeatmapLayer() = default; + + // Property getters + + jni::Local> HeatmapLayer::getHeatmapRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapRadius())); + } + + jni::Local> HeatmapLayer::getHeatmapRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapRadiusTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapRadiusTransition(options); + } + + jni::Local> HeatmapLayer::getHeatmapWeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapWeight())); + } + + jni::Local> HeatmapLayer::getHeatmapIntensity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapIntensity())); + } + + jni::Local> HeatmapLayer::getHeatmapIntensityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapIntensityTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapIntensityTransition(options); + } + + jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = toHeatmapLayer(layer).getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = toHeatmapLayer(layer).getDefaultHeatmapColor(); + } + return std::move(*convert>>(env, propertyValue)); + } + + jni::Local> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapOpacity())); + } + + jni::Local> HeatmapLayer::getHeatmapOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapOpacityTransition(options); + } + + + // HeatmapJavaLayerPeerFactory + + HeatmapJavaLayerPeerFactory::~HeatmapJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HeatmapLayer(map, toHeatmapLayer(layer))); + } + + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HeatmapLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void HeatmapJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&HeatmapLayer::getHeatmapRadiusTransition, "nativeGetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::setHeatmapRadiusTransition, "nativeSetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::getHeatmapRadius, "nativeGetHeatmapRadius"), + METHOD(&HeatmapLayer::getHeatmapWeight, "nativeGetHeatmapWeight"), + METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), + METHOD(&HeatmapLayer::getHeatmapColor, "nativeGetHeatmapColor"), + METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/heatmap_layer.hpp b/src/style/layers/heatmap_layer.hpp new file mode 100644 index 000000000..9e3db0c89 --- /dev/null +++ b/src/style/layers/heatmap_layer.hpp @@ -0,0 +1,62 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class HeatmapLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HeatmapLayer"; }; + + HeatmapLayer(jni::JNIEnv&, jni::String&, jni::String&); + + HeatmapLayer(mbgl::Map&, mbgl::style::HeatmapLayer&); + + HeatmapLayer(mbgl::Map&, std::unique_ptr); + + ~HeatmapLayer(); + + // Properties + + jni::Local> getHeatmapRadius(jni::JNIEnv&); + void setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapRadiusTransition(jni::JNIEnv&); + + jni::Local> getHeatmapWeight(jni::JNIEnv&); + + jni::Local> getHeatmapIntensity(jni::JNIEnv&); + void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapIntensityTransition(jni::JNIEnv&); + + jni::Local> getHeatmapColor(jni::JNIEnv&); + + jni::Local> getHeatmapOpacity(jni::JNIEnv&); + void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapOpacityTransition(jni::JNIEnv&); + +}; // class HeatmapLayer + +class HeatmapJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HeatmapLayerFactory { +public: + ~HeatmapJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class HeatmapJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/hillshade_layer.cpp b/src/style/layers/hillshade_layer.cpp new file mode 100644 index 000000000..bc25f666a --- /dev/null +++ b/src/style/layers/hillshade_layer.cpp @@ -0,0 +1,178 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "hillshade_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::HillshadeLayer& toHillshadeLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HillshadeLayer::HillshadeLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HillshadeLayer::HillshadeLayer(mbgl::Map& map, mbgl::style::HillshadeLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HillshadeLayer::HillshadeLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + HillshadeLayer::~HillshadeLayer() = default; + + // Property getters + + jni::Local> HillshadeLayer::getHillshadeIlluminationDirection(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationDirection())); + } + + jni::Local> HillshadeLayer::getHillshadeIlluminationAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationAnchor())); + } + + jni::Local> HillshadeLayer::getHillshadeExaggeration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeExaggeration())); + } + + jni::Local> HillshadeLayer::getHillshadeExaggerationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeExaggerationTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeExaggerationTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeShadowColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeShadowColor())); + } + + jni::Local> HillshadeLayer::getHillshadeShadowColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeShadowColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeShadowColorTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeHighlightColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeHighlightColor())); + } + + jni::Local> HillshadeLayer::getHillshadeHighlightColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeHighlightColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeHighlightColorTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeAccentColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeAccentColor())); + } + + jni::Local> HillshadeLayer::getHillshadeAccentColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeAccentColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeAccentColorTransition(options); + } + + + // HillshadeJavaLayerPeerFactory + + HillshadeJavaLayerPeerFactory::~HillshadeJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HillshadeLayer(map, toHillshadeLayer(layer))); + } + + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HillshadeLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void HillshadeJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&HillshadeLayer::getHillshadeIlluminationDirection, "nativeGetHillshadeIlluminationDirection"), + METHOD(&HillshadeLayer::getHillshadeIlluminationAnchor, "nativeGetHillshadeIlluminationAnchor"), + METHOD(&HillshadeLayer::getHillshadeExaggerationTransition, "nativeGetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::setHillshadeExaggerationTransition, "nativeSetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::getHillshadeExaggeration, "nativeGetHillshadeExaggeration"), + METHOD(&HillshadeLayer::getHillshadeShadowColorTransition, "nativeGetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::setHillshadeShadowColorTransition, "nativeSetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::getHillshadeShadowColor, "nativeGetHillshadeShadowColor"), + METHOD(&HillshadeLayer::getHillshadeHighlightColorTransition, "nativeGetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::setHillshadeHighlightColorTransition, "nativeSetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::getHillshadeHighlightColor, "nativeGetHillshadeHighlightColor"), + METHOD(&HillshadeLayer::getHillshadeAccentColorTransition, "nativeGetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::setHillshadeAccentColorTransition, "nativeSetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::getHillshadeAccentColor, "nativeGetHillshadeAccentColor")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/hillshade_layer.hpp b/src/style/layers/hillshade_layer.hpp new file mode 100644 index 000000000..2f4ea30c2 --- /dev/null +++ b/src/style/layers/hillshade_layer.hpp @@ -0,0 +1,66 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class HillshadeLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HillshadeLayer"; }; + + HillshadeLayer(jni::JNIEnv&, jni::String&, jni::String&); + + HillshadeLayer(mbgl::Map&, mbgl::style::HillshadeLayer&); + + HillshadeLayer(mbgl::Map&, std::unique_ptr); + + ~HillshadeLayer(); + + // Properties + + jni::Local> getHillshadeIlluminationDirection(jni::JNIEnv&); + + jni::Local> getHillshadeIlluminationAnchor(jni::JNIEnv&); + + jni::Local> getHillshadeExaggeration(jni::JNIEnv&); + void setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeExaggerationTransition(jni::JNIEnv&); + + jni::Local> getHillshadeShadowColor(jni::JNIEnv&); + void setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeShadowColorTransition(jni::JNIEnv&); + + jni::Local> getHillshadeHighlightColor(jni::JNIEnv&); + void setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeHighlightColorTransition(jni::JNIEnv&); + + jni::Local> getHillshadeAccentColor(jni::JNIEnv&); + void setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeAccentColorTransition(jni::JNIEnv&); + +}; // class HillshadeLayer + +class HillshadeJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HillshadeLayerFactory { +public: + ~HillshadeJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class HillshadeJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/layer.cpp b/src/style/layers/layer.cpp new file mode 100644 index 000000000..2f335b6ff --- /dev/null +++ b/src/style/layers/layer.cpp @@ -0,0 +1,198 @@ +#include "layer.hpp" +#include "../android_conversion.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Java -> C++ conversion +#include +#include +#include +#include + +// C++ -> Java conversion +#include "../conversion/property_value.hpp" +#include "custom_layer.hpp" +#include "background_layer.hpp" +#include + +#include + +namespace mbgl { +namespace android { + + /** + * Invoked when the construction is initiated from the jvm through a subclass + */ + Layer::Layer(std::unique_ptr coreLayer) + : ownedLayer(std::move(coreLayer)) + , layer(*ownedLayer) { + } + + /** + * Takes a non-owning reference. For lookup methods + */ + Layer::Layer(mbgl::Map& coreMap, mbgl::style::Layer& coreLayer) : layer(coreLayer) , map(&coreMap) { + } + + /** + * Takes a owning reference. Ownership is transfered to this peer, eg after removing + * from the map + */ + Layer::Layer(mbgl::Map& coreMap, std::unique_ptr coreLayer) + : ownedLayer(std::move(coreLayer)) + , layer(*ownedLayer) + , map(&coreMap) { + } + + Layer::~Layer() { + } + + void Layer::addToMap(mbgl::Map& _map, mbgl::optional before) { + // Check to see if we own the layer first + if (!ownedLayer) { + throw std::runtime_error("Cannot add layer twice"); + } + + // Add layer to map + _map.getStyle().addLayer(releaseCoreLayer(), before); + + // Save pointer to the map + this->map = &_map; + } + + void Layer::setLayer(std::unique_ptr sourceLayer) { + this->ownedLayer = std::move(sourceLayer); + } + + std::unique_ptr Layer::releaseCoreLayer() { + assert(ownedLayer != nullptr); + return std::move(ownedLayer); + } + + jni::Local Layer::getId(jni::JNIEnv& env) { + return jni::Make(env, layer.getID()); + } + + style::Layer& Layer::get() { + return layer; + } + + void Layer::setLayoutProperty(jni::JNIEnv& env, const jni::String& jname, const jni::Object<>& jvalue) { + // Convert and set property + optional error = layer.setLayoutProperty(jni::Make(env, jname), Value(env, jvalue)); + if (error) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); + return; + } + } + + void Layer::setPaintProperty(jni::JNIEnv& env, const jni::String& jname, const jni::Object<>& jvalue) { + // Convert and set property + optional error = layer.setPaintProperty(jni::Make(env, jname), Value(env, jvalue)); + if (error) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); + return; + } + } + + void Layer::setFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Error error; + optional converted = convert(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message); + return; + } + + layer.setFilter(std::move(*converted)); + } + + jni::Local> Layer::getFilter(jni::JNIEnv& env) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Filter filter = layer.getFilter(); + if (filter.expression) { + mbgl::Value expressionValue = (*filter.expression)->serialize(); + return gson::JsonElement::New(env, expressionValue); + } else { + return jni::Local>(env, nullptr); + } + } + + void Layer::setSourceLayer(jni::JNIEnv& env, const jni::String& sourceLayer) { + layer.setSourceLayer(jni::Make(env, sourceLayer)); + } + + jni::Local Layer::getSourceLayer(jni::JNIEnv& env) { + return jni::Make(env, layer.getSourceLayer()); + } + + jni::Local Layer::getSourceId(jni::JNIEnv& env) { + return jni::Make(env, layer.getSourceID()); + } + + jni::jfloat Layer::getMinZoom(jni::JNIEnv&){ + return layer.getMinZoom(); + } + + jni::jfloat Layer::getMaxZoom(jni::JNIEnv&) { + return layer.getMaxZoom(); + } + + void Layer::setMinZoom(jni::JNIEnv&, jni::jfloat zoom) { + layer.setMinZoom(zoom); + } + + void Layer::setMaxZoom(jni::JNIEnv&, jni::jfloat zoom) { + layer.setMaxZoom(zoom); + } + + jni::Local> Layer::getVisibility(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, layer.getVisibility())); + } + + void Layer::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&Layer::getId, "nativeGetId"), + METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"), + METHOD(&Layer::setPaintProperty, "nativeSetPaintProperty"), + METHOD(&Layer::setFilter, "nativeSetFilter"), + METHOD(&Layer::getFilter, "nativeGetFilter"), + METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"), + METHOD(&Layer::getSourceLayer, "nativeGetSourceLayer"), + METHOD(&Layer::getSourceId, "nativeGetSourceId"), + METHOD(&Layer::getMinZoom, "nativeGetMinZoom"), + METHOD(&Layer::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&Layer::setMinZoom, "nativeSetMinZoom"), + METHOD(&Layer::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&Layer::getVisibility, "nativeGetVisibility") + ); + + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/layer.cpp.ejs b/src/style/layers/layer.cpp.ejs new file mode 100644 index 000000000..c81fc5ab3 --- /dev/null +++ b/src/style/layers/layer.cpp.ejs @@ -0,0 +1,137 @@ +<% + const type = locals.type; + const properties = locals.properties; +-%> +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "<%- type.replace('-', '_') %>_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::<%- camelize(type) %>Layer& to<%- camelize(type) %>Layer(mbgl::style::Layer& layer) { + return static_castLayer&>(layer); + } + +<% if (type === 'background') { -%> + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId) + : Layer(std::make_uniqueLayer>(jni::Make(env, layerId))) { +<% } else { -%> + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_uniqueLayer>(jni::Make(env, layerId), jni::Make(env, sourceId))) { +<% } -%> + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, std::unique_ptrLayer> coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + <%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; + + // Property getters + +<% for (const property of properties) { -%> +<% if (property.name != 'heatmap-color') { -%> + jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>())); + } + +<% } else { -%> + jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = to<%- camelize(type) %>Layer(layer).getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = to<%- camelize(type) %>Layer(layer).getDefaultHeatmapColor(); + } + return std::move(*convert>>(env, propertyValue)); + } + +<% } -%> +<% if (property.transition) { -%> + jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>Transition(); + return std::move(*convert>>(env, options)); + } + + void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + to<%- camelize(type) %>Layer(layer).set<%- camelize(property.name) %>Transition(options); + } + +<% } -%> +<% } -%> + + // <%- camelize(type) %>JavaLayerPeerFactory + + <%- camelize(type) %>JavaLayerPeerFactory::~<%- camelize(type) %>JavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new <%- camelize(type) %>Layer(map, to<%- camelize(type) %>Layer(layer))); + } + + jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new <%- camelize(type) %>Layer(map, std::unique_ptrLayer>(static_castLayer*>(layer.release())))); + } + + void <%- camelize(type) %>JavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer<<%- camelize(type) %>Layer>( + env, javaClass, "nativePtr", +<% if (type === 'background') { -%> + jni::MakePeer<<%- camelize(type) %>Layer, jni::String&>, +<% } else { -%> + jni::MakePeer<<%- camelize(type) %>Layer, jni::String&, jni::String&>, +<% } -%> + "initialize", + "finalize",<% for(var i = 0; i < properties.length; i++) {%> +<% if (properties[i].transition) { -%> + METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"), + METHOD(&<%- camelize(type) %>Layer::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"), +<% } -%> + METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/layer.hpp b/src/style/layers/layer.hpp new file mode 100644 index 000000000..0fb679152 --- /dev/null +++ b/src/style/layers/layer.hpp @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include "../../gson/json_array.hpp" +#include "../value.hpp" +#include "../../gson/json_element.hpp" + +#include + +namespace mbgl { + +namespace android { + +class Layer { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/Layer"; }; + + static void registerNative(jni::JNIEnv&); + + virtual ~Layer(); + + /** + * Set core layer (ie return ownership after remove) + */ + void setLayer(std::unique_ptr); + + void addToMap(mbgl::Map&, mbgl::optional); + + jni::Local getId(jni::JNIEnv&); + + jni::Local getSourceId(jni::JNIEnv&); + + style::Layer& get(); + + void setLayoutProperty(jni::JNIEnv&, const jni::String&, const jni::Object<>& value); + + void setPaintProperty(jni::JNIEnv&, const jni::String&, const jni::Object<>& value); + + // Zoom + + jni::jfloat getMinZoom(jni::JNIEnv&); + + jni::jfloat getMaxZoom(jni::JNIEnv&); + + void setMinZoom(jni::JNIEnv&, jni::jfloat zoom); + + void setMaxZoom(jni::JNIEnv&, jni::jfloat zoom); + + /* common properties, but not shared by all */ + + void setFilter(jni::JNIEnv&, const jni::Array>&); + + jni::Local> getFilter(jni::JNIEnv&); + + void setSourceLayer(jni::JNIEnv&, const jni::String&); + + jni::Local getSourceLayer(jni::JNIEnv&); + + // Property getters + + jni::Local> getVisibility(jni::JNIEnv&); + +protected: + /* + * Called when a non-owning peer object is created on the c++ side + */ + Layer(mbgl::Map&, mbgl::style::Layer&); + + /* + * Called when a owning peer object is created on the c++ side + */ + Layer(mbgl::Map&, std::unique_ptr); + + /* + * Called when a Java object was created from the jvm side + */ + Layer(std::unique_ptr); + + // Release the owned view and return it + std::unique_ptr releaseCoreLayer(); + + // Owned layer is set when creating a new layer, before adding it to the map + std::unique_ptr ownedLayer; + + // Raw reference to the layer + mbgl::style::Layer& layer; + + // Map is set when the layer is retrieved or after adding to the map + mbgl::Map* map; +}; + +/** + * @brief A factory class for a layer Java peer objects of a certain type. + */ +class JavaLayerPeerFactory { +public: + virtual ~JavaLayerPeerFactory() = default; + /** + * @brief Create a non-owning peer. + */ + virtual jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) = 0; + + /** + * @brief Create an owning peer. + */ + virtual jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) = 0; + + /** + * @brief Register peer methods. + */ + virtual void registerNative(jni::JNIEnv&) = 0; + + /** + * @brief Get the corresponding layer factory. + * + * @return style::LayerFactory* must not be \c nullptr. + */ + virtual LayerFactory* getLayerFactory() = 0; +}; + + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/layer.hpp.ejs b/src/style/layers/layer.hpp.ejs new file mode 100644 index 000000000..28e00b273 --- /dev/null +++ b/src/style/layers/layer.hpp.ejs @@ -0,0 +1,62 @@ +<% + const type = locals.type; + const properties = locals.properties; +-%> +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include _layer_factory.hpp> +#include _layer.hpp> +#include + +namespace mbgl { +namespace android { + +class <%- camelize(type) %>Layer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; }; + +<% if (type === 'background') { -%> + <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&); +<% } else { -%> + <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&, jni::String&); +<% } -%> + + <%- camelize(type) %>Layer(mbgl::Map&, mbgl::style::<%- camelize(type) %>Layer&); + + <%- camelize(type) %>Layer(mbgl::Map&, std::unique_ptrLayer>); + + ~<%- camelize(type) %>Layer(); + + // Properties +<% for (const property of properties) { -%> + + jni::Local> get<%- camelize(property.name) %>(jni::JNIEnv&); +<% if (property.transition) { -%> + void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> get<%- camelize(property.name) %>Transition(jni::JNIEnv&); +<% } -%> +<% } -%> + +}; // class <%- camelize(type) %>Layer + +class <%- camelize(type) %>JavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::<%- camelize(type) %>LayerFactory { +public: + ~<%- camelize(type) %>JavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class <%- camelize(type) %>JavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/layer_manager.cpp b/src/style/layers/layer_manager.cpp new file mode 100644 index 000000000..d0c54ee00 --- /dev/null +++ b/src/style/layers/layer_manager.cpp @@ -0,0 +1,172 @@ +#include "layer_manager.hpp" + +#include + +#include +#include +#include + +#include "background_layer.hpp" +#include "circle_layer.hpp" +#include "custom_layer.hpp" +#include "fill_extrusion_layer.hpp" +#include "fill_layer.hpp" +#include "heatmap_layer.hpp" +#include "hillshade_layer.hpp" +#include "line_layer.hpp" +#include "raster_layer.hpp" +#include "symbol_layer.hpp" +#include "fill_extrusion_layer.hpp" + +namespace mbgl { + +namespace android { + +LayerManagerAndroid::LayerManagerAndroid() { +#if defined(MBGL_LAYER_FILL_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_FILL_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_LINE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_LINE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_CIRCLE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_CIRCLE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_SYMBOL_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_RASTER_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_RASTER_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_BACKGROUND_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_BACKGROUND_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_HILLSHADE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_HILLSHADE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_HEATMAP_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_HEATMAP_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_CUSTOM_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +} + +LayerManagerAndroid::~LayerManagerAndroid() = default; + +jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + if (JavaLayerPeerFactory* factory = getPeerFactory(layer.getTypeInfo())) { + return factory->createJavaLayerPeer(env, map, layer); + } + return jni::Local>(); +} + +jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + if (JavaLayerPeerFactory* factory = getPeerFactory(layer->getTypeInfo())) { + return factory->createJavaLayerPeer(env, map, std::move(layer)); + } + return jni::Local>(); +} + +void LayerManagerAndroid::registerNative(jni::JNIEnv& env) { + if (peerFactories.empty()) { + return; + } + + Layer::registerNative(env); + for (const auto& factory: peerFactories) { + factory->registerNative(env); + } +} + +void LayerManagerAndroid::addLayerType(std::unique_ptr factory) { + assert(getFactory(factory->getLayerFactory()->getTypeInfo()) == nullptr); + registerCoreFactory(factory->getLayerFactory()); + peerFactories.emplace_back(std::move(factory)); +} + +void LayerManagerAndroid::addLayerTypeCoreOnly(std::unique_ptr factory) { + assert(getFactory(factory->getTypeInfo()) == nullptr); + registerCoreFactory(factory.get()); + coreFactories.emplace_back(std::move(factory)); +} + +void LayerManagerAndroid::registerCoreFactory(mbgl::LayerFactory* factory) { + std::string type{factory->getTypeInfo()->type}; + if (!type.empty()) { + assert(typeToFactory.find(type) == typeToFactory.end()); + typeToFactory.emplace(std::make_pair(std::move(type), factory)); + } +} + +JavaLayerPeerFactory* LayerManagerAndroid::getPeerFactory(const mbgl::style::LayerTypeInfo* typeInfo) { + assert(typeInfo); + for (const auto& factory: peerFactories) { + if (factory->getLayerFactory()->getTypeInfo() == typeInfo) { + return factory.get(); + } + } + return nullptr; +} + +LayerFactory* LayerManagerAndroid::getFactory(const std::string& type) noexcept { + auto search = typeToFactory.find(type); + return (search != typeToFactory.end()) ? search->second : nullptr; +} + +LayerFactory* LayerManagerAndroid::getFactory(const mbgl::style::LayerTypeInfo* info) noexcept { + if (JavaLayerPeerFactory* peerFactory = getPeerFactory(info)) { + return peerFactory->getLayerFactory(); + } + + for (const auto& factory: coreFactories) { + if (factory->getTypeInfo() == info) { + return factory.get(); + } + } + + return nullptr; +} + +// static +LayerManagerAndroid* LayerManagerAndroid::get() noexcept { + static LayerManagerAndroid impl; + return &impl; +} + +} // namespace android + +LayerManager* LayerManager::get() noexcept { + return android::LayerManagerAndroid::get(); +} + +#if defined(MBGL_LAYER_LINE_DISABLE_ALL) || defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) || defined(MBGL_LAYER_FILL_DISABLE_ALL) +const bool LayerManager::annotationsEnabled = false; +#else +const bool LayerManager::annotationsEnabled = true; +#endif + +} // namespace mbgl diff --git a/src/style/layers/layer_manager.hpp b/src/style/layers/layer_manager.hpp new file mode 100644 index 000000000..807ded173 --- /dev/null +++ b/src/style/layers/layer_manager.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include "layer.hpp" + +#include + +#include +#include + +namespace mbgl { +namespace android { + +/** + * @brief A singleton class forwarding calls to the corresponding \c JavaLayerPeerFactory instance. + */ +class LayerManagerAndroid final : public mbgl::LayerManager { +public: + ~LayerManagerAndroid() final; + static LayerManagerAndroid* get() noexcept; + + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&); + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr); + + void registerNative(jni::JNIEnv&); + +private: + LayerManagerAndroid(); + /** + * @brief Enables a layer type for both JSON style and runtime API. + */ + void addLayerType(std::unique_ptr); + /** + * @brief Enables a layer type for JSON style only. + * + * We might not want to expose runtime API for some layer types + * in order to save binary size - JNI glue code for these layer types + * won't be added to the binary. + */ + void addLayerTypeCoreOnly(std::unique_ptr); + + void registerCoreFactory(mbgl::LayerFactory*); + JavaLayerPeerFactory* getPeerFactory(const mbgl::style::LayerTypeInfo*); + // mbgl::LayerManager overrides. + LayerFactory* getFactory(const std::string& type) noexcept final; + LayerFactory* getFactory(const mbgl::style::LayerTypeInfo* info) noexcept final; + + std::vector> peerFactories; + std::vector> coreFactories; + std::map typeToFactory; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/line_layer.cpp b/src/style/layers/line_layer.cpp new file mode 100644 index 000000000..73fcd5f99 --- /dev/null +++ b/src/style/layers/line_layer.cpp @@ -0,0 +1,307 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "line_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::LineLayer& toLineLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + LineLayer::LineLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + LineLayer::LineLayer(mbgl::Map& map, mbgl::style::LineLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + LineLayer::LineLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + LineLayer::~LineLayer() = default; + + // Property getters + + jni::Local> LineLayer::getLineCap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineCap())); + } + + jni::Local> LineLayer::getLineJoin(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineJoin())); + } + + jni::Local> LineLayer::getLineMiterLimit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineMiterLimit())); + } + + jni::Local> LineLayer::getLineRoundLimit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineRoundLimit())); + } + + jni::Local> LineLayer::getLineOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineOpacity())); + } + + jni::Local> LineLayer::getLineOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineOpacityTransition(options); + } + + jni::Local> LineLayer::getLineColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineColor())); + } + + jni::Local> LineLayer::getLineColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineColorTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineColorTransition(options); + } + + jni::Local> LineLayer::getLineTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineTranslate())); + } + + jni::Local> LineLayer::getLineTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineTranslateTransition(options); + } + + jni::Local> LineLayer::getLineTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineTranslateAnchor())); + } + + jni::Local> LineLayer::getLineWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineWidth())); + } + + jni::Local> LineLayer::getLineWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineWidthTransition(options); + } + + jni::Local> LineLayer::getLineGapWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineGapWidth())); + } + + jni::Local> LineLayer::getLineGapWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineGapWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineGapWidthTransition(options); + } + + jni::Local> LineLayer::getLineOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineOffset())); + } + + jni::Local> LineLayer::getLineOffsetTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOffsetTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineOffsetTransition(options); + } + + jni::Local> LineLayer::getLineBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineBlur())); + } + + jni::Local> LineLayer::getLineBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineBlurTransition(options); + } + + jni::Local> LineLayer::getLineDasharray(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineDasharray())); + } + + jni::Local> LineLayer::getLineDasharrayTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineDasharrayTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineDasharrayTransition(options); + } + + jni::Local> LineLayer::getLinePattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLinePattern())); + } + + jni::Local> LineLayer::getLinePatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLinePatternTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLinePatternTransition(options); + } + + jni::Local> LineLayer::getLineGradient(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineGradient())); + } + + + // LineJavaLayerPeerFactory + + LineJavaLayerPeerFactory::~LineJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new LineLayer(map, toLineLayer(layer))); + } + + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new LineLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void LineJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&LineLayer::getLineCap, "nativeGetLineCap"), + METHOD(&LineLayer::getLineJoin, "nativeGetLineJoin"), + METHOD(&LineLayer::getLineMiterLimit, "nativeGetLineMiterLimit"), + METHOD(&LineLayer::getLineRoundLimit, "nativeGetLineRoundLimit"), + METHOD(&LineLayer::getLineOpacityTransition, "nativeGetLineOpacityTransition"), + METHOD(&LineLayer::setLineOpacityTransition, "nativeSetLineOpacityTransition"), + METHOD(&LineLayer::getLineOpacity, "nativeGetLineOpacity"), + METHOD(&LineLayer::getLineColorTransition, "nativeGetLineColorTransition"), + METHOD(&LineLayer::setLineColorTransition, "nativeSetLineColorTransition"), + METHOD(&LineLayer::getLineColor, "nativeGetLineColor"), + METHOD(&LineLayer::getLineTranslateTransition, "nativeGetLineTranslateTransition"), + METHOD(&LineLayer::setLineTranslateTransition, "nativeSetLineTranslateTransition"), + METHOD(&LineLayer::getLineTranslate, "nativeGetLineTranslate"), + METHOD(&LineLayer::getLineTranslateAnchor, "nativeGetLineTranslateAnchor"), + METHOD(&LineLayer::getLineWidthTransition, "nativeGetLineWidthTransition"), + METHOD(&LineLayer::setLineWidthTransition, "nativeSetLineWidthTransition"), + METHOD(&LineLayer::getLineWidth, "nativeGetLineWidth"), + METHOD(&LineLayer::getLineGapWidthTransition, "nativeGetLineGapWidthTransition"), + METHOD(&LineLayer::setLineGapWidthTransition, "nativeSetLineGapWidthTransition"), + METHOD(&LineLayer::getLineGapWidth, "nativeGetLineGapWidth"), + METHOD(&LineLayer::getLineOffsetTransition, "nativeGetLineOffsetTransition"), + METHOD(&LineLayer::setLineOffsetTransition, "nativeSetLineOffsetTransition"), + METHOD(&LineLayer::getLineOffset, "nativeGetLineOffset"), + METHOD(&LineLayer::getLineBlurTransition, "nativeGetLineBlurTransition"), + METHOD(&LineLayer::setLineBlurTransition, "nativeSetLineBlurTransition"), + METHOD(&LineLayer::getLineBlur, "nativeGetLineBlur"), + METHOD(&LineLayer::getLineDasharrayTransition, "nativeGetLineDasharrayTransition"), + METHOD(&LineLayer::setLineDasharrayTransition, "nativeSetLineDasharrayTransition"), + METHOD(&LineLayer::getLineDasharray, "nativeGetLineDasharray"), + METHOD(&LineLayer::getLinePatternTransition, "nativeGetLinePatternTransition"), + METHOD(&LineLayer::setLinePatternTransition, "nativeSetLinePatternTransition"), + METHOD(&LineLayer::getLinePattern, "nativeGetLinePattern"), + METHOD(&LineLayer::getLineGradient, "nativeGetLineGradient")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/line_layer.hpp b/src/style/layers/line_layer.hpp new file mode 100644 index 000000000..75a367ab7 --- /dev/null +++ b/src/style/layers/line_layer.hpp @@ -0,0 +1,94 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class LineLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LineLayer"; }; + + LineLayer(jni::JNIEnv&, jni::String&, jni::String&); + + LineLayer(mbgl::Map&, mbgl::style::LineLayer&); + + LineLayer(mbgl::Map&, std::unique_ptr); + + ~LineLayer(); + + // Properties + + jni::Local> getLineCap(jni::JNIEnv&); + + jni::Local> getLineJoin(jni::JNIEnv&); + + jni::Local> getLineMiterLimit(jni::JNIEnv&); + + jni::Local> getLineRoundLimit(jni::JNIEnv&); + + jni::Local> getLineOpacity(jni::JNIEnv&); + void setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineOpacityTransition(jni::JNIEnv&); + + jni::Local> getLineColor(jni::JNIEnv&); + void setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineColorTransition(jni::JNIEnv&); + + jni::Local> getLineTranslate(jni::JNIEnv&); + void setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineTranslateTransition(jni::JNIEnv&); + + jni::Local> getLineTranslateAnchor(jni::JNIEnv&); + + jni::Local> getLineWidth(jni::JNIEnv&); + void setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineWidthTransition(jni::JNIEnv&); + + jni::Local> getLineGapWidth(jni::JNIEnv&); + void setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineGapWidthTransition(jni::JNIEnv&); + + jni::Local> getLineOffset(jni::JNIEnv&); + void setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineOffsetTransition(jni::JNIEnv&); + + jni::Local> getLineBlur(jni::JNIEnv&); + void setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineBlurTransition(jni::JNIEnv&); + + jni::Local> getLineDasharray(jni::JNIEnv&); + void setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineDasharrayTransition(jni::JNIEnv&); + + jni::Local> getLinePattern(jni::JNIEnv&); + void setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLinePatternTransition(jni::JNIEnv&); + + jni::Local> getLineGradient(jni::JNIEnv&); + +}; // class LineLayer + +class LineJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::LineLayerFactory { +public: + ~LineJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class LineJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/raster_layer.cpp b/src/style/layers/raster_layer.cpp new file mode 100644 index 000000000..b12267525 --- /dev/null +++ b/src/style/layers/raster_layer.cpp @@ -0,0 +1,220 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "raster_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::RasterLayer& toRasterLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + RasterLayer::RasterLayer(mbgl::Map& map, mbgl::style::RasterLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + RasterLayer::RasterLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + RasterLayer::~RasterLayer() = default; + + // Property getters + + jni::Local> RasterLayer::getRasterOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterOpacity())); + } + + jni::Local> RasterLayer::getRasterOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterOpacityTransition(options); + } + + jni::Local> RasterLayer::getRasterHueRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterHueRotate())); + } + + jni::Local> RasterLayer::getRasterHueRotateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterHueRotateTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterHueRotateTransition(options); + } + + jni::Local> RasterLayer::getRasterBrightnessMin(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMin())); + } + + jni::Local> RasterLayer::getRasterBrightnessMinTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMinTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterBrightnessMinTransition(options); + } + + jni::Local> RasterLayer::getRasterBrightnessMax(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMax())); + } + + jni::Local> RasterLayer::getRasterBrightnessMaxTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMaxTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterBrightnessMaxTransition(options); + } + + jni::Local> RasterLayer::getRasterSaturation(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterSaturation())); + } + + jni::Local> RasterLayer::getRasterSaturationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterSaturationTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterSaturationTransition(options); + } + + jni::Local> RasterLayer::getRasterContrast(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterContrast())); + } + + jni::Local> RasterLayer::getRasterContrastTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterContrastTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterContrastTransition(options); + } + + jni::Local> RasterLayer::getRasterResampling(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterResampling())); + } + + jni::Local> RasterLayer::getRasterFadeDuration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterFadeDuration())); + } + + + // RasterJavaLayerPeerFactory + + RasterJavaLayerPeerFactory::~RasterJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new RasterLayer(map, toRasterLayer(layer))); + } + + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new RasterLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void RasterJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&RasterLayer::getRasterOpacityTransition, "nativeGetRasterOpacityTransition"), + METHOD(&RasterLayer::setRasterOpacityTransition, "nativeSetRasterOpacityTransition"), + METHOD(&RasterLayer::getRasterOpacity, "nativeGetRasterOpacity"), + METHOD(&RasterLayer::getRasterHueRotateTransition, "nativeGetRasterHueRotateTransition"), + METHOD(&RasterLayer::setRasterHueRotateTransition, "nativeSetRasterHueRotateTransition"), + METHOD(&RasterLayer::getRasterHueRotate, "nativeGetRasterHueRotate"), + METHOD(&RasterLayer::getRasterBrightnessMinTransition, "nativeGetRasterBrightnessMinTransition"), + METHOD(&RasterLayer::setRasterBrightnessMinTransition, "nativeSetRasterBrightnessMinTransition"), + METHOD(&RasterLayer::getRasterBrightnessMin, "nativeGetRasterBrightnessMin"), + METHOD(&RasterLayer::getRasterBrightnessMaxTransition, "nativeGetRasterBrightnessMaxTransition"), + METHOD(&RasterLayer::setRasterBrightnessMaxTransition, "nativeSetRasterBrightnessMaxTransition"), + METHOD(&RasterLayer::getRasterBrightnessMax, "nativeGetRasterBrightnessMax"), + METHOD(&RasterLayer::getRasterSaturationTransition, "nativeGetRasterSaturationTransition"), + METHOD(&RasterLayer::setRasterSaturationTransition, "nativeSetRasterSaturationTransition"), + METHOD(&RasterLayer::getRasterSaturation, "nativeGetRasterSaturation"), + METHOD(&RasterLayer::getRasterContrastTransition, "nativeGetRasterContrastTransition"), + METHOD(&RasterLayer::setRasterContrastTransition, "nativeSetRasterContrastTransition"), + METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"), + METHOD(&RasterLayer::getRasterResampling, "nativeGetRasterResampling"), + METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/raster_layer.hpp b/src/style/layers/raster_layer.hpp new file mode 100644 index 000000000..53bee85e2 --- /dev/null +++ b/src/style/layers/raster_layer.hpp @@ -0,0 +1,74 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class RasterLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/RasterLayer"; }; + + RasterLayer(jni::JNIEnv&, jni::String&, jni::String&); + + RasterLayer(mbgl::Map&, mbgl::style::RasterLayer&); + + RasterLayer(mbgl::Map&, std::unique_ptr); + + ~RasterLayer(); + + // Properties + + jni::Local> getRasterOpacity(jni::JNIEnv&); + void setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterOpacityTransition(jni::JNIEnv&); + + jni::Local> getRasterHueRotate(jni::JNIEnv&); + void setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterHueRotateTransition(jni::JNIEnv&); + + jni::Local> getRasterBrightnessMin(jni::JNIEnv&); + void setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterBrightnessMinTransition(jni::JNIEnv&); + + jni::Local> getRasterBrightnessMax(jni::JNIEnv&); + void setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterBrightnessMaxTransition(jni::JNIEnv&); + + jni::Local> getRasterSaturation(jni::JNIEnv&); + void setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterSaturationTransition(jni::JNIEnv&); + + jni::Local> getRasterContrast(jni::JNIEnv&); + void setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterContrastTransition(jni::JNIEnv&); + + jni::Local> getRasterResampling(jni::JNIEnv&); + + jni::Local> getRasterFadeDuration(jni::JNIEnv&); + +}; // class RasterLayer + +class RasterJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::RasterLayerFactory { +public: + ~RasterJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class RasterJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/symbol_layer.cpp b/src/style/layers/symbol_layer.cpp new file mode 100644 index 000000000..53b35a9a1 --- /dev/null +++ b/src/style/layers/symbol_layer.cpp @@ -0,0 +1,592 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "symbol_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::SymbolLayer& toSymbolLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + SymbolLayer::SymbolLayer(mbgl::Map& map, mbgl::style::SymbolLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + SymbolLayer::SymbolLayer(mbgl::Map& map, std::unique_ptr coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + SymbolLayer::~SymbolLayer() = default; + + // Property getters + + jni::Local> SymbolLayer::getSymbolPlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolPlacement())); + } + + jni::Local> SymbolLayer::getSymbolSpacing(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSpacing())); + } + + jni::Local> SymbolLayer::getSymbolAvoidEdges(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolAvoidEdges())); + } + + jni::Local> SymbolLayer::getSymbolSortKey(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSortKey())); + } + + jni::Local> SymbolLayer::getSymbolZOrder(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolZOrder())); + } + + jni::Local> SymbolLayer::getIconAllowOverlap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconAllowOverlap())); + } + + jni::Local> SymbolLayer::getIconIgnorePlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconIgnorePlacement())); + } + + jni::Local> SymbolLayer::getIconOptional(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOptional())); + } + + jni::Local> SymbolLayer::getIconRotationAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotationAlignment())); + } + + jni::Local> SymbolLayer::getIconSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconSize())); + } + + jni::Local> SymbolLayer::getIconTextFit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFit())); + } + + jni::Local> SymbolLayer::getIconTextFitPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFitPadding())); + } + + jni::Local> SymbolLayer::getIconImage(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconImage())); + } + + jni::Local> SymbolLayer::getIconRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotate())); + } + + jni::Local> SymbolLayer::getIconPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconPadding())); + } + + jni::Local> SymbolLayer::getIconKeepUpright(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconKeepUpright())); + } + + jni::Local> SymbolLayer::getIconOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOffset())); + } + + jni::Local> SymbolLayer::getIconAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconAnchor())); + } + + jni::Local> SymbolLayer::getIconPitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconPitchAlignment())); + } + + jni::Local> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextPitchAlignment())); + } + + jni::Local> SymbolLayer::getTextRotationAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotationAlignment())); + } + + jni::Local> SymbolLayer::getTextField(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextField())); + } + + jni::Local> SymbolLayer::getTextFont(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextFont())); + } + + jni::Local> SymbolLayer::getTextSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextSize())); + } + + jni::Local> SymbolLayer::getTextMaxWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxWidth())); + } + + jni::Local> SymbolLayer::getTextLineHeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextLineHeight())); + } + + jni::Local> SymbolLayer::getTextLetterSpacing(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextLetterSpacing())); + } + + jni::Local> SymbolLayer::getTextJustify(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextJustify())); + } + + jni::Local> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRadialOffset())); + } + + jni::Local> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextVariableAnchor())); + } + + jni::Local> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextAnchor())); + } + + jni::Local> SymbolLayer::getTextMaxAngle(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxAngle())); + } + + jni::Local> SymbolLayer::getTextWritingMode(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextWritingMode())); + } + + jni::Local> SymbolLayer::getTextRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotate())); + } + + jni::Local> SymbolLayer::getTextPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextPadding())); + } + + jni::Local> SymbolLayer::getTextKeepUpright(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextKeepUpright())); + } + + jni::Local> SymbolLayer::getTextTransform(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTransform())); + } + + jni::Local> SymbolLayer::getTextOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOffset())); + } + + jni::Local> SymbolLayer::getTextAllowOverlap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextAllowOverlap())); + } + + jni::Local> SymbolLayer::getTextIgnorePlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextIgnorePlacement())); + } + + jni::Local> SymbolLayer::getTextOptional(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOptional())); + } + + jni::Local> SymbolLayer::getIconOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOpacity())); + } + + jni::Local> SymbolLayer::getIconOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconOpacityTransition(options); + } + + jni::Local> SymbolLayer::getIconColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconColor())); + } + + jni::Local> SymbolLayer::getIconColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconColorTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloColor())); + } + + jni::Local> SymbolLayer::getIconHaloColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloColorTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloWidth())); + } + + jni::Local> SymbolLayer::getIconHaloWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloWidthTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloBlur())); + } + + jni::Local> SymbolLayer::getIconHaloBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloBlurTransition(options); + } + + jni::Local> SymbolLayer::getIconTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslate())); + } + + jni::Local> SymbolLayer::getIconTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconTranslateTransition(options); + } + + jni::Local> SymbolLayer::getIconTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslateAnchor())); + } + + jni::Local> SymbolLayer::getTextOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOpacity())); + } + + jni::Local> SymbolLayer::getTextOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextOpacityTransition(options); + } + + jni::Local> SymbolLayer::getTextColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextColor())); + } + + jni::Local> SymbolLayer::getTextColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextColorTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloColor())); + } + + jni::Local> SymbolLayer::getTextHaloColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloColorTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloWidth())); + } + + jni::Local> SymbolLayer::getTextHaloWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloWidthTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloBlur())); + } + + jni::Local> SymbolLayer::getTextHaloBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloBlurTransition(options); + } + + jni::Local> SymbolLayer::getTextTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslate())); + } + + jni::Local> SymbolLayer::getTextTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextTranslateTransition(options); + } + + jni::Local> SymbolLayer::getTextTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslateAnchor())); + } + + + // SymbolJavaLayerPeerFactory + + SymbolJavaLayerPeerFactory::~SymbolJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new SymbolLayer(map, toSymbolLayer(layer))); + } + + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new SymbolLayer(map, std::unique_ptr(static_cast(layer.release())))); + } + + void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&SymbolLayer::getSymbolPlacement, "nativeGetSymbolPlacement"), + METHOD(&SymbolLayer::getSymbolSpacing, "nativeGetSymbolSpacing"), + METHOD(&SymbolLayer::getSymbolAvoidEdges, "nativeGetSymbolAvoidEdges"), + METHOD(&SymbolLayer::getSymbolSortKey, "nativeGetSymbolSortKey"), + METHOD(&SymbolLayer::getSymbolZOrder, "nativeGetSymbolZOrder"), + METHOD(&SymbolLayer::getIconAllowOverlap, "nativeGetIconAllowOverlap"), + METHOD(&SymbolLayer::getIconIgnorePlacement, "nativeGetIconIgnorePlacement"), + METHOD(&SymbolLayer::getIconOptional, "nativeGetIconOptional"), + METHOD(&SymbolLayer::getIconRotationAlignment, "nativeGetIconRotationAlignment"), + METHOD(&SymbolLayer::getIconSize, "nativeGetIconSize"), + METHOD(&SymbolLayer::getIconTextFit, "nativeGetIconTextFit"), + METHOD(&SymbolLayer::getIconTextFitPadding, "nativeGetIconTextFitPadding"), + METHOD(&SymbolLayer::getIconImage, "nativeGetIconImage"), + METHOD(&SymbolLayer::getIconRotate, "nativeGetIconRotate"), + METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"), + METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"), + METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"), + METHOD(&SymbolLayer::getIconAnchor, "nativeGetIconAnchor"), + METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"), + METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"), + METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"), + METHOD(&SymbolLayer::getTextField, "nativeGetTextField"), + METHOD(&SymbolLayer::getTextFont, "nativeGetTextFont"), + METHOD(&SymbolLayer::getTextSize, "nativeGetTextSize"), + METHOD(&SymbolLayer::getTextMaxWidth, "nativeGetTextMaxWidth"), + METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"), + METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"), + METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), + METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), + METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), + METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), + METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), + METHOD(&SymbolLayer::getTextWritingMode, "nativeGetTextWritingMode"), + METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"), + METHOD(&SymbolLayer::getTextPadding, "nativeGetTextPadding"), + METHOD(&SymbolLayer::getTextKeepUpright, "nativeGetTextKeepUpright"), + METHOD(&SymbolLayer::getTextTransform, "nativeGetTextTransform"), + METHOD(&SymbolLayer::getTextOffset, "nativeGetTextOffset"), + METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"), + METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"), + METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"), + METHOD(&SymbolLayer::getIconOpacityTransition, "nativeGetIconOpacityTransition"), + METHOD(&SymbolLayer::setIconOpacityTransition, "nativeSetIconOpacityTransition"), + METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"), + METHOD(&SymbolLayer::getIconColorTransition, "nativeGetIconColorTransition"), + METHOD(&SymbolLayer::setIconColorTransition, "nativeSetIconColorTransition"), + METHOD(&SymbolLayer::getIconColor, "nativeGetIconColor"), + METHOD(&SymbolLayer::getIconHaloColorTransition, "nativeGetIconHaloColorTransition"), + METHOD(&SymbolLayer::setIconHaloColorTransition, "nativeSetIconHaloColorTransition"), + METHOD(&SymbolLayer::getIconHaloColor, "nativeGetIconHaloColor"), + METHOD(&SymbolLayer::getIconHaloWidthTransition, "nativeGetIconHaloWidthTransition"), + METHOD(&SymbolLayer::setIconHaloWidthTransition, "nativeSetIconHaloWidthTransition"), + METHOD(&SymbolLayer::getIconHaloWidth, "nativeGetIconHaloWidth"), + METHOD(&SymbolLayer::getIconHaloBlurTransition, "nativeGetIconHaloBlurTransition"), + METHOD(&SymbolLayer::setIconHaloBlurTransition, "nativeSetIconHaloBlurTransition"), + METHOD(&SymbolLayer::getIconHaloBlur, "nativeGetIconHaloBlur"), + METHOD(&SymbolLayer::getIconTranslateTransition, "nativeGetIconTranslateTransition"), + METHOD(&SymbolLayer::setIconTranslateTransition, "nativeSetIconTranslateTransition"), + METHOD(&SymbolLayer::getIconTranslate, "nativeGetIconTranslate"), + METHOD(&SymbolLayer::getIconTranslateAnchor, "nativeGetIconTranslateAnchor"), + METHOD(&SymbolLayer::getTextOpacityTransition, "nativeGetTextOpacityTransition"), + METHOD(&SymbolLayer::setTextOpacityTransition, "nativeSetTextOpacityTransition"), + METHOD(&SymbolLayer::getTextOpacity, "nativeGetTextOpacity"), + METHOD(&SymbolLayer::getTextColorTransition, "nativeGetTextColorTransition"), + METHOD(&SymbolLayer::setTextColorTransition, "nativeSetTextColorTransition"), + METHOD(&SymbolLayer::getTextColor, "nativeGetTextColor"), + METHOD(&SymbolLayer::getTextHaloColorTransition, "nativeGetTextHaloColorTransition"), + METHOD(&SymbolLayer::setTextHaloColorTransition, "nativeSetTextHaloColorTransition"), + METHOD(&SymbolLayer::getTextHaloColor, "nativeGetTextHaloColor"), + METHOD(&SymbolLayer::getTextHaloWidthTransition, "nativeGetTextHaloWidthTransition"), + METHOD(&SymbolLayer::setTextHaloWidthTransition, "nativeSetTextHaloWidthTransition"), + METHOD(&SymbolLayer::getTextHaloWidth, "nativeGetTextHaloWidth"), + METHOD(&SymbolLayer::getTextHaloBlurTransition, "nativeGetTextHaloBlurTransition"), + METHOD(&SymbolLayer::setTextHaloBlurTransition, "nativeSetTextHaloBlurTransition"), + METHOD(&SymbolLayer::getTextHaloBlur, "nativeGetTextHaloBlur"), + METHOD(&SymbolLayer::getTextTranslateTransition, "nativeGetTextTranslateTransition"), + METHOD(&SymbolLayer::setTextTranslateTransition, "nativeSetTextTranslateTransition"), + METHOD(&SymbolLayer::getTextTranslate, "nativeGetTextTranslate"), + METHOD(&SymbolLayer::getTextTranslateAnchor, "nativeGetTextTranslateAnchor")); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/layers/symbol_layer.hpp b/src/style/layers/symbol_layer.hpp new file mode 100644 index 000000000..9e494e678 --- /dev/null +++ b/src/style/layers/symbol_layer.hpp @@ -0,0 +1,180 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class SymbolLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/SymbolLayer"; }; + + SymbolLayer(jni::JNIEnv&, jni::String&, jni::String&); + + SymbolLayer(mbgl::Map&, mbgl::style::SymbolLayer&); + + SymbolLayer(mbgl::Map&, std::unique_ptr); + + ~SymbolLayer(); + + // Properties + + jni::Local> getSymbolPlacement(jni::JNIEnv&); + + jni::Local> getSymbolSpacing(jni::JNIEnv&); + + jni::Local> getSymbolAvoidEdges(jni::JNIEnv&); + + jni::Local> getSymbolSortKey(jni::JNIEnv&); + + jni::Local> getSymbolZOrder(jni::JNIEnv&); + + jni::Local> getIconAllowOverlap(jni::JNIEnv&); + + jni::Local> getIconIgnorePlacement(jni::JNIEnv&); + + jni::Local> getIconOptional(jni::JNIEnv&); + + jni::Local> getIconRotationAlignment(jni::JNIEnv&); + + jni::Local> getIconSize(jni::JNIEnv&); + + jni::Local> getIconTextFit(jni::JNIEnv&); + + jni::Local> getIconTextFitPadding(jni::JNIEnv&); + + jni::Local> getIconImage(jni::JNIEnv&); + + jni::Local> getIconRotate(jni::JNIEnv&); + + jni::Local> getIconPadding(jni::JNIEnv&); + + jni::Local> getIconKeepUpright(jni::JNIEnv&); + + jni::Local> getIconOffset(jni::JNIEnv&); + + jni::Local> getIconAnchor(jni::JNIEnv&); + + jni::Local> getIconPitchAlignment(jni::JNIEnv&); + + jni::Local> getTextPitchAlignment(jni::JNIEnv&); + + jni::Local> getTextRotationAlignment(jni::JNIEnv&); + + jni::Local> getTextField(jni::JNIEnv&); + + jni::Local> getTextFont(jni::JNIEnv&); + + jni::Local> getTextSize(jni::JNIEnv&); + + jni::Local> getTextMaxWidth(jni::JNIEnv&); + + jni::Local> getTextLineHeight(jni::JNIEnv&); + + jni::Local> getTextLetterSpacing(jni::JNIEnv&); + + jni::Local> getTextJustify(jni::JNIEnv&); + + jni::Local> getTextRadialOffset(jni::JNIEnv&); + + jni::Local> getTextVariableAnchor(jni::JNIEnv&); + + jni::Local> getTextAnchor(jni::JNIEnv&); + + jni::Local> getTextMaxAngle(jni::JNIEnv&); + + jni::Local> getTextWritingMode(jni::JNIEnv&); + + jni::Local> getTextRotate(jni::JNIEnv&); + + jni::Local> getTextPadding(jni::JNIEnv&); + + jni::Local> getTextKeepUpright(jni::JNIEnv&); + + jni::Local> getTextTransform(jni::JNIEnv&); + + jni::Local> getTextOffset(jni::JNIEnv&); + + jni::Local> getTextAllowOverlap(jni::JNIEnv&); + + jni::Local> getTextIgnorePlacement(jni::JNIEnv&); + + jni::Local> getTextOptional(jni::JNIEnv&); + + jni::Local> getIconOpacity(jni::JNIEnv&); + void setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconOpacityTransition(jni::JNIEnv&); + + jni::Local> getIconColor(jni::JNIEnv&); + void setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconColorTransition(jni::JNIEnv&); + + jni::Local> getIconHaloColor(jni::JNIEnv&); + void setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloColorTransition(jni::JNIEnv&); + + jni::Local> getIconHaloWidth(jni::JNIEnv&); + void setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloWidthTransition(jni::JNIEnv&); + + jni::Local> getIconHaloBlur(jni::JNIEnv&); + void setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloBlurTransition(jni::JNIEnv&); + + jni::Local> getIconTranslate(jni::JNIEnv&); + void setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconTranslateTransition(jni::JNIEnv&); + + jni::Local> getIconTranslateAnchor(jni::JNIEnv&); + + jni::Local> getTextOpacity(jni::JNIEnv&); + void setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextOpacityTransition(jni::JNIEnv&); + + jni::Local> getTextColor(jni::JNIEnv&); + void setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextColorTransition(jni::JNIEnv&); + + jni::Local> getTextHaloColor(jni::JNIEnv&); + void setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloColorTransition(jni::JNIEnv&); + + jni::Local> getTextHaloWidth(jni::JNIEnv&); + void setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloWidthTransition(jni::JNIEnv&); + + jni::Local> getTextHaloBlur(jni::JNIEnv&); + void setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloBlurTransition(jni::JNIEnv&); + + jni::Local> getTextTranslate(jni::JNIEnv&); + void setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextTranslateTransition(jni::JNIEnv&); + + jni::Local> getTextTranslateAnchor(jni::JNIEnv&); + +}; // class SymbolLayer + +class SymbolJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::SymbolLayerFactory { +public: + ~SymbolJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class SymbolJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/src/style/light.cpp b/src/style/light.cpp new file mode 100644 index 000000000..d8ed4d9d9 --- /dev/null +++ b/src/style/light.cpp @@ -0,0 +1,143 @@ +#include +#include "light.hpp" +#include "conversion/transition_options.hpp" +#include "conversion/position.hpp" + +namespace mbgl { +namespace android { + +Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight) + : light(coreLight) , map(&coreMap) { +} + +static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) { + return new Light(map, coreLight); +} + +jni::Local> Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) { + std::unique_ptr peerLight = std::unique_ptr(initializeLightPeer(map, coreLight)); + auto result = peerLight->createJavaPeer(env); + peerLight.release(); + return result; +} + +jni::Local> Light::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); +} + +void Light::setAnchor(jni::JNIEnv& env, const jni::String& property) { + std::string anchorStr = jni::Make(env, property); + if (anchorStr.compare("map") == 0) { + light.setAnchor(LightAnchorType::Map); + } else if (anchorStr.compare("viewport") == 0) { + light.setAnchor(LightAnchorType::Viewport); + } +} + +jni::Local Light::getAnchor(jni::JNIEnv& env) { + auto anchorType = light.getAnchor(); + if (anchorType == LightAnchorType::Map) { + return jni::Make(env, "map"); + } else { + return jni::Make(env, "viewport"); + } +} + +void Light::setPosition(jni::JNIEnv& env, const jni::Object& jposition) { + using namespace mbgl::android::conversion; + auto position = *convert(env, jposition); + light.setPosition(position); +} + +jni::Local> Light::getPosition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::Position position = light.getPosition().asConstant(); + return std::move(*convert>>(env, position)); +} + +jni::Local> Light::getPositionTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getPositionTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setPositionTransition(options); +} + +void Light::setColor(jni::JNIEnv& env, const jni::String& property) { + auto color = Color::parse(jni::Make(env, property)); + if (color) { + light.setColor(color.value()); + } +} + +jni::Local Light::getColor(jni::JNIEnv &env) { + auto color = light.getColor().asConstant(); + return jni::Make(env, color.stringify()); +} + +jni::Local> Light::getColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getColorTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setColorTransition(options); +} + +void Light::setIntensity(jni::JNIEnv&, jni::jfloat property) { + light.setIntensity(property); +} + +jni::jfloat Light::getIntensity(jni::JNIEnv&) { + return light.getIntensity().asConstant(); +} + +jni::Local> Light::getIntensityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getIntensityTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setIntensityTransition(options); +} + +void Light::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&Light::getAnchor, "nativeGetAnchor"), + METHOD(&Light::setAnchor, "nativeSetAnchor"), + METHOD(&Light::getPositionTransition, "nativeGetPositionTransition"), + METHOD(&Light::setPositionTransition, "nativeSetPositionTransition"), + METHOD(&Light::getPosition, "nativeGetPosition"), + METHOD(&Light::setPosition, "nativeSetPosition"), + METHOD(&Light::getColorTransition, "nativeGetColorTransition"), + METHOD(&Light::setColorTransition, "nativeSetColorTransition"), + METHOD(&Light::getColor, "nativeGetColor"), + METHOD(&Light::setColor, "nativeSetColor"), + METHOD(&Light::getIntensityTransition, "nativeGetIntensityTransition"), + METHOD(&Light::setIntensityTransition, "nativeSetIntensityTransition"), + METHOD(&Light::getIntensity, "nativeGetIntensity"), + METHOD(&Light::setIntensity, "nativeSetIntensity")); +} + +} // namespace android +} // namespace mb diff --git a/src/style/light.hpp b/src/style/light.hpp new file mode 100644 index 000000000..97767c4f7 --- /dev/null +++ b/src/style/light.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include +#include +#include "transition_options.hpp" +#include "position.hpp" +#include +#include + +namespace mbgl { +namespace android { + +using namespace style; + +class Light : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; }; + + static void registerNative(jni::JNIEnv&); + + static jni::Local> createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&); + + Light(mbgl::Map&, mbgl::style::Light&); + + void setAnchor(jni::JNIEnv&, const jni::String&); + jni::Local getAnchor(jni::JNIEnv&); + void setPosition(jni::JNIEnv&, const jni::Object&); + jni::Local> getPosition(jni::JNIEnv&); + void setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getPositionTransition(jni::JNIEnv&); + void setColor(jni::JNIEnv&, const jni::String&); + jni::Local getColor(jni::JNIEnv&); + void setColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getColorTransition(jni::JNIEnv&); + void setIntensity(jni::JNIEnv&, jni::jfloat); + jni::jfloat getIntensity(jni::JNIEnv&); + void setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIntensityTransition(jni::JNIEnv&); + jni::Local> createJavaPeer(jni::JNIEnv&); + +protected: + + // Raw reference to the light + mbgl::style::Light& light; + + // Map is set when the light is retrieved + mbgl::Map* map; +}; +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/position.cpp b/src/style/position.cpp new file mode 100644 index 000000000..326310be0 --- /dev/null +++ b/src/style/position.cpp @@ -0,0 +1,35 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { + +jni::Local> Position::fromPosition(jni::JNIEnv& env, jfloat radialCoordinate, jfloat azimuthalAngle, jfloat polarAngle) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jfloat, jfloat, jfloat)>(env, "fromPosition"); + return javaClass.Call(env, method, radialCoordinate, azimuthalAngle, polarAngle); +} + +void Position::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +float Position::getRadialCoordinate(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "radialCoordinate"); + return position.Get(env, field); +} + +float Position::getAzimuthalAngle(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "azimuthalAngle"); + return position.Get(env, field); +} + +float Position::getPolarAngle(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "polarAngle"); + return position.Get(env, field); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/position.hpp b/src/style/position.hpp new file mode 100644 index 000000000..eb4f5ac67 --- /dev/null +++ b/src/style/position.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class Position : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Position"; }; + + static jni::Local> fromPosition(jni::JNIEnv&, jfloat, jfloat, jfloat); + + static void registerNative(jni::JNIEnv&); + + static float getRadialCoordinate(jni::JNIEnv&, const jni::Object&); + static float getAzimuthalAngle(jni::JNIEnv&, const jni::Object&); + static float getPolarAngle(jni::JNIEnv&, const jni::Object&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/sources/custom_geometry_source.cpp b/src/style/sources/custom_geometry_source.cpp new file mode 100644 index 000000000..dccca4cf4 --- /dev/null +++ b/src/style/sources/custom_geometry_source.cpp @@ -0,0 +1,210 @@ +#include "custom_geometry_source.hpp" +#include "../../attach_env.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include + +#include + +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a CustomGeometrySourceOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. + static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env, + const jni::Object<>& options, + style::TileFunction fetchFn, + style::TileFunction cancelFn) { + using namespace mbgl::style::conversion; + if (!options) { + return style::CustomGeometrySource::Options(); + } + Error error; + optional result = convert(Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + result->fetchTileFunction = fetchFn; + result->cancelTileFunction = cancelFn; + return *result; + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + const jni::String& sourceId, + const jni::Object<>& options) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + convertCustomGeometrySourceOptions(env, options, + std::bind(&CustomGeometrySource::fetchTile, this, std::placeholders::_1), + std::bind(&CustomGeometrySource::cancelTile, this, std::placeholders::_1)))) { + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + CustomGeometrySource::~CustomGeometrySource() { + releaseThreads(); + } + + void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto fetchTile = javaClass.GetMethod(*_env, "fetchTile"); + + // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. + // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. + // See https://github.com/mapbox/mapbox-gl-native/issues/12551. + if(!javaPeer) { + return; + } + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::cancelTile(const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto cancelTile = javaClass.GetMethod(*_env, "cancelTile"); + + // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. + // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. + // See https://github.com/mapbox/mapbox-gl-native/issues/12551. + if(!javaPeer) { + return; + } + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::startThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto startThreads = javaClass.GetMethod(*_env, "startThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, startThreads); + } + + void CustomGeometrySource::releaseThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto releaseThreads = javaClass.GetMethod(*_env, "releaseThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, releaseThreads); + }; + + bool CustomGeometrySource::isCancelled(jni::jint z, + jni::jint x, + jni::jint y) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto isCancelled = javaClass.GetMethod(*_env, "isCancelled"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + return peer.Call(*_env, isCancelled, z, x, y); + }; + + void CustomGeometrySource::setTileData(jni::JNIEnv& env, + jni::jint z, + jni::jint x, + jni::jint y, + const jni::Object& jFeatures) { + using namespace mbgl::android::geojson; + + // Convert the jni object + auto geometry = geojson::FeatureCollection::convert(env, jFeatures); + + // Update the core source if not cancelled + if (!isCancelled(z, x ,y)) { + source.as()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); + } + } + + void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) { + source.as()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); + } + + void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, const jni::Object& jBounds) { + auto bounds = LatLngBounds::getLatLngBounds(env, jBounds); + source.as()->CustomGeometrySource::invalidateRegion(bounds); + } + + jni::Local>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local> CustomGeometrySource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void CustomGeometrySource::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + Source::addToMap(env, obj, map, frontend); + startThreads(); + } + + bool CustomGeometrySource::removeFromMap(JNIEnv& env, const jni::Object& source, mbgl::Map& map) { + bool successfullyRemoved = Source::removeFromMap(env, source, map); + if (successfullyRemoved) { + releaseThreads(); + } + return successfullyRemoved; + } + + void CustomGeometrySource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&CustomGeometrySource::querySourceFeatures, "querySourceFeatures"), + METHOD(&CustomGeometrySource::setTileData, "nativeSetTileData"), + METHOD(&CustomGeometrySource::invalidateTile, "nativeInvalidateTile"), + METHOD(&CustomGeometrySource::invalidateBounds, "nativeInvalidateBounds") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/custom_geometry_source.hpp b/src/style/sources/custom_geometry_source.hpp new file mode 100644 index 000000000..52e4027dd --- /dev/null +++ b/src/style/sources/custom_geometry_source.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "source.hpp" +#include +#include +#include +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include "../../geometry/lat_lng_bounds.hpp" +#include + +namespace mbgl { +namespace android { + +class CustomGeometrySource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/CustomGeometrySource"; }; + + static void registerNative(jni::JNIEnv&); + + CustomGeometrySource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + CustomGeometrySource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + ~CustomGeometrySource(); + + bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&) override; + void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&) override; + + void fetchTile(const mbgl::CanonicalTileID& tileID); + void cancelTile(const mbgl::CanonicalTileID& tileID); + bool isCancelled(jni::jint z, jni::jint x, jni::jint y); + void startThreads(); + void releaseThreads(); + +private: + void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, const jni::Object& jf); + + void invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y); + void invalidateBounds(jni::JNIEnv& env, const jni::Object& bounds); + + jni::Local>> querySourceFeatures(jni::JNIEnv&, + const jni::Array>& ); + + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class CustomGeometrySource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/geojson_source.cpp b/src/style/sources/geojson_source.cpp new file mode 100644 index 000000000..5ff486427 --- /dev/null +++ b/src/style/sources/geojson_source.cpp @@ -0,0 +1,265 @@ +#include "geojson_source.hpp" +#include "../../attach_env.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" +#include +#include +#include + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +// GeoJSONSource uses a "coalescing" model for high frequency asynchronous data update calls, +// which in practice means, that any update that started processing is going to finish +// and the last scheduled update is going to finish as well. Any updates scheduled during processing can be canceled. +// Conversion from Java features to core ones is done on a worker thread and once finished, +// the ownership of the converted features is returned to the calling thread. +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a GeoJsonOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. + static style::GeoJSONOptions convertGeoJSONOptions(jni::JNIEnv& env, const jni::Object<>& options) { + using namespace mbgl::style::conversion; + if (!options) { + return style::GeoJSONOptions(); + } + Error error; + optional result = convert( + mbgl::android::Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + return *result; + } + + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& options) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + convertGeoJSONOptions(env, options))) + , converter(std::make_unique>(Scheduler::GetBackground())) { + } + + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) + , converter(std::make_unique>(Scheduler::GetBackground())) { + } + + GeoJSONSource::~GeoJSONSource() = default; + + void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, const jni::String& jString) { + + std::shared_ptr json = std::make_shared(jni::Make(env, jString)); + + Update::Converter converterFn = [this, json](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertJson, json, _callback); + }; + + setAsync(converterFn); + } + + void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, const jni::Object& jFeatures) { + setCollectionAsync(env, jFeatures); + } + + void GeoJSONSource::setFeature(jni::JNIEnv& env, const jni::Object& jFeature) { + setCollectionAsync(env, jFeature); + } + + void GeoJSONSource::setGeometry(jni::JNIEnv& env, const jni::Object& jGeometry) { + setCollectionAsync(env, jGeometry); + } + + void GeoJSONSource::setURL(jni::JNIEnv& env, const jni::String& url) { + // Update the core source + source.as()->GeoJSONSource::setURL(jni::Make(env, url)); + } + + jni::Local GeoJSONSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->GeoJSONSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local>> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), + { {}, toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local>> GeoJSONSource::getClusterChildren(jni::JNIEnv& env, const jni::Object& feature) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + const auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "children", {}); + if (featureExtension.is()) { + return Feature::convert(env, featureExtension.get()); + } + } + return jni::Array>::New(env, 0); + } + + jni::Local>> GeoJSONSource::getClusterLeaves(jni::JNIEnv& env, const jni::Object& feature, jni::jlong limit, jni::jlong offset) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + const std::map options = { {"limit", static_cast(limit)}, + {"offset", static_cast(offset)} }; + auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "leaves", options); + if (featureExtension.is()) { + return Feature::convert(env, featureExtension.get()); + } + } + return jni::Array>::New(env, 0);; + } + + jint GeoJSONSource::getClusterExpansionZoom(jni::JNIEnv& env, const jni::Object& feature) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "expansion-zoom", {}); + if (featureExtension.is()) { + auto value = featureExtension.get(); + if (value.is()) { + return value.get(); + } + } + } + return 0; + } + + jni::Local> GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + template + void GeoJSONSource::setCollectionAsync(jni::JNIEnv& env, const jni::Object& jObject) { + auto global = jni::NewGlobal(env, jObject); + auto object = std::make_shared(std::move(global)); + + Update::Converter converterFn = [this, object](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertObject, object, _callback); + }; + + setAsync(converterFn); + } + + void GeoJSONSource::setAsync(Update::Converter converterFn) { + awaitingUpdate = std::make_unique( + std::move(converterFn), + std::make_unique>( + *Scheduler::GetCurrent(), + [this](GeoJSON geoJSON) { + // conversion from Java features to core ones finished + android::UniqueEnv _env = android::AttachEnv(); + + // Update the core source + source.as()->GeoJSONSource::setGeoJSON(geoJSON); + + // if there is an awaiting update, execute it, otherwise, release resources + if (awaitingUpdate) { + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } else { + update.reset(); + } + }) + ); + + // If another update is running, wait + if (update) { + return; + } + + // no updates are being processed, execute this one + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } + + void GeoJSONSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&GeoJSONSource::setGeoJSONString, "nativeSetGeoJsonString"), + METHOD(&GeoJSONSource::setFeatureCollection, "nativeSetFeatureCollection"), + METHOD(&GeoJSONSource::setFeature, "nativeSetFeature"), + METHOD(&GeoJSONSource::setGeometry, "nativeSetGeometry"), + METHOD(&GeoJSONSource::setURL, "nativeSetUrl"), + METHOD(&GeoJSONSource::getURL, "nativeGetUrl"), + METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures"), + METHOD(&GeoJSONSource::getClusterChildren, "nativeGetClusterChildren"), + METHOD(&GeoJSONSource::getClusterLeaves, "nativeGetClusterLeaves"), + METHOD(&GeoJSONSource::getClusterExpansionZoom, "nativeGetClusterExpansionZoom") + ); + } + + void FeatureConverter::convertJson(std::shared_ptr json, + ActorRef callback) { + using namespace mbgl::style::conversion; + + android::UniqueEnv _env = android::AttachEnv(); + + // Convert the jni object + Error error; + optional converted = parseGeoJSON(*json, error); + if(!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); + return; + } + + callback.invoke(&Callback::operator(), *converted); + } + + template + void FeatureConverter::convertObject(std::shared_ptr, jni::EnvAttachingDeleter>> jObject, ActorRef callback) { + using namespace mbgl::android::geojson; + + android::UniqueEnv _env = android::AttachEnv(); + // Convert the jni object + auto geometry = JNIType::convert(*_env, *jObject); + callback.invoke(&Callback::operator(), GeoJSON(geometry)); + } + + Update::Update(Converter _converterFn, std::unique_ptr> _callback) + : converterFn(std::move(_converterFn)) + , callback(std::move(_callback)) {} + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/geojson_source.hpp b/src/style/sources/geojson_source.hpp new file mode 100644 index 000000000..e737e4192 --- /dev/null +++ b/src/style/sources/geojson_source.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "source.hpp" +#include +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include "../../android_renderer_frontend.hpp" +#include + +namespace mbgl { +namespace android { + +using Callback = std::function; + +struct FeatureConverter { + void convertJson(std::shared_ptr, ActorRef); + + template + void convertObject(std::shared_ptr, jni::EnvAttachingDeleter>>, ActorRef); +}; + +struct Update { + using Converter = std::function)>; + Converter converterFn; + + std::unique_ptr> callback; + + Update(Converter, std::unique_ptr>); +}; + +class GeoJSONSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/GeoJsonSource"; }; + + static void registerNative(jni::JNIEnv&); + + GeoJSONSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + GeoJSONSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + ~GeoJSONSource(); + +private: + void setGeoJSONString(jni::JNIEnv&, const jni::String&); + void setFeatureCollection(jni::JNIEnv&, const jni::Object&); + void setFeature(jni::JNIEnv&, const jni::Object&); + void setGeometry(jni::JNIEnv&, const jni::Object&); + void setURL(jni::JNIEnv&, const jni::String&); + + jni::Local>> querySourceFeatures(jni::JNIEnv&, + const jni::Array>&); + + jni::Local>> getClusterChildren(jni::JNIEnv&, const jni::Object&); + jni::Local>> getClusterLeaves(jni::JNIEnv&, const jni::Object&, jni::jlong, jni::jlong); + jint getClusterExpansionZoom(jni::JNIEnv&, const jni::Object&); + + jni::Local getURL(jni::JNIEnv&); + + jni::Local> createJavaPeer(jni::JNIEnv&); + std::unique_ptr awaitingUpdate; + std::unique_ptr update; + std::shared_ptr threadPool; + std::unique_ptr> converter; + + template + void setCollectionAsync(jni::JNIEnv&, const jni::Object&); + + void setAsync(Update::Converter); + +}; // class GeoJSONSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/image_source.cpp b/src/style/sources/image_source.cpp new file mode 100644 index 000000000..b42e0e5a5 --- /dev/null +++ b/src/style/sources/image_source.cpp @@ -0,0 +1,79 @@ +#include "image_source.hpp" + +// Java -> C++ conversion +#include "../android_conversion.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include +#include + +#include "../../bitmap.hpp" +#include +#include + +namespace mbgl { +namespace android { + + ImageSource::ImageSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object& coordinatesObject) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + LatLngQuad::getLatLngArray(env, coordinatesObject) + ) + ) { + } + + ImageSource::ImageSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + ImageSource::~ImageSource() = default; + + void ImageSource::setURL(jni::JNIEnv& env, const jni::String& url) { + // Update the core source + source.as()->ImageSource::setURL(jni::Make(env, url)); + } + + jni::Local ImageSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->ImageSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + void ImageSource::setImage(jni::JNIEnv& env, const jni::Object& bitmap) { + source.as()->setImage(Bitmap::GetImage(env, bitmap)); + } + + void ImageSource::setCoordinates(jni::JNIEnv& env, const jni::Object& coordinatesObject) { + source.as()->setCoordinates( + LatLngQuad::getLatLngArray(env, coordinatesObject)); + } + + jni::Local> ImageSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void ImageSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&ImageSource::setURL, "nativeSetUrl"), + METHOD(&ImageSource::getURL, "nativeGetUrl"), + METHOD(&ImageSource::setImage, "nativeSetImage"), + METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/image_source.hpp b/src/style/sources/image_source.hpp new file mode 100644 index 000000000..6c359bf0e --- /dev/null +++ b/src/style/sources/image_source.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "source.hpp" +#include "../../geometry/lat_lng_quad.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class Bitmap; + +class ImageSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; }; + + static void registerNative(jni::JNIEnv&); + + ImageSource(jni::JNIEnv&, const jni::String&, const jni::Object&); + + ImageSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + ~ImageSource(); + + void setURL(jni::JNIEnv&, const jni::String&); + jni::Local getURL(jni::JNIEnv&); + + void setImage(jni::JNIEnv&, const jni::Object&); + + void setCoordinates(jni::JNIEnv&, const jni::Object&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class ImageSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/raster_dem_source.cpp b/src/style/sources/raster_dem_source.cpp new file mode 100644 index 000000000..f60526a9b --- /dev/null +++ b/src/style/sources/raster_dem_source.cpp @@ -0,0 +1,62 @@ +#include "raster_dem_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" +#include "source.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + RasterDEMSource::~RasterDEMSource() = default; + + jni::Local RasterDEMSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->RasterDEMSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local> RasterDEMSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void RasterDEMSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&, jni::jint>, + "initialize", + "finalize", + METHOD(&RasterDEMSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/raster_dem_source.hpp b/src/style/sources/raster_dem_source.hpp new file mode 100644 index 000000000..0b31c4ecd --- /dev/null +++ b/src/style/sources/raster_dem_source.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class RasterDEMSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterDemSource"; }; + + static void registerNative(jni::JNIEnv&); + + RasterDEMSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); + RasterDEMSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + ~RasterDEMSource(); + + jni::Local getURL(jni::JNIEnv&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class RasterDEMSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/raster_source.cpp b/src/style/sources/raster_source.cpp new file mode 100644 index 000000000..535f899c9 --- /dev/null +++ b/src/style/sources/raster_source.cpp @@ -0,0 +1,61 @@ +#include "raster_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + RasterSource::RasterSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterSource::RasterSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + RasterSource::~RasterSource() = default; + + jni::Local RasterSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->RasterSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local> RasterSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void RasterSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&, jni::jint>, + "initialize", + "finalize", + METHOD(&RasterSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/raster_source.hpp b/src/style/sources/raster_source.hpp new file mode 100644 index 000000000..08648f79a --- /dev/null +++ b/src/style/sources/raster_source.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class RasterSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterSource"; }; + + static void registerNative(jni::JNIEnv&); + + RasterSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); + RasterSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + ~RasterSource(); + + jni::Local getURL(jni::JNIEnv&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class RasterSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/source.cpp b/src/style/sources/source.cpp new file mode 100644 index 000000000..be4c0367f --- /dev/null +++ b/src/style/sources/source.cpp @@ -0,0 +1,168 @@ +#include "source.hpp" +#include "../android_conversion.hpp" +#include "../../attach_env.hpp" + +#include + +#include +#include + +// Java -> C++ conversion +#include +#include + +// C++ -> Java conversion +#include "../conversion/property_value.hpp" + +#include + +// Core Sources +#include +#include +#include +#include + +// Android Source peers +#include "geojson_source.hpp" +#include "image_source.hpp" +#include "raster_source.hpp" +#include "unknown_source.hpp" +#include "vector_source.hpp" +#include "custom_geometry_source.hpp" +#include "raster_dem_source.hpp" + +namespace mbgl { +namespace android { + + static std::unique_ptr createSourcePeer(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else { + return std::make_unique(env, coreSource, frontend); + } + } + + const jni::Object& Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (!coreSource.peer.has_value()) { + coreSource.peer = createSourcePeer(env, coreSource, frontend); + } + return coreSource.peer.get>()->javaPeer; + } + + Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, const jni::Object& obj, AndroidRendererFrontend& frontend) + : source(coreSource) + , javaPeer(jni::NewGlobal(env, obj)) + , rendererFrontend(&frontend) { + } + + Source::Source(jni::JNIEnv&, std::unique_ptr coreSource) + : ownedSource(std::move(coreSource)) + , source(*ownedSource) { + } + + Source::~Source() { + // Before being added to a map, the Java peer owns this C++ peer and cleans + // up after itself correctly through the jni native peer bindings. + // After being added to the map, the ownership is flipped and the C++ peer has a strong reference + // to it's Java peer, preventing the Java peer from being GC'ed. + // In this case, the core source initiates the destruction, which requires releasing the Java peer, + // while also resetting it's nativePtr to 0 to prevent the subsequent GC of the Java peer from + // re-entering this dtor. + if (ownedSource.get() == nullptr && javaPeer.get() != nullptr) { + // Manually clear the java peer + android::UniqueEnv env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*env); + static auto nativePtrField = javaClass.GetField(*env, "nativePtr"); + javaPeer.Set(*env, nativePtrField, (jlong) 0); + javaPeer.reset(); + } + } + + jni::Local Source::getId(jni::JNIEnv& env) { + return jni::Make(env, source.getID()); + } + + jni::Local Source::getAttribution(jni::JNIEnv& env) { + auto attribution = source.getAttribution(); + return attribution ? jni::Make(env, attribution.value()) : jni::Make(env,""); + } + + void Source::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + // Check to see if we own the source first + if (!ownedSource) { + throw std::runtime_error("Cannot add source twice"); + } + + // Add source to map and release ownership + map.getStyle().addSource(std::move(ownedSource)); + + // Add peer to core source + source.peer = std::unique_ptr(this); + + // Add strong reference to java source + javaPeer = jni::NewGlobal(env, obj); + + rendererFrontend = &frontend; + } + + bool Source::removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map& map) { + // Cannot remove if not attached yet + if (ownedSource) { + throw std::runtime_error("Cannot remove detached source"); + } + + // Remove the source from the map and take ownership + ownedSource = map.getStyle().removeSource(source.getID()); + + // The source may not be removed if any layers still reference it + return ownedSource != nullptr; + } + + void Source::releaseJavaPeer() { + // We can't release the peer if the source was not removed from the map + if (!ownedSource) { + return; + } + + // Release the peer relationships. These will be re-established when the source is added to a map + assert(ownedSource->peer.has_value()); + ownedSource->peer.get>().release(); + ownedSource->peer = util::peer(); + + // Release the strong reference to the java peer + assert(javaPeer); + javaPeer.release(); + + rendererFrontend = nullptr; + } + + void Source::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&Source::getId, "nativeGetId"), + METHOD(&Source::getAttribution, "nativeGetAttribution") + ); + + // Register subclasses + GeoJSONSource::registerNative(env); + ImageSource::registerNative(env); + RasterSource::registerNative(env); + UnknownSource::registerNative(env); + VectorSource::registerNative(env); + CustomGeometrySource::registerNative(env); + RasterDEMSource::registerNative(env); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/source.hpp b/src/style/sources/source.hpp new file mode 100644 index 000000000..93b706425 --- /dev/null +++ b/src/style/sources/source.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +#include "../value.hpp" +#include "../../android_renderer_frontend.hpp" + +#include + +namespace mbgl { +namespace android { + +class Source : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/Source"; }; + + static void registerNative(jni::JNIEnv&); + + static const jni::Object& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + /* + * Called when a Java object is created for a core source that belongs to a map. + */ + Source(jni::JNIEnv&, mbgl::style::Source&, const jni::Object&, AndroidRendererFrontend&); + + /* + * Called when a Java object is created for a new core source that does not belong to a map. + */ + Source(jni::JNIEnv&, std::unique_ptr); + + virtual ~Source(); + + virtual void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&); + + virtual bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&); + + void releaseJavaPeer(); + + jni::Local getId(jni::JNIEnv&); + + jni::Local getAttribution(jni::JNIEnv&); + +protected: + // Set on newly created sources until added to the map. + std::unique_ptr ownedSource; + + // Raw pointer that is valid at all times. + mbgl::style::Source& source; + + // Set when the source is added to a map. + jni::Global> javaPeer; + + // RendererFrontend pointer is valid only when added to the map. + AndroidRendererFrontend* rendererFrontend { nullptr }; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/unknown_source.cpp b/src/style/sources/unknown_source.cpp new file mode 100644 index 000000000..b5285a5f9 --- /dev/null +++ b/src/style/sources/unknown_source.cpp @@ -0,0 +1,43 @@ +#include "unknown_source.hpp" + +namespace { + + // Dummy initializer (We don't support initializing this from the JVM) + std::unique_ptr init(jni::JNIEnv&) { + throw std::runtime_error("UnknownSource should not be initialized from the JVM"); + } + +} // namespace + +namespace mbgl { +namespace android { + + UnknownSource::UnknownSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + jni::Local> UnknownSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void UnknownSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + init, + "initialize", + "finalize" + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/unknown_source.hpp b/src/style/sources/unknown_source.hpp new file mode 100644 index 000000000..f042e2042 --- /dev/null +++ b/src/style/sources/unknown_source.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class UnknownSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/UnknownSource"; }; + + static void registerNative(jni::JNIEnv&); + + UnknownSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + ~UnknownSource() = default; + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class UnknownSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/vector_source.cpp b/src/style/sources/vector_source.cpp new file mode 100644 index 000000000..e46fc1a94 --- /dev/null +++ b/src/style/sources/vector_source.cpp @@ -0,0 +1,84 @@ +#include "vector_source.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +#include +#include + +namespace mbgl { +namespace android { + + VectorSource::VectorSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)) + ) + ) { + } + + VectorSource::VectorSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + VectorSource::~VectorSource() = default; + + jni::Local VectorSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->VectorSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local>> VectorSource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array& jSourceLayerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), + { toVector(env, jSourceLayerIds), toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local> VectorSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void VectorSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&VectorSource::querySourceFeatures, "querySourceFeatures"), + METHOD(&VectorSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/src/style/sources/vector_source.hpp b/src/style/sources/vector_source.hpp new file mode 100644 index 000000000..4cb46c6c6 --- /dev/null +++ b/src/style/sources/vector_source.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "source.hpp" +#include +#include "../../geojson/feature.hpp" +#include + +namespace mbgl { +namespace android { + +class VectorSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/VectorSource"; }; + + static void registerNative(jni::JNIEnv&); + + VectorSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + VectorSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + ~VectorSource(); + +private: + jni::Local>> querySourceFeatures(jni::JNIEnv&, const jni::Array&, + const jni::Array>& jfilter); + + jni::Local getURL(jni::JNIEnv&); + + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class VectorSource + +} // namespace android +} // namespace mbgl diff --git a/src/style/transition_options.cpp b/src/style/transition_options.cpp new file mode 100644 index 000000000..d70a04e0d --- /dev/null +++ b/src/style/transition_options.cpp @@ -0,0 +1,35 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { + +jni::Local> TransitionOptions::fromTransitionOptions(jni::JNIEnv& env, jlong duration, jlong delay, jboolean enablePlacementTransitions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jlong, jlong, jboolean)>(env, "fromTransitionOptions"); + return javaClass.Call(env, method, duration, delay, enablePlacementTransitions); +} + +long TransitionOptions::getDuration(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "duration"); + return transitionOptions.Get(env, field); +} + +long TransitionOptions::getDelay(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "delay"); + return transitionOptions.Get(env, field); +} + +bool TransitionOptions::isEnablePlacementTransitions(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "enablePlacementTransitions"); + return transitionOptions.Get(env, field); +} + +void TransitionOptions::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/transition_options.hpp b/src/style/transition_options.hpp new file mode 100644 index 000000000..58656a946 --- /dev/null +++ b/src/style/transition_options.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class TransitionOptions : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TransitionOptions"; }; + + static jni::Local> fromTransitionOptions(jni::JNIEnv&, jlong duration, jlong delay, jboolean enablePlacementTransitions); + + static long getDuration(jni::JNIEnv&, const jni::Object&); + + static long getDelay(jni::JNIEnv&, const jni::Object&); + + static bool isEnablePlacementTransitions(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/src/style/value.cpp b/src/style/value.cpp new file mode 100644 index 000000000..2f0484072 --- /dev/null +++ b/src/style/value.cpp @@ -0,0 +1,83 @@ +#include "value.hpp" + +#include "../java_types.hpp" + +namespace mbgl { +namespace android { + // Instance + + Value::Value(jni::JNIEnv& _env, jni::Local> _value) + : env(_env), + value(std::move(_value)) {} + + Value::Value(jni::JNIEnv& _env, const jni::Object<>& _value) + : env(_env), + value(jni::NewLocal(_env, _value)) {} + + bool Value::isNull() const { + return !value; + } + + bool Value::isArray() const { + return jni::IsInstanceOf(env, value.get(), *java::ObjectArray::jclass); + } + + bool Value::isObject() const { + return jni::IsInstanceOf(env, value.get(), *java::Map::jclass); + } + + bool Value::isString() const { + return jni::IsInstanceOf(env, value.get(), *java::String::jclass); + } + + bool Value::isBool() const { + return jni::IsInstanceOf(env, value.get(), *java::Boolean::jclass); + } + + bool Value::isNumber() const { + return jni::IsInstanceOf(env, value.get(), *java::Number::jclass); + } + + std::string Value::toString() const { + return jni::Make(env, jni::Cast(env, jni::Class::Singleton(env), value)); + } + + float Value::toFloat() const { + return jni::CallMethod(env, value.get(), *java::Number::floatValueMethodId); + } + + double Value::toDouble() const { + return jni::CallMethod(env, value.get(), *java::Number::doubleValueMethodId); + } + + long Value::toLong() const { + return jni::CallMethod(env, value.get(), *java::Number::longValueMethodId); + } + + bool Value::toBool() const { + return jni::CallMethod(env, value.get(), *java::Boolean::booleanValueMethodId); + } + + Value Value::get(const char* key) const { + jni::jobject* member = jni::CallMethod(env, value.get(), *java::Map::getMethodId, jni::Make(env, std::string(key)).get()); + return Value(env, jni::Local>(env, member)); + } + + Value Value::keyArray() const{ + jni::jobject* set = jni::CallMethod(env, value.get(), *java::Map::keySetMethodId); + jni::jobject* array = jni::CallMethod(env, set, *java::Set::toArrayMethodId); + return Value(env, jni::Local>(env, array)); + } + + int Value::getLength() const { + auto array = (jni::jarray*) value.get(); + return jni::GetArrayLength(env, *array); + } + + Value Value::get(const int index) const { + auto array = (jni::jarray*) value.get(); + return Value(env, jni::Local>(env, jni::GetObjectArrayElement(env, *array, index))); + } +} +} + diff --git a/src/style/value.hpp b/src/style/value.hpp new file mode 100644 index 000000000..b507c5ed1 --- /dev/null +++ b/src/style/value.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class Value { +public: + Value(jni::JNIEnv&, jni::Local>); + Value(jni::JNIEnv&, const jni::Object<>&); + + Value(Value&&) = default; + Value& operator=(Value&&) = delete; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; + + bool isNull() const; + bool isArray() const; + bool isObject() const; + bool isString() const; + bool isBool() const; + bool isNumber() const; + + std::string toString() const; + float toFloat() const; + double toDouble() const; + long toLong() const; + bool toBool() const; + Value get(const char* key) const; + Value keyArray() const; + int getLength() const; + Value get(const int index ) const; + + jni::JNIEnv& env; + jni::Local> value; +}; + +} +} diff --git a/src/test/benchmark_runner.cpp b/src/test/benchmark_runner.cpp new file mode 100644 index 000000000..321a37a02 --- /dev/null +++ b/src/test/benchmark_runner.cpp @@ -0,0 +1,10 @@ +#include "runtime.hpp" +#include + +int main(int argc, char *argv[]) { + if (!mbgl::android::initRuntime(argc, argv)) { + return 1; + } + + return mbgl::runBenchmark(argc, argv); +} diff --git a/src/test/runtime.cpp b/src/test/runtime.cpp new file mode 100644 index 000000000..1f8f16da3 --- /dev/null +++ b/src/test/runtime.cpp @@ -0,0 +1,74 @@ +#include "runtime.hpp" +#include "../jni.hpp" +#include "../jni_native.hpp" + +#include +#include +#include +#include +#include + +// Required for art / libsigchain +extern "C" JNIEXPORT void EnsureFrontOfChain(int, struct sigaction*) { } +extern "C" JNIEXPORT void AddSpecialSignalHandlerFn(int, void*) { } +extern "C" JNIEXPORT void RemoveSpecialSignalHandlerFn(int, bool (*) (int, siginfo_t*, void*)) { } + +namespace { +const std::string kClassPathCommand{"--class_path="}; +const std::string kClassPath{"-Djava.class.path="}; +const std::string kDefaultDex{"/data/local/tmp/core-tests/classes.dex"}; +} // namespace + +namespace mbgl { +namespace android { + +bool initRuntime(int argc, char *argv[]) { + void* vmHandle = dlopen("libart.so", RTLD_NOW); + assert(vmHandle != nullptr); + + using CreateJavaVMFn = jint (*)(JavaVM** vm, JNIEnv** env, void* vmArgs); + CreateJavaVMFn createJavaVMFn = reinterpret_cast(dlsym(vmHandle, "JNI_CreateJavaVM")); + assert(createJavaVMFn != nullptr); + + std::string classPath = kClassPath + kDefaultDex; + for (int i = 0; i < argc; ++i) { + const std::string arg{argv[i]}; + if (arg.compare(0, kClassPathCommand.length(), kClassPathCommand) == 0) { + classPath = kClassPath + arg.substr(kClassPathCommand.length()); + break; + } + } + + JavaVMOption options[1]; + options[0].optionString = classPath.c_str(); + + JavaVMInitArgs args; + args.version = JNI_VERSION_1_6; + args.nOptions = 1; + args.options = options; + args.ignoreUnrecognized = JNI_FALSE; + + JavaVM* vm; + JNIEnv* env; + + if (createJavaVMFn(&vm, &env, &args) != JNI_OK) { + return false; + } + + void* runtimeHandle = dlopen("libandroid_runtime.so", RTLD_NOW); + assert(runtimeHandle != nullptr); + + using RegisterNativesFn = jint (*)(JNIEnv* env); + RegisterNativesFn registerNativesFn = reinterpret_cast(dlsym(runtimeHandle, "registerFrameworkNatives")); + assert(registerNativesFn != nullptr); + + if (registerNativesFn(env) != JNI_OK) { + return false; + } + + mbgl::android::registerNatives(vm); + return true; +} + +} // namespace android +} // namespace mbgl diff --git a/src/test/runtime.hpp b/src/test/runtime.hpp new file mode 100644 index 000000000..c5e69d61c --- /dev/null +++ b/src/test/runtime.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace mbgl { +namespace android { + +bool initRuntime(int argc, char *argv[]); + +} // namespace android +} // namespace mbgl diff --git a/src/test/test_runner.cpp b/src/test/test_runner.cpp new file mode 100644 index 000000000..008e3c574 --- /dev/null +++ b/src/test/test_runner.cpp @@ -0,0 +1,10 @@ +#include "runtime.hpp" +#include + +int main(int argc, char *argv[]) { + if (!mbgl::android::initRuntime(argc, argv)) { + return 1; + } + + mbgl::runTests(argc, argv); +} diff --git a/src/text/collator.cpp b/src/text/collator.cpp new file mode 100644 index 000000000..acb4f36ee --- /dev/null +++ b/src/text/collator.cpp @@ -0,0 +1,199 @@ +#include +#include +#include + +#include + +#include + +#include "../attach_env.hpp" +#include "collator_jni.hpp" + +namespace mbgl { +namespace android { + +void Collator::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setStrength"); + collator.Call(env, method, strength); +} + +jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "compare"); + return collator.Call(env, method, lhs, rhs); +} + +void StringUtils::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(env, "unaccent"); + return javaClass.Call(env, method, value); +} + +void Locale::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +/* +We would prefer to use for/toLanguageTag, but they're only available in API level 21+ + +jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { + using Signature = jni::Object(jni::String); + auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); + return javaClass.Call(env, method, languageTag); +} + +jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { + using Signature = jni::String(); + auto static method = javaClass.GetMethod(env, "toLanguageTag"); + return locale.Call(env, method); +} +*/ + +jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getLanguage"); + return locale.Call(env, method); +} + +jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getCountry"); + return locale.Call(env, method); +} + +jni::Local> Locale::getDefault(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); + return javaClass.Call(env, method); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language, region); +} + +} // namespace android + +namespace style { +namespace expression { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + , env(android::AttachEnv()) + { + LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, + android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); + if (!diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); + } else if (diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); + } else if (caseSensitive) { + // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator + // and a fallback implementation of diacritic-insensitivity. + android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); + } + } + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && + diacriticSensitive == other.diacriticSensitive && + resolvedLocale() == other.resolvedLocale(); + } + + int compare(const std::string& lhs, const std::string& rhs) const { + bool useUnaccent = !diacriticSensitive && caseSensitive; + // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation + // order, so we have to compromise here. We use Android's case-sensitive Collator + // against strings that have been "unaccented" using non-locale-aware nunicode logic. + // Because of the difference in locale-awareness, this means turning on case-sensitivity + // can _potentially_ change compare results for strings that don't actually have any case + // differences. + jni::Local jlhs = jni::Make(*env, useUnaccent ? + platform::unaccent(lhs) : + lhs); + jni::Local jrhs = jni::Make(*env, useUnaccent ? + platform::unaccent(rhs) : + rhs); + + jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); + + return result; + } + + std::string resolvedLocale() const { + std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); + std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); + + optional resultLanguage; + if (!language.empty()) resultLanguage = language; + optional resultRegion; + if (!region.empty()) resultRegion = region; + + return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); + } + +private: + bool caseSensitive; + bool diacriticSensitive; + + android::UniqueEnv env; + jni::Global> collator; + jni::Global> locale; +}; + + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) + : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) +{} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/text/collator_jni.hpp b/src/text/collator_jni.hpp new file mode 100644 index 000000000..dd3f84566 --- /dev/null +++ b/src/text/collator_jni.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include + +/* + android::Collator and android::Locale are + the JNI wrappers of + java/text/Collator and java/util/Locale + + mbgl::Collator is the portable interface + Both implementations are in collator.cpp + */ + +namespace mbgl { +namespace android { + +class Locale { +public: + static constexpr auto Name() { return "java/util/Locale"; }; + + /* Requires API level 21+ in order to support script/variant + static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); + static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); + */ + static jni::Local> getDefault(jni::JNIEnv&); + static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); + static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::String&); + static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +class Collator { +public: + static constexpr auto Name() { return "java/text/Collator"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + + static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); + + static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + + +class StringUtils { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; + + static jni::Local unaccent(jni::JNIEnv&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/text/format_number.cpp b/src/text/format_number.cpp new file mode 100644 index 000000000..3a41175ec --- /dev/null +++ b/src/text/format_number.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +#include + +#include "../attach_env.hpp" +#include "format_number_jni.hpp" + +namespace mbgl { +namespace android { + +void NumberFormat::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "format"); + return nf.Call(env, method, number); +} + +void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); + return nf.Call(env, method, value); +} + +void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); + return nf.Call(env, method, value); +} + +} // namespace android + +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + auto env{ android::AttachEnv() }; + + jni::Global> locale; + LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + + jni::Global> formatter; + if (currency.empty()) { + formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); + android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); + android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); + } else { + formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); + } + + auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); + return jni::Make(*env, result); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/text/format_number_jni.hpp b/src/text/format_number_jni.hpp new file mode 100644 index 000000000..172003892 --- /dev/null +++ b/src/text/format_number_jni.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "collator_jni.hpp" + +/* + android::NumberFormat is the JNI wrapper + of java/text/NumberFormat. + */ + +namespace mbgl { +namespace android { + +class NumberFormat { +public: + static constexpr auto Name() { return "java/text/NumberFormat"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); + static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/text/local_glyph_rasterizer.cpp b/src/text/local_glyph_rasterizer.cpp new file mode 100644 index 000000000..8892ee3f3 --- /dev/null +++ b/src/text/local_glyph_rasterizer.cpp @@ -0,0 +1,130 @@ +#include +#include +#include + +#include + +#include "../attach_env.hpp" +#include "../bitmap.hpp" + +#include "local_glyph_rasterizer_jni.hpp" + +/* + Android implementation of LocalGlyphRasterizer: + Draws CJK glyphs using locally available fonts. + + Follows pattern of GL JS implementation in that: + - Only CJK glyphs are drawn locally (because we can guess their metrics effectively) + * Render size/metrics determined experimentally using Noto Sans + - Configuration is done at map creation time by setting a "font family" + * JS uses a CSS font-family, this uses android.graphics.Typeface + https://developer.android.com/reference/android/graphics/Typeface.html + - We use heuristics to extract a font-weight based on the incoming font stack + * JS tries to extract multiple weights, this implementation only looks for + "bold" + + mbgl::LocalGlyphRasterizer is the portable interface + mbgl::LocalGlyphRasterizer::Impl stores platform-specific configuration data + mbgl::android::LocalGlyphRasterizer is the JNI wrapper + com.mapbox.mapboxsdk.text.LocalGlyphRasterizer is the Java implementation that + actually does the drawing + */ + +namespace mbgl { +namespace android { + +LocalGlyphRasterizer::LocalGlyphRasterizer() { + UniqueEnv env { AttachEnv() }; + + static auto& javaClass = jni::Class::Singleton(*env); + static auto constructor = javaClass.GetConstructor(*env); + + javaObject = jni::NewGlobal(*env, javaClass.New(*env, constructor)); +} + +PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& fontFamily, const bool bold, const GlyphID glyphID) { + UniqueEnv env { AttachEnv() }; + + static auto& javaClass = jni::Class::Singleton(*env); + static auto drawGlyphBitmap = javaClass.GetMethod (jni::String, jni::jboolean, jni::jchar)>(*env, "drawGlyphBitmap"); + + return Bitmap::GetImage(*env, + javaObject.Call(*env, + drawGlyphBitmap, + jni::Make(*env, fontFamily), + static_cast(bold), + static_cast(glyphID))); +} + +void LocalGlyphRasterizer::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android + +class LocalGlyphRasterizer::Impl { +public: + Impl(const optional fontFamily_) + : fontFamily(fontFamily_) + {} + + bool isConfigured() const { + return bool(fontFamily); + } + + PremultipliedImage drawGlyphBitmap(const FontStack& fontStack, GlyphID glyphID) { + bool bold = false; + for (auto font : fontStack) { + std::string lowercaseFont = platform::lowercase(font); + if (lowercaseFont.find("bold") != std::string::npos) { + bold = true; + break; + } + } + return androidLocalGlyphRasterizer.drawGlyphBitmap(*fontFamily, bold, glyphID); + } + +private: + optional fontFamily; + android::LocalGlyphRasterizer androidLocalGlyphRasterizer; +}; + +LocalGlyphRasterizer::LocalGlyphRasterizer(const optional fontFamily) + : impl(std::make_unique(fontFamily)) +{} + +LocalGlyphRasterizer::~LocalGlyphRasterizer() +{} + +bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) { + return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured(); +} + +Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) { + Glyph fixedMetrics; + if (!impl->isConfigured()) { + return fixedMetrics; + } + + fixedMetrics.id = glyphID; + + Size size(35, 35); + + fixedMetrics.metrics.width = size.width; + fixedMetrics.metrics.height = size.height; + fixedMetrics.metrics.left = 3; + fixedMetrics.metrics.top = -10; + fixedMetrics.metrics.advance = 24; + + PremultipliedImage rgbaBitmap = impl->drawGlyphBitmap(fontStack, glyphID); + + // Copy alpha values from RGBA bitmap into the AlphaImage output + fixedMetrics.bitmap = AlphaImage(size); + for (uint32_t i = 0; i < size.width * size.height; i++) { + fixedMetrics.bitmap.data[i] = rgbaBitmap.data[4 * i + 3]; + } + + return fixedMetrics; +} + +} // namespace mbgl diff --git a/src/text/local_glyph_rasterizer_jni.hpp b/src/text/local_glyph_rasterizer_jni.hpp new file mode 100644 index 000000000..e80e84833 --- /dev/null +++ b/src/text/local_glyph_rasterizer_jni.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +/* + android::LocalGlyphRasterizer is the JNI wrapper of + com/mapbox/mapboxsdk/text/LocalGlyphRasterizer + + mbgl::LocalGlyphRasterizer is the portable interface + Both implementations are in local_glyph_rasterizer.cpp + */ + +namespace mbgl { +namespace android { + +class LocalGlyphRasterizer { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/text/LocalGlyphRasterizer"; }; + + static void registerNative(jni::JNIEnv&); + + LocalGlyphRasterizer(); + + PremultipliedImage drawGlyphBitmap(const std::string& fontFamily, const bool bold, const char16_t glyphID); + +private: + jni::Global> javaObject; +}; + +} // namespace android +} // namespace mbgl diff --git a/src/thread.cpp b/src/thread.cpp new file mode 100644 index 000000000..cd0a72306 --- /dev/null +++ b/src/thread.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +#include +#include + +#include +#include "jni.hpp" + +// Implementation based on Chromium's platform_thread_android.cc. + +namespace mbgl { +namespace platform { + +thread_local static JNIEnv* env; +thread_local static bool detach; + +std::string getCurrentThreadName() { + char name[32] = "unknown"; + + if (prctl(PR_GET_NAME, name) == -1) { + Log::Warning(Event::General, "Couldn't get thread name"); + } + + return name; +} + +void setCurrentThreadName(const std::string& name) { + if (prctl(PR_SET_NAME, name.c_str()) == -1) { + Log::Warning(Event::General, "Couldn't set thread name"); + } +} + +void makeThreadLowPriority() { + // ANDROID_PRIORITY_LOWEST = 19 + // + // Supposedly would set the priority for the whole process, but + // on Linux/Android it only sets for the current thread. + setpriority(PRIO_PROCESS, 0, 19); +} + +void attachThread() { + using namespace android; + assert(env == nullptr); + detach = attach_jni_thread(theJVM, &env, platform::getCurrentThreadName()); +} + +void detachThread() { + using namespace android; + assert(env); + detach_jni_thread(theJVM, &env, detach); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/timer.cpp b/src/timer.cpp new file mode 100644 index 000000000..a45c48702 --- /dev/null +++ b/src/timer.cpp @@ -0,0 +1,75 @@ +#include "run_loop_impl.hpp" + +#include +#include + +#include + +namespace mbgl { +namespace util { + +class Timer::Impl : public RunLoop::Impl::Runnable { +public: + Impl() = default; + + ~Impl() { + stop(); + } + + void start(Duration timeout, Duration repeat_, std::function&& task_) { + stop(); + + repeat = repeat_; + task = std::move(task_); + // Prevent overflows when timeout is set to Duration::max() + due = (timeout == Duration::max()) ? std::chrono::time_point::max() : Clock::now() + + timeout; + loop->addRunnable(this); + } + + void stop() { + loop->removeRunnable(this); + } + + void reschedule() { + if (repeat != Duration::zero()) { + due = Clock::now() + repeat; + loop->wake(); + } else { + stop(); + } + } + + TimePoint dueTime() const override { + return due; + } + + void runTask() override { + reschedule(); + task(); + } + +private: + TimePoint due; + Duration repeat; + + RunLoop::Impl* loop = reinterpret_cast(RunLoop::getLoopHandle()); + + std::function task; +}; + +Timer::Timer() : impl(std::make_unique()) { +} + +Timer::~Timer() = default; + +void Timer::start(Duration timeout, Duration repeat, std::function&& cb) { + impl->start(timeout, repeat, std::move(cb)); +} + +void Timer::stop() { + impl->stop(); +} + +} // namespace util +} // namespace mbgl diff --git a/src/unaccent.cpp b/src/unaccent.cpp new file mode 100644 index 000000000..8da0ce493 --- /dev/null +++ b/src/unaccent.cpp @@ -0,0 +1,18 @@ +#include +#include +#include "attach_env.hpp" +#include "text/collator_jni.hpp" +#include + +namespace mbgl { +namespace platform { + +std::string unaccent(const std::string& str) { + android::UniqueEnv env = android::AttachEnv(); + jni::Local input = jni::Make(*env, str); + jni::Local unaccented = android::StringUtils::unaccent(*env, input); + return jni::Make(*env, unaccented); +} + +} // namespace platform +} // namespace mbgl diff --git a/vendor/mapbox-events-android b/vendor/mapbox-events-android new file mode 160000 index 000000000..58fbec16c --- /dev/null +++ b/vendor/mapbox-events-android @@ -0,0 +1 @@ +Subproject commit 58fbec16cdedb909eb63c68e46708fe9268b6fed diff --git a/vendor/mapbox-gestures-android b/vendor/mapbox-gestures-android new file mode 160000 index 000000000..ae08de82c --- /dev/null +++ b/vendor/mapbox-gestures-android @@ -0,0 +1 @@ +Subproject commit ae08de82ca178dca7f005dfc8056554cf77124ad diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native new file mode 160000 index 000000000..89eaac05e --- /dev/null +++ b/vendor/mapbox-gl-native @@ -0,0 +1 @@ +Subproject commit 89eaac05ebc2928e59d3f0404f7b92bdb42b92bb diff --git a/vendor/mapbox-java b/vendor/mapbox-java new file mode 160000 index 000000000..84de2d4b0 --- /dev/null +++ b/vendor/mapbox-java @@ -0,0 +1 @@ +Subproject commit 84de2d4b02e93a9eda9d0254332cd356d17445de From 90b829a22e4d15b9ae5f0f2e22bcada8cc7373a9 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 13:56:35 +0200 Subject: [PATCH 002/185] [build] restore Makefile targets --- Makefile | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..dcff72b4a --- /dev/null +++ b/Makefile @@ -0,0 +1,314 @@ +#### Android targets ########################################################### + +MBGL_ANDROID_ABIS = arm-v7;armeabi-v7a +MBGL_ANDROID_ABIS += arm-v8;arm64-v8a +MBGL_ANDROID_ABIS += x86;x86 +MBGL_ANDROID_ABIS += x86-64;x86_64 + +MBGL_ANDROID_LOCAL_WORK_DIR = /data/local/tmp/core-tests +MBGL_ANDROID_LOCAL_BENCHMARK_DIR = /data/local/tmp/benchmark +MBGL_ANDROID_LIBDIR = lib$(if $(filter arm-v8 x86-64,$1),64) +MBGL_ANDROID_DALVIKVM = dalvikvm$(if $(filter arm-v8 x86-64,$1),64,32) +MBGL_ANDROID_APK_SUFFIX = $(if $(filter Release,$(BUILDTYPE)),release,debug) +MBGL_ANDROID_CORE_TEST_DIR = MapboxGLAndroidSDK/.externalNativeBuild/cmake/$(buildtype)/$2/core-tests +MBGL_ANDROID_BENCHMARK_DIR = MapboxGLAndroidSDK/.externalNativeBuild/cmake/$(buildtype)/$2/benchmark +MBGL_ANDROID_STL ?= c++_static +MBGL_ANDROID_GRADLE = ./gradlew --parallel --max-workers=$(JOBS) -Pmapbox.buildtype=$(buildtype) -Pmapbox.stl=$(MBGL_ANDROID_STL) + +# Lists all devices, and extracts the identifiers, then obtains the ABI for every one. +# Some devices return \r\n, so we'll have to remove the carriage return before concatenating. +MBGL_ANDROID_ACTIVE_ARCHS = $(shell adb devices | sed '1d;/^\*/d;s/[[:space:]].*//' | xargs -n 1 -I DEV `type -P adb` -s DEV shell getprop ro.product.cpu.abi | tr -d '\r') + +# Generate code based on the style specification +.PHONY: android-style-code +android-style-code: + node scripts/generate-style-code.js +style-code: android-style-code + +# Configuration file for running CMake from Gradle within Android Studio. +gradle/configuration.gradle: + @printf "ext {\n node = '`command -v node || command -v nodejs`'\n npm = '`command -v npm`'\n ccache = '`command -v ccache`'\n}" > $@ + +define ANDROID_RULES +# $1 = arm-v7 (short arch) +# $2 = armeabi-v7a (internal arch) + +.PHONY: android-test-lib-$1 +android-test-lib-$1: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 -Pmapbox.with_test=true :MapboxGLAndroidSDKTestApp:assemble$(BUILDTYPE) + +.PHONY: android-benchmark-$1 +android-benchmark-$1: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 -Pmapbox.with_benchmark=true :MapboxGLAndroidSDKTestApp:assemble$(BUILDTYPE) + +# Build SDK for for specified abi +.PHONY: android-lib-$1 +android-lib-$1: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDK:assemble$(BUILDTYPE) + +# Build test app and SDK for for specified abi +.PHONY: android-$1 +android-$1: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:assemble$(BUILDTYPE) + +# Build the core test for specified abi +.PHONY: android-core-test-$1 +android-core-test-$1: android-test-lib-$1 + # Compile main sources and extract the classes (using the test app to get all transitive dependencies in one place) + mkdir -p $(MBGL_ANDROID_CORE_TEST_DIR) + unzip -o MapboxGLAndroidSDKTestApp/build/outputs/apk/$(buildtype)/MapboxGLAndroidSDKTestApp-$(MBGL_ANDROID_APK_SUFFIX).apk classes.dex -d $(MBGL_ANDROID_CORE_TEST_DIR) + +run-android-core-test-$1-%: android-core-test-$1 + # Ensure clean state on the device + adb shell "rm -Rf $(MBGL_ANDROID_LOCAL_WORK_DIR) && mkdir -p $(MBGL_ANDROID_LOCAL_WORK_DIR)/test && mkdir -p $(MBGL_ANDROID_LOCAL_WORK_DIR)/mapbox-gl-js/src/style-spec/reference" + + # Push all needed files to the device + adb push $(MBGL_ANDROID_CORE_TEST_DIR)/classes.dex $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1 + adb push MapboxGLAndroidSDK/build/intermediates/intermediate-jars/$(buildtype)/jni/$2/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1 + adb push test/fixtures $(MBGL_ANDROID_LOCAL_WORK_DIR)/test > /dev/null 2>&1 + adb push mapbox-gl-js/src/style-spec/reference/v8.json $(MBGL_ANDROID_LOCAL_WORK_DIR)/mapbox-gl-js/src/style-spec/reference > /dev/null 2>&1 + adb push MapboxGLAndroidSDK/build/intermediates/cmake/$(buildtype)/obj/$2/mbgl-test $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1 + +# Create gtest filter for skipped tests. + $(eval SKIPPED_TESTS := -$(shell sed -n '/#\|^$$/!p' tests/skipped.txt | sed ':a;$!N;s/\n/:/g;ta')) + + # Kick off the tests + adb shell "export LD_LIBRARY_PATH=$(MBGL_ANDROID_LOCAL_WORK_DIR) && cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && chmod +x mbgl-test && ./mbgl-test --class_path=$(MBGL_ANDROID_LOCAL_WORK_DIR)/classes.dex --gtest_filter=$$*:$(SKIPPED_TESTS)" + + # Gather the results and unpack them + adb shell "cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && tar -cvzf results.tgz test/fixtures/* > /dev/null 2>&1" + adb pull $(MBGL_ANDROID_LOCAL_WORK_DIR)/results.tgz $(MBGL_ANDROID_CORE_TEST_DIR)/ > /dev/null 2>&1 + rm -rf $(MBGL_ANDROID_CORE_TEST_DIR)/results && mkdir -p $(MBGL_ANDROID_CORE_TEST_DIR)/results + tar -xzf $(MBGL_ANDROID_CORE_TEST_DIR)/results.tgz --strip-components=2 -C $(MBGL_ANDROID_CORE_TEST_DIR)/results + +# Run the core test for specified abi +.PHONY: run-android-core-test-$1 +run-android-core-test-$1: run-android-core-test-$1-* + +# Run benchmarks for specified abi +.PHONY: run-android-benchmark-$1 +run-android-benchmark-$1: run-android-benchmark-$1-* + +run-android-benchmark-$1-%: android-benchmark-$1 + mkdir -p $(MBGL_ANDROID_BENCHMARK_DIR) + unzip -o MapboxGLAndroidSDKTestApp/build/outputs/apk/$(buildtype)/MapboxGLAndroidSDKTestApp-$(MBGL_ANDROID_APK_SUFFIX).apk classes.dex -d $(MBGL_ANDROID_BENCHMARK_DIR) + + # Delete old test folder and create new one + adb shell "rm -Rf $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) && mkdir -p $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/benchmark && mkdir -p $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/test" + + # Push compiled java sources, test data and executable to device + adb push $(MBGL_ANDROID_BENCHMARK_DIR)/classes.dex $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) > /dev/null 2>&1 + adb push MapboxGLAndroidSDK/build/intermediates/intermediate-jars/$(buildtype)/jni/$2/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) > /dev/null 2>&1 + adb push benchmark/fixtures $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/benchmark > /dev/null 2>&1 + adb push test/fixtures $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/test > /dev/null 2>&1 + adb push MapboxGLAndroidSDK/build/intermediates/cmake/$(buildtype)/obj/$2/mbgl-benchmark $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) > /dev/null 2>&1 + + # Run benchmark. Number of benchmark iterations can be set by run-android-benchmark-N parameter. + adb shell "export LD_LIBRARY_PATH=$(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) && cd $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR) && chmod +x mbgl-benchmark && ./mbgl-benchmark --class_path=$(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/classes.dex --benchmark_repetitions=$$* --benchmark_format=json --benchmark_out=results.json" + + # Pull results.json from the device + rm -rf $(MBGL_ANDROID_BENCHMARK_DIR)/results && mkdir -p $(MBGL_ANDROID_BENCHMARK_DIR)/results + adb pull $(MBGL_ANDROID_LOCAL_BENCHMARK_DIR)/results.json $(MBGL_ANDROID_BENCHMARK_DIR)/results > /dev/null 2>&1 + +# Run the test app on connected android device with specified abi +.PHONY: run-android-$1 +run-android-$1: gradle/configuration.gradle + -adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:install$(BUILDTYPE) && adb shell am start -n com.mapbox.mapboxsdk.testapp/.activity.FeatureOverviewActivity + +# Build test app instrumentation tests apk and test app apk for specified abi +.PHONY: android-ui-test-$1 +android-ui-test-$1: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:assembleDebug :MapboxGLAndroidSDKTestApp:assembleAndroidTest + +# Run test app instrumentation tests on a connected android device or emulator with specified abi +.PHONY: run-android-ui-test-$1 +run-android-ui-test-$1: gradle/configuration.gradle + -adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:connectedAndroidTest + +# Run Java Instrumentation tests on a connected android device or emulator with specified abi and test filter +run-android-ui-test-$1-%: gradle/configuration.gradle + -adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="$$*" + +# Symbolicate native stack trace with the specified abi +.PHONY: android-ndk-stack-$1 +android-ndk-stack-$1: gradle/configuration.gradle + adb logcat | ndk-stack -sym MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj/$2/ + +# Run render tests with pixelmatch +.PHONY: run-android-render-test-$1 +run-android-render-test-$1: $(BUILD_DEPS) gradle/configuration.gradle + -adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null + # delete old test results + rm -rf build/render-test/mapbox/ + # copy test definitions & ignore file to test app assets folder, clear old ones first + rm -rf MapboxGLAndroidSDKTestApp/src/main/assets/integration + cp -r mapbox-gl-js/test/integration MapboxGLAndroidSDKTestApp/src/main/assets + cp platform/node/test/ignores.json MapboxGLAndroidSDKTestApp/src/main/assets/integration/ignores.json + # run RenderTest.java to generate static map images + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="com.mapbox.mapboxsdk.testapp.render.RenderTest" + # pull generated images from the device + adb pull "`adb shell 'printenv EXTERNAL_STORAGE' | tr -d '\r'`/mapbox/render" build/render-test + # copy expected result and run pixelmatch + python scripts/run-render-test.py + # remove test definitions from assets + rm -rf MapboxGLAndroidSDKTestApp/src/main/assets/integration + +endef + +# Explodes the arguments into individual variables +define ANDROID_RULES_INVOKER +$(call ANDROID_RULES,$(word 1,$1),$(word 2,$1)) +endef + +$(foreach abi,$(MBGL_ANDROID_ABIS),$(eval $(call ANDROID_RULES_INVOKER,$(subst ;, ,$(abi))))) + +# Build the Android SDK and test app with abi set to arm-v7 +.PHONY: android +android: android-arm-v7 + +# Build the Android SDK with abi set to arm-v7 +.PHONY: android-lib +android-lib: android-lib-arm-v7 + +# Run the test app on connected android device with abi set to arm-v7 +.PHONY: run-android +run-android: run-android-arm-v7 + +# Run Java Instrumentation tests on a connected android device or emulator with abi set to arm-v7 +.PHONY: run-android-ui-test +run-android-ui-test: run-android-ui-test-arm-v7 +run-android-ui-test-%: run-android-ui-test-arm-v7-% + +# Run Java Unit tests on the JVM of the development machine executing this +.PHONY: run-android-unit-test +run-android-unit-test: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest --info +run-android-unit-test-%: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest --info --tests "$*" + +# Run unit test and build a coverage report from .exec file generated by unit tests and .ec file generated by instrumentation tests +.PHONY: android-create-jacoco-report +android-create-jacoco-report: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:jacocoTestReport + +# Parse merged jacoco report and send it to S3 +.PHONY: android-parse-and-send-jacoco-report +android-parse-and-send-jacoco-report: + python scripts/parse-jacoco-report.py + +# Builds a release package of the Android SDK +.PHONY: apackage +apackage: gradle/configuration.gradle + make android-lib-arm-v7 && make android-lib-arm-v8 && make android-lib-x86 && make android-lib-x86-64 + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=all assemble$(BUILDTYPE) + +# Build test app instrumentation tests apk and test app apk for all abi's +.PHONY: android-ui-test +android-ui-test: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=all :MapboxGLAndroidSDKTestApp:assembleDebug :MapboxGLAndroidSDKTestApp:assembleAndroidTest + +#Run instrumentations tests on MicroSoft App Center +.PHONY: run-android-test-app-center +run-android-test-app-center: + appcenter test run espresso --app "mapboxcn-outlook.com/MapsSdk" --devices "mapboxcn-outlook.com/china" --app-path MapboxGLAndroidSDKTestApp/build/outputs/apk/debug/MapboxGLAndroidSDKTestApp-debug.apk --test-series "master" --locale "en_US" --build-dir MapboxGLAndroidSDKTestApp/build/outputs/apk/androidTest/debug + +# Uploads the compiled Android SDK to Bintray +.PHONY: run-android-upload-to-bintray +run-android-upload-to-bintray: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=all :MapboxGLAndroidSDK:bintrayUpload + +# Uploads the compiled Android SDK SNAPSHOT to oss.jfrog.org +.PHONY: run-android-upload-to-artifactory +run-android-upload-to-artifactory: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=all :MapboxGLAndroidSDK:artifactoryPublish + +# Dump system graphics information for the test app +.PHONY: android-gfxinfo +android-gfxinfo: + adb shell dumpsys gfxinfo com.mapbox.mapboxsdk.testapp reset + +# Generates Activity sanity tests +.PHONY: test-code-android +test-code-android: + node scripts/generate-test-code.js + +# Runs checkstyle and lint on the java code +.PHONY: android-check +android-check : android-ktlint android-checkstyle android-lint-sdk android-lint-test-app run-android-nitpick + +# Runs checkstyle on the java code +.PHONY: android-checkstyle +android-checkstyle: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:checkstyle :MapboxGLAndroidSDKTestApp:checkstyle + +# Runs checkstyle on the kotlin code +.PHONY: android-ktlint +android-ktlint: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none ktlint + +# Runs lint on the Android SDK java code +.PHONY: android-lint-sdk +android-lint-sdk: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:lint + +# Runs lint on the Android test app java code +.PHONY: android-lint-test-app +android-lint-test-app: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDKTestApp:lint + +# Generates javadoc from the Android SDK +.PHONY: android-javadoc +android-javadoc: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:javadocrelease + +# Generates LICENSE.md file based on all Android project dependencies +.PHONY: android-license +android-license: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:licenseReleaseReport + python scripts/generate-license.py + +# Symbolicate ndk stack traces for the arm-v7 abi +.PHONY: android-ndk-stack +android-ndk-stack: android-ndk-stack-arm-v7 + +# Open Android Studio if machine is macos +ifeq ($(HOST_PLATFORM), macos) +.PHONY: aproj +aproj: gradle/configuration.gradle + open -b com.google.android.studio +endif + +# Creates the configuration needed to build with Android Studio +.PHONY: android-configuration +android-configuration: gradle/configuration.gradle + cat gradle/configuration.gradle + +# Updates Android's vendor submodules +.PHONY: android-update-vendor +android-update-vendor: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none updateVendorSubmodules + +# Run android nitpick script +.PHONY: run-android-nitpick +run-android-nitpick: android-update-vendor + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none androidNitpick + +# Creates a dependency graph using Graphviz +.PHONY: android-graph +android-graph: gradle/configuration.gradle + $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:generateDependencyGraphMapboxLibraries + +#### Miscellaneous targets ##################################################### + +.PHONY: clean +clean: + -rm -rf ./gradle/configuration.gradle \ + ./MapboxGLAndroidSDK/build \ + ./MapboxGLAndroidSDK/.externalNativeBuild \ + ./MapboxGLAndroidSDKTestApp/build \ + ./MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen \ + ./MapboxGLAndroidSDK/src/main/assets \ + ./MapboxGLAndroidSDKTestApp/src/main/assets/integration \ No newline at end of file From daf0430a24b1f761472c90f12ae25a5e081c9ed2 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 16:05:15 +0200 Subject: [PATCH 003/185] [update] pull in latest for gl-native --- CHANGELOG.md | 54 +++++ .../java/com/mapbox/mapboxsdk/Mapbox.java | 12 + .../mapboxsdk/location/LocationComponent.java | 32 +++ .../maps/AttributionDialogManager.java | 62 ++++-- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 38 +++- .../mapboxsdk/maps/MapboxMapOptions.java | 41 ++++ .../com/mapbox/mapboxsdk/maps/NativeMap.java | 6 + .../mapbox/mapboxsdk/maps/NativeMapView.java | 25 ++- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 5 +- .../mapboxsdk/maps/widgets/CompassView.java | 1 + .../mapboxsdk/snapshotter/MapSnapshotter.java | 2 +- .../mapbox/mapboxsdk/storage/FileSource.java | 9 +- .../src/main/res-public/values/public.xml | 1 + .../src/main/res/values/attrs.xml | 1 + .../maps/AttributionDialogManagerTest.java | 99 +++++++++ .../mapboxsdk/maps/MapboxMapOptionsTest.java | 10 + .../mapbox/mapboxsdk/maps/MapboxMapTest.kt | 12 + .../mapbox/mapboxsdk/maps/UiSettingsTest.java | 18 ++ .../location/LocationComponentTest.kt | 60 +++++ .../mapboxsdk/maps/NativeMapViewTest.kt | 19 +- .../mapboxsdk/testapp/activity/BaseTest.java | 12 +- .../annotation/BulkMarkerActivity.java | 3 + .../fragment/MapFragmentActivity.java | 4 +- .../location/LocationFragmentActivity.kt | 2 +- .../snapshot/MapSnapshotterActivity.java | 1 + .../style/SymbolGeneratorActivity.java | 7 +- gradle/dependencies.gradle | 2 +- gradle/jacoco-report.gradle | 2 +- scripts/exclude-activity-gen.json | 5 +- src/file_source.cpp | 59 ++--- src/file_source.hpp | 2 +- src/i18n/collator.cpp | 194 ++++++++++++++++ src/i18n/collator_jni.hpp | 62 ++++++ src/i18n/number_format.cpp | 80 +++++++ src/i18n/number_format_jni.hpp | 29 +++ src/jni_native.cpp | 12 +- src/jni_native.hpp | 2 +- src/map/camera_position.cpp | 21 +- src/map_renderer.cpp | 2 +- src/map_renderer.hpp | 2 +- src/map_renderer_runnable.cpp | 7 +- src/map_renderer_runnable.hpp | 4 +- src/mapbox.cpp | 23 ++ src/mapbox.hpp | 19 ++ src/native_map_view.cpp | 209 ++++++++++-------- src/native_map_view.hpp | 6 +- src/style/sources/source.cpp | 2 +- src/test/version-script | 8 + vendor/mapbox-gl-native | 2 +- 49 files changed, 1103 insertions(+), 187 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AttributionDialogManagerTest.java create mode 100644 src/i18n/collator.cpp create mode 100644 src/i18n/collator_jni.hpp create mode 100644 src/i18n/number_format.cpp create mode 100644 src/i18n/number_format_jni.hpp mode change 100755 => 100644 src/jni_native.cpp create mode 100644 src/mapbox.cpp create mode 100644 src/mapbox.hpp mode change 100755 => 100644 src/native_map_view.cpp create mode 100644 src/test/version-script diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb33f7ca..e3b07dd32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,62 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. ## master + +### Performance improvements + - Improved rendering performance for the styles with multiple sources [#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756) + +## 8.5.0-alpha.1 - October 3, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0): +### Bug fixes + - Suppress network requests for expired tiles update, if these tiles are invisible. [#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741) + - Fixed opacity interpolation for composition expressions [#15738](https://github.com/mapbox/mapbox-gl-native/pull/15738) + - Fixed an issue where `Projection#getMetersPerPixelAtLatitude` returned a value incorrectly divided by the pixel ratio. This also fixes an issue where `LocationComponent` accuracy circle's radius was artificially increased. [#15742](https://github.com/mapbox/mapbox-gl-native/pull/15742) + +## 8.4.0 - September 25, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): + +### Bug fixes + - Fixing a crash when `CameraPosition` padding is set when using `MapSnapshotter`. [#15699](https://github.com/mapbox/mapbox-gl-native/pull/15699) + +### Other Changes + - Bumped Java SDK dependency to stable 4.9.0 [#15700](https://github.com/mapbox/mapbox-gl-native/pull/15700) + - Migrate map feedback to GL JS–powered feedback form [#15623](https://github.com/mapbox/mapbox-gl-native/pull/15623) + +## 8.4.0-beta.1 - September 19, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.2...android-v8.4.0-beta.1) since [Mapbox Maps SDK for Android v8.4.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.2): + +### Bug fixes + - Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. [#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581) + - Fixed constant repainting for the sources with invisible layers, caused by `RenderSource::hasFadingTiles()` returning `true` all the time. [#15600](https://github.com/mapbox/mapbox-gl-native/pull/15600) + - Fixed an issue that caused the state of CompassView not up to date when `UiSettings.setCompassEnabled()` is set to true. [#15606](https://github.com/mapbox/mapbox-gl-native/pull/15606) + - Ignore location tracking mode based animations when the camera is transitioning. [#15641](https://github.com/mapbox/mapbox-gl-native/pull/15641) + - Fixed MapSnapshotter so that `MapSnapshotter.withApiBaseUri` works again. [#15642](https://github.com/mapbox/mapbox-gl-native/pull/15642) + - Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. [#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644) + +## 8.3.2 - September 19, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.1...android-v8.3.2) since [Mapbox Maps SDK for Android v8.3.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.1): + ### Bug fixes - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560) + +## 8.3.1 - September 18, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.3.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): + +### Bug fixes + - Updated earcut.hpp submodule file [#15660](https://github.com/mapbox/mapbox-gl-native/pull/15660) + - Fixed a wrong variable assignment of `MapSnapshotter.Options.withApiBaseUri`. [#15642](https://github.com/mapbox/mapbox-gl-native/pull/15642) + +## 8.4.0-alpha.2 - September 11, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1): + +### Performance improvements + - Newly loaded labels appear faster on the screen. [#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308) + +### Bug fixes + - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560) + +### Other Changes + - Bumped Java SDK dependency to 4.9.0-alpha.1 [#15570](https://github.com/mapbox/mapbox-gl-native/pull/15570) ## 8.4.0-alpha.1 - September 4, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.4.0-alpha.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 01c82ddad..35f7a5975 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -2,6 +2,8 @@ package com.mapbox.mapboxsdk; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; +import android.support.annotation.Keep; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; @@ -24,6 +26,7 @@ import com.mapbox.mapboxsdk.utils.ThreadUtils; */ @UiThread @SuppressLint("StaticFieldLeak") +@Keep public final class Mapbox { private static final String TAG = "Mbgl-Mapbox"; @@ -222,4 +225,13 @@ public final class Mapbox { public static boolean hasInstance() { return INSTANCE != null; } + + /** + * Internal use. Returns AssetManager. + * + * @return the asset manager + */ + private static AssetManager getAssetManager() { + return getApplicationContext().getResources().getAssets(); + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 46de3673e..8b014b0e9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -726,6 +726,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the zoom change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument. + *

    * * @param zoomLevel The desired zoom level. * @param animationDuration The zoom animation duration. @@ -741,6 +745,10 @@ public final class LocationComponent { "LocationComponent#zoomWhileTracking method can only be used", " when a camera mode other than CameraMode#NONE is engaged.")); return; + } else if (locationCameraController.isTransitioning()) { + Logger.e(TAG, + "LocationComponent#zoomWhileTracking method call is ignored because the camera mode is transitioning"); + return; } locationAnimatorCoordinator.feedNewZoomLevel(zoomLevel, mapboxMap.getCameraPosition(), animationDuration, callback); } @@ -751,6 +759,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the zoom change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument. + *

    * * @param zoomLevel The desired zoom level. * @param animationDuration The zoom animation duration. @@ -766,6 +778,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the zoom change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument. + *

    * * @param zoomLevel The desired zoom level. */ @@ -788,6 +804,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the tilt change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument. + *

    * * @param tilt The desired camera tilt. * @param animationDuration The tilt animation duration. @@ -803,6 +823,10 @@ public final class LocationComponent { "LocationComponent#tiltWhileTracking method can only be used", " when a camera mode other than CameraMode#NONE is engaged.")); return; + } else if (locationCameraController.isTransitioning()) { + Logger.e(TAG, + "LocationComponent#tiltWhileTracking method call is ignored because the camera mode is transitioning"); + return; } locationAnimatorCoordinator.feedNewTilt(tilt, mapboxMap.getCameraPosition(), animationDuration, callback); } @@ -813,6 +837,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the tilt change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument. + *

    * * @param tilt The desired camera tilt. * @param animationDuration The tilt animation duration. @@ -828,6 +856,10 @@ public final class LocationComponent { * If you are not using any of {@link CameraMode} modes, * use one of {@link MapboxMap#moveCamera(CameraUpdate)}, * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead. + *

    + * If the camera is transitioning when the tilt change is requested, the call is going to be ignored. + * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument. + *

    * * @param tilt The desired camera tilt. */ diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 4f523948d..5384a29fc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -26,6 +26,8 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Responsible for managing attribution interactions on the map. @@ -36,9 +38,10 @@ import java.util.Set; *

    */ public class AttributionDialogManager implements View.OnClickListener, DialogInterface.OnClickListener { - private static final String MAP_FEEDBACK_URL = "https://apps.mapbox.com/feedback"; - private static final String MAP_FEEDBACK_LOCATION_FORMAT = MAP_FEEDBACK_URL + "/#/%f/%f/%d"; + private static final String MAP_FEEDBACK_URL_OLD = "https://www.mapbox.com/map-feedback"; + private static final String MAP_FEEDBACK_URL_LOCATION_FRAGMENT_FORMAT = "/%f/%f/%f/%f/%d"; + private static final String MAP_FEEDBACK_STYLE_URI_REGEX = "^(.*://[^:^/]*)/(.*)/(.*)"; @NonNull private final Context context; @@ -90,7 +93,7 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt if (isLatestEntry(which)) { showTelemetryDialog(); } else { - showMapFeedbackWebPage(which); + showMapAttributionWebPage(which); } } @@ -138,21 +141,54 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt builder.show(); } - private void showMapFeedbackWebPage(int which) { + private void showMapAttributionWebPage(int which) { Attribution[] attributions = attributionSet.toArray(new Attribution[attributionSet.size()]); String url = attributions[which].getUrl(); - if (url.contains(MAP_FEEDBACK_URL)) { - url = buildMapFeedbackMapUrl(mapboxMap.getCameraPosition()); + if (url.contains(MAP_FEEDBACK_URL_OLD) || url.contains(MAP_FEEDBACK_URL)) { + url = buildMapFeedbackMapUrl(Mapbox.getAccessToken()); } showWebPage(url); } @NonNull - private String buildMapFeedbackMapUrl(@Nullable CameraPosition cameraPosition) { - // appends current location to the map feedback url if available - return cameraPosition != null ? String.format(Locale.getDefault(), - MAP_FEEDBACK_LOCATION_FORMAT, cameraPosition.target.getLongitude(), cameraPosition.target.getLatitude(), - (int) cameraPosition.zoom) : MAP_FEEDBACK_URL; + String buildMapFeedbackMapUrl(@Nullable String accessToken) { + // TODO Add Android Maps SDK version to the query parameter, currently the version API is not available. + // TODO Keep track of this issue at [#15632](https://github.com/mapbox/mapbox-gl-native/issues/15632) + + Uri.Builder builder = Uri.parse(MAP_FEEDBACK_URL).buildUpon(); + + CameraPosition cameraPosition = mapboxMap.getCameraPosition(); + if (cameraPosition != null) { + builder.encodedFragment(String.format(Locale.getDefault(), MAP_FEEDBACK_URL_LOCATION_FRAGMENT_FORMAT, + cameraPosition.target.getLongitude(), cameraPosition.target.getLatitude(), + cameraPosition.zoom, cameraPosition.bearing, (int) cameraPosition.tilt)); + } + + String packageName = context.getApplicationContext().getPackageName(); + if (packageName != null) { + builder.appendQueryParameter("referrer", packageName); + } + + if (accessToken != null) { + builder.appendQueryParameter("access_token", accessToken); + } + + Style style = mapboxMap.getStyle(); + if (style != null) { + String styleUri = style.getUri(); + Pattern pattern = Pattern.compile(MAP_FEEDBACK_STYLE_URI_REGEX); + Matcher matcher = pattern.matcher(styleUri); + + if (matcher.find()) { + String styleOwner = matcher.group(2); + String styleId = matcher.group(3); + + builder.appendQueryParameter("owner", styleOwner) + .appendQueryParameter("id", styleId); + } + } + + return builder.build().toString(); } private void showWebPage(@NonNull String url) { @@ -189,10 +225,10 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt Style style = mapboxMap.getStyle(); if (style != null) { - for (Source source : mapboxMap.getStyle().getSources()) { + for (Source source : style.getSources()) { attribution = source.getAttribution(); if (!attribution.isEmpty()) { - attributions.add(source.getAttribution()); + attributions.add(attribution); } } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index acd5093da..8f4cb9438 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -6,6 +6,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; import android.support.annotation.FloatRange; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Size; @@ -246,12 +247,16 @@ public final class MapboxMap { // Style /** - * Sets tile pre-fetching from MapboxOptions. + * Sets tile pre-fetching zoom delta from MapboxOptions. * * @param options the options object */ private void setPrefetchesTiles(@NonNull MapboxMapOptions options) { - setPrefetchesTiles(options.getPrefetchesTiles()); + if (!options.getPrefetchesTiles()) { + setPrefetchZoomDelta(0); + } else { + setPrefetchZoomDelta(options.getPrefetchZoomDelta()); + } } /** @@ -259,7 +264,9 @@ public final class MapboxMap { * tile is rendered as soon as possible at the expense of a little bandwidth. * * @param enable true to enable + * @deprecated Use {@link #setPrefetchZoomDelta(int)} instead. */ + @Deprecated public void setPrefetchesTiles(boolean enable) { nativeMapView.setPrefetchTiles(enable); } @@ -269,11 +276,38 @@ public final class MapboxMap { * * @return true if enabled * @see MapboxMap#setPrefetchesTiles(boolean) + * @deprecated Use {@link #getPrefetchZoomDelta()} instead. */ + @Deprecated public boolean getPrefetchesTiles() { return nativeMapView.getPrefetchTiles(); } + /** + * Set the tile pre-fetching zoom delta. Pre-fetching makes sure that a low-resolution + * tile at the (current_zoom_level - delta) is rendered as soon as possible at the + * expense of a little bandwidth. + * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) + * Setting zoom delta to 0 will disable pre-fetching. + * Default zoom delta is 4. + * + * @param delta zoom delta + */ + public void setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + nativeMapView.setPrefetchZoomDelta(delta); + } + + /** + * Check current pre-fetching zoom delta. + * + * @return current zoom delta. + * @see MapboxMap#setPrefetchZoomDelta(int) + */ + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + return nativeMapView.getPrefetchZoomDelta(); + } + // // MinZoom // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 6cd3271d1..827756870 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -8,6 +8,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.ColorInt; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -70,6 +71,7 @@ public class MapboxMapOptions implements Parcelable { private boolean quickZoomGesturesEnabled = true; private boolean prefetchesTiles = true; + private int prefetchZoomDelta = 4; private boolean zMediaOverlay = false; private boolean localIdeographFontFamilyEnabled = true; @@ -134,6 +136,7 @@ public class MapboxMapOptions implements Parcelable { textureMode = in.readByte() != 0; translucentTextureSurface = in.readByte() != 0; prefetchesTiles = in.readByte() != 0; + prefetchZoomDelta = in.readInt(); zMediaOverlay = in.readByte() != 0; localIdeographFontFamilyEnabled = in.readByte() != 0; localIdeographFontFamily = in.readString(); @@ -257,6 +260,8 @@ public class MapboxMapOptions implements Parcelable { typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureTranslucentSurface, false)); mapboxMapOptions.setPrefetchesTiles( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); + mapboxMapOptions.setPrefetchZoomDelta( + typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); mapboxMapOptions.renderSurfaceOnTop( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false)); @@ -633,13 +638,32 @@ public class MapboxMapOptions implements Parcelable { * * @param enable true to enable * @return This + * @deprecated Use {@link #setPrefetchZoomDelta(int)} instead. */ + @Deprecated @NonNull public MapboxMapOptions setPrefetchesTiles(boolean enable) { this.prefetchesTiles = enable; return this; } + /** + * Set the tile pre-fetching zoom delta. Pre-fetching makes sure that a low-resolution + * tile at the (current_zoom_level - delta) is rendered as soon as possible at the + * expense of a little bandwidth. + * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) + * Setting zoom delta to 0 will disable pre-fetching. + * Default zoom delta is 4. + * + * @param delta zoom delta + * @return This + */ + @NonNull + public MapboxMapOptions setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + this.prefetchZoomDelta = delta; + return this; + } + /** * Enable cross-source symbol collision detection, defaults to true. *

    @@ -721,11 +745,23 @@ public class MapboxMapOptions implements Parcelable { * Check whether tile pre-fetching is enabled. * * @return true if enabled + * @deprecated Use {@link #getPrefetchZoomDelta()} instead. */ + @Deprecated public boolean getPrefetchesTiles() { return prefetchesTiles; } + /** + * Check current pre-fetching zoom delta. + * + * @return current zoom delta. + */ + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + return prefetchZoomDelta; + } + /** * Check whether cross-source symbol collision detection is enabled. * @@ -1081,6 +1117,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (textureMode ? 1 : 0)); dest.writeByte((byte) (translucentTextureSurface ? 1 : 0)); dest.writeByte((byte) (prefetchesTiles ? 1 : 0)); + dest.writeInt(prefetchZoomDelta); dest.writeByte((byte) (zMediaOverlay ? 1 : 0)); dest.writeByte((byte) (localIdeographFontFamilyEnabled ? 1 : 0)); dest.writeString(localIdeographFontFamily); @@ -1175,6 +1212,9 @@ public class MapboxMapOptions implements Parcelable { if (prefetchesTiles != options.prefetchesTiles) { return false; } + if (prefetchZoomDelta != options.prefetchZoomDelta) { + return false; + } if (zMediaOverlay != options.zMediaOverlay) { return false; } @@ -1231,6 +1271,7 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (textureMode ? 1 : 0); result = 31 * result + (translucentTextureSurface ? 1 : 0); result = 31 * result + (prefetchesTiles ? 1 : 0); + result = 31 * result + prefetchZoomDelta; result = 31 * result + (zMediaOverlay ? 1 : 0); result = 31 * result + (localIdeographFontFamilyEnabled ? 1 : 0); result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 7f3017c7a..c805dcddb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -6,6 +6,7 @@ import android.graphics.RectF; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; + import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; import com.mapbox.mapboxsdk.annotations.Marker; @@ -214,6 +215,11 @@ interface NativeMap { boolean getPrefetchTiles(); + void setPrefetchZoomDelta(@IntRange(from = 0) int delta); + + @IntRange(from = 0) + int getPrefetchZoomDelta(); + void setGestureInProgress(boolean inProgress); float getPixelRatio(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 8496160c7..75ca5edfc 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -620,7 +620,7 @@ final class NativeMapView implements NativeMap { if (checkState("getMetersPerPixelAtLatitude")) { return 0; } - return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio; + return nativeGetMetersPerPixelAtLatitude(lat, getZoom()); } @Override @@ -724,6 +724,23 @@ final class NativeMapView implements NativeMap { return nativeGetPrefetchTiles(); } + @Override + public void setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + if (checkState("nativeSetPrefetchZoomDelta")) { + return; + } + nativeSetPrefetchZoomDelta(delta); + } + + @Override + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + if (checkState("nativeGetPrefetchZoomDelta")) { + return 0; + } + return nativeGetPrefetchZoomDelta(); + } + // Runtime style Api @Override @@ -1383,6 +1400,12 @@ final class NativeMapView implements NativeMap { @Keep private native boolean nativeGetPrefetchTiles(); + @Keep + private native void nativeSetPrefetchZoomDelta(int delta); + + @Keep + private native int nativeGetPrefetchZoomDelta(); + @Override public long getNativePtr() { return nativePtr; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 9e72be8e9..3fd155837 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -417,10 +417,6 @@ public final class UiSettings { } void update(@NonNull CameraPosition cameraPosition) { - if (!isCompassEnabled()) { - return; - } - double clockwiseBearing = -cameraPosition.bearing; compassView.update(clockwiseBearing); } @@ -1073,6 +1069,7 @@ public final class UiSettings { */ public void invalidate() { setLogoMargins(getLogoMarginLeft(), getLogoMarginTop(), getLogoMarginRight(), getLogoMarginBottom()); + setCompassEnabled(isCompassEnabled()); setCompassMargins(getCompassMarginLeft(), getCompassMarginTop(), getCompassMarginRight(), getCompassMarginBottom()); setAttributionMargins(getAttributionMarginLeft(), getAttributionMarginTop(), getAttributionMarginRight(), getAttributionMarginBottom()); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index 53c0c1c60..b593076dc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java @@ -91,6 +91,7 @@ public final class CompassView extends ImageView implements Runnable { resetAnimation(); setAlpha(1.0f); setVisibility(View.VISIBLE); + update(rotation); } else { resetAnimation(); setAlpha(0.0f); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 1e0069c25..990bd3226 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -235,7 +235,7 @@ public class MapSnapshotter { */ @NonNull public Options withApiBaseUri(String apiBaseUri) { - this.apiBaseUrl = apiBaseUrl; + this.apiBaseUrl = apiBaseUri; return this; } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index 763c97cca..07e5b7e16 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.AssetManager; import android.os.AsyncTask; import android.os.Environment; import android.support.annotation.Keep; @@ -90,7 +89,7 @@ public class FileSource { @UiThread public static synchronized FileSource getInstance(@NonNull Context context) { if (INSTANCE == null) { - INSTANCE = new FileSource(getResourcesCachePath(context), context.getResources().getAssets()); + INSTANCE = new FileSource(getResourcesCachePath(context)); } return INSTANCE; @@ -366,8 +365,8 @@ public class FileSource { @Keep private long nativePtr; - private FileSource(String cachePath, AssetManager assetManager) { - initialize(Mapbox.getAccessToken(), cachePath, assetManager); + private FileSource(String cachePath) { + initialize(Mapbox.getAccessToken(), cachePath); } @Keep @@ -404,7 +403,7 @@ public class FileSource { private native void setResourceCachePath(String path, ResourcesCachePathChangeCallback callback); @Keep - private native void initialize(String accessToken, String cachePath, AssetManager assetManager); + private native void initialize(String accessToken, String cachePath); @Override @Keep diff --git a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 60a1efc77..36071cc2a 100644 --- a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -69,6 +69,7 @@ + diff --git a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index ff8a32ac6..137f72f8d 100644 --- a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -109,6 +109,7 @@ + diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AttributionDialogManagerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AttributionDialogManagerTest.java new file mode 100644 index 000000000..9b4eeb27a --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AttributionDialogManagerTest.java @@ -0,0 +1,99 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; + +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.geometry.LatLng; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.robolectric.RobolectricTestRunner; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +public class AttributionDialogManagerTest { + @InjectMocks + Context context = mock(Context.class); + + @InjectMocks + MapboxMap mapboxMap = mock(MapboxMap.class); + + @InjectMocks + Style style = mock(Style.class); + + private AttributionDialogManager attributionDialogManager; + private CameraPosition cameraPosition; + + private static final String ASSERT_MAPBOX_TOKEN = "TestAccessToken"; + + private static final String ASSERT_MAPBOX_STYLE_URI = "mapbox://styles/mapbox/streets-v11"; + private static final String ASSERT_MAPBOX_LOCAL_STYLE_URI = "asset://style.json"; + + private static final String ASSERT_MAPBOX_PACKAGE_NAME = "com.mapbox.attributionmanagertest"; + + private static final String ASSERT_MAPBOX_FEEDBACK_FINAL_URL = + "https://apps.mapbox.com/feedback?referrer=com.mapbox.attributionmanagertest&" + + "access_token=TestAccessToken&owner=mapbox&id=streets-v11" + + "#/22.200001/11.100000/12.000000/24.000000/5"; + private static final String ASSERT_MAPBOX_FEEDHACK_FINAL_URL_LOCAL_STYLE = + "https://apps.mapbox.com/feedback?referrer=com.mapbox.attributionmanagertest&" + + "access_token=TestAccessToken#/22.200001/11.100000/12.000000/24.000000/5"; + private static final String ASSERT_MAPBOX_FEEDBACL_FINAL_URL_NULL_CAMERA_POSITION = + "https://apps.mapbox.com/feedback?referrer=com.mapbox.attributionmanagertest&access_token=TestAccessToken"; + + @Before + public void beforeTest() { + attributionDialogManager = new AttributionDialogManager(context, mapboxMap); + cameraPosition = new CameraPosition.Builder(CameraPosition.DEFAULT) + .tilt(5.0f).zoom(12).bearing(24.0f).target(new LatLng(11.1f, 22.2f)).build(); + } + + @Test + public void testSanity() { + assertNotNull("AttributionDialogManager should not be null", attributionDialogManager); + } + + @Test + public void testBuildMapFeedbackMapUrl() { + when(context.getApplicationContext()).thenReturn(context); + when(context.getPackageName()).thenReturn(ASSERT_MAPBOX_PACKAGE_NAME); + when(style.getUri()).thenReturn(ASSERT_MAPBOX_STYLE_URI); + when(mapboxMap.getCameraPosition()).thenReturn(cameraPosition); + when(mapboxMap.getStyle()).thenReturn(style); + + Assert.assertEquals(ASSERT_MAPBOX_FEEDBACK_FINAL_URL, + attributionDialogManager.buildMapFeedbackMapUrl(ASSERT_MAPBOX_TOKEN)); + } + + @Test + public void testBuildMapFeedbackMapUrlWithLocalStyleJson() { + when(context.getApplicationContext()).thenReturn(context); + when(context.getPackageName()).thenReturn(ASSERT_MAPBOX_PACKAGE_NAME); + when(style.getUri()).thenReturn(ASSERT_MAPBOX_LOCAL_STYLE_URI); + when(mapboxMap.getCameraPosition()).thenReturn(cameraPosition); + when(mapboxMap.getStyle()).thenReturn(style); + + Assert.assertEquals(ASSERT_MAPBOX_FEEDHACK_FINAL_URL_LOCAL_STYLE, + attributionDialogManager.buildMapFeedbackMapUrl(ASSERT_MAPBOX_TOKEN)); + } + + @Test + public void testBuildMapFeedbackMapUrlWithNullCameraPosition() { + when(context.getApplicationContext()).thenReturn(context); + when(context.getPackageName()).thenReturn(ASSERT_MAPBOX_PACKAGE_NAME); + when(style.getUri()).thenReturn(ASSERT_MAPBOX_LOCAL_STYLE_URI); + when(mapboxMap.getCameraPosition()).thenReturn(null); + when(mapboxMap.getStyle()).thenReturn(style); + + Assert.assertEquals(ASSERT_MAPBOX_FEEDBACL_FINAL_URL_NULL_CAMERA_POSITION, + attributionDialogManager.buildMapFeedbackMapUrl(ASSERT_MAPBOX_TOKEN)); + } + + +} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index 6978afcf1..c46e6e319 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -167,6 +167,16 @@ public class MapboxMapOptionsTest { assertFalse(new MapboxMapOptions().setPrefetchesTiles(false).getPrefetchesTiles()); } + @Test + public void testPrefetchZoomDelta() { + // Default value + assertEquals(4, new MapboxMapOptions().getPrefetchZoomDelta()); + + // Check mutations + assertEquals(5, new MapboxMapOptions().setPrefetchZoomDelta(5).getPrefetchZoomDelta()); + } + + @Test public void testCrossSourceCollisions() { // Default value diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt index deb5f603c..6647fe559 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -126,6 +126,18 @@ class MapboxMapTest { verify { nativeMapView.prefetchTiles = true } } + @Test + fun testGetPrefetchZoomDelta() { + every { nativeMapView.prefetchZoomDelta } answers { 3 } + assertEquals(3, mapboxMap.prefetchZoomDelta) + } + + @Test + fun testSetPrefetchZoomDelta() { + mapboxMap.prefetchZoomDelta = 2 + verify { nativeMapView.prefetchZoomDelta = 2 } + } + @Test fun testCameraForLatLngBounds() { val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java index cfcf0a048..a84e93cd7 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java @@ -5,6 +5,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import org.junit.Before; @@ -17,6 +18,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; public class UiSettingsTest { @@ -412,4 +414,20 @@ public class UiSettingsTest { assertEquals("Zoom rate should be 0.83f", 0.83f, uiSettings.getZoomRate(), 0); } + + @Test + public void testUpdateWhenCompassViewNotHidden() { + CameraPosition cameraPosition = new CameraPosition.Builder(CameraPosition.DEFAULT).bearing(24.0f).build(); + when(compassView.isHidden()).thenReturn(false); + uiSettings.update(cameraPosition); + verify(compassView).update(-24.0f); + } + + @Test + public void testUpdateWhenCompassViewHidden() { + CameraPosition cameraPosition = new CameraPosition.Builder(CameraPosition.DEFAULT).bearing(24.0f).build(); + when(compassView.isHidden()).thenReturn(true); + uiSettings.update(cameraPosition); + verify(compassView).update(-24.0f); + } } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index fb113502e..51c9e1c10 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -1288,6 +1288,36 @@ class LocationComponentTest : EspressoTest() { executeComponentTest(componentAction) } + @Test + fun animators_dontZoomWhileTransitioning() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent(LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build()) + component.isLocationComponentEnabled = true + component.forceLocationUpdate(location) + + val zoom = mapboxMap.cameraPosition.zoom + component.setCameraMode(CameraMode.TRACKING_GPS, 500L, null, null, null, null) + component.zoomWhileTracking(16.0, 1000) + uiController.loopMainThreadForAtLeast(1000) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.0001) + } + } + + executeComponentTest(componentAction) + } + @Test @Ignore fun animators_cancelZoomWhileTracking() { @@ -1433,6 +1463,36 @@ class LocationComponentTest : EspressoTest() { executeComponentTest(componentAction) } + @Test + fun animators_dontTiltWhileTransitioning() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent(LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build()) + component.isLocationComponentEnabled = true + component.forceLocationUpdate(location) + + val tilt = mapboxMap.cameraPosition.tilt + component.setCameraMode(CameraMode.TRACKING_GPS, 500L, null, null, null, null) + component.tiltWhileTracking(30.0, 1000) + uiController.loopMainThreadForAtLeast(1000) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.0001) + } + } + + executeComponentTest(componentAction) + } + @Test @Ignore fun animators_cancelTiltWhileTracking() { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt index b13bb6b79..dc313b5f6 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt @@ -221,6 +221,23 @@ class NativeMapViewTest : AppCenter() { assertEquals("Flag should match", expected, actual) } + @Test + @UiThreadTest + fun testPrefetchZoomDelta() { + val expected = 2 + nativeMapView.prefetchZoomDelta = 2 + val actual = nativeMapView.prefetchZoomDelta + assertEquals("Prefetch zoom delta should match", expected, actual) + } + + @Test + @UiThreadTest + fun testPrefetchZoomDeltaDefault() { + val expected = 4 + val actual = nativeMapView.prefetchZoomDelta + assertEquals("Prefetch zoom delta should match", expected, actual) + } + @Test @UiThreadTest fun testSetContentPadding() { @@ -254,7 +271,7 @@ class NativeMapViewTest : AppCenter() { @Test @UiThreadTest fun testGetProjectedMetersAtLatitude() { - val expected = 38986.83510557766 + val expected = 77973.67021115532 val actual = nativeMapView.getMetersPerPixelAtLatitude(5.0) assertEquals("Get projected meters should match", expected, actual) } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java index 45dac2361..b6c16c814 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java @@ -4,6 +4,7 @@ import android.content.Context; import android.support.annotation.CallSuper; import android.support.annotation.UiThread; import android.support.test.rule.ActivityTestRule; +import android.support.test.rule.GrantPermissionRule; import com.mapbox.mapboxsdk.AppCenter; import com.mapbox.mapboxsdk.Mapbox; @@ -35,6 +36,10 @@ public abstract class BaseTest extends AppCenter { @Rule public TestName testName = new TestName(); + @Rule + public GrantPermissionRule grantLocationPermissionRule = GrantPermissionRule + .grant(android.Manifest.permission.ACCESS_FINE_LOCATION); + protected MapboxMap mapboxMap; protected MapView mapView; private final CountDownLatch latch = new CountDownLatch(1); @@ -75,7 +80,12 @@ public abstract class BaseTest extends AppCenter { try { rule.runOnUiThread(() -> { mapView = rule.getActivity().findViewById(R.id.mapView); - mapView.getMapAsync(this::initMap); + if (mapView != null) { + mapView.getMapAsync(this::initMap); + } else { + Timber.w("Skipping map load test since mapView is not found."); + latch.countDown(); + } }); } catch (Throwable throwable) { throwable.printStackTrace(); diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java index 05337081d..d8fd42876 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java @@ -151,6 +151,9 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView @Override protected void onDestroy() { super.onDestroy(); + if (progressDialog != null) { + progressDialog.dismiss(); + } mapView.onDestroy(); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java index 40ea7509b..a0e8b31fc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java @@ -81,7 +81,9 @@ public class MapFragmentActivity extends AppCompatActivity implements MapFragmen @Override protected void onDestroy() { super.onDestroy(); - mapView.removeOnDidFinishRenderingFrameListener(this); + if (mapView != null) { + mapView.removeOnDidFinishRenderingFrameListener(this); + } } @Override diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt index ff2afb50c..7e18cbfa2 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt @@ -116,7 +116,7 @@ class LocationFragmentActivity : AppCompatActivity() { } override fun onSuccess(result: LocationEngineResult?) { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0)) + if (!mapView.isDestroyed) mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0)) } override fun onFailure(exception: Exception) { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java index 59c708266..ab7ffed83 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java @@ -89,6 +89,7 @@ public class MapSnapshotterActivity extends AppCompatActivity { .bearing(randomInRange(0, 360)) .tilt(randomInRange(0, 60)) .zoom(randomInRange(0, 20)) + .padding(1, 1, 1, 1) .build() ); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java index 24bfe62e7..e80d6fe3e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java @@ -362,7 +362,12 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR @Override protected void onPostExecute(HashMap bitmapHashMap) { super.onPostExecute(bitmapHashMap); - mapboxMap.getStyle().addImagesAsync(bitmapHashMap); + mapboxMap.getStyle(new Style.OnStyleLoaded() { + @Override + public void onStyleLoaded(@NonNull Style style) { + style.addImagesAsync(bitmapHashMap); + } + }); } } } \ No newline at end of file diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index c1c489472..31633488e 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -7,7 +7,7 @@ ext { ] versions = [ - mapboxServices : '4.9.0-alpha.1', + mapboxServices : '4.9.0', mapboxTelemetry : '4.5.1', mapboxCore : '1.3.0', mapboxGestures : '0.5.1', diff --git a/gradle/jacoco-report.gradle b/gradle/jacoco-report.gradle index c4e0bb913..64c99e09f 100644 --- a/gradle/jacoco-report.gradle +++ b/gradle/jacoco-report.gradle @@ -15,7 +15,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { } def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] - def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes) + def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/classes", excludes: fileExcludes) def mainSrc = "${project.projectDir}/src/main/java" println(mainSrc) def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec") diff --git a/scripts/exclude-activity-gen.json b/scripts/exclude-activity-gen.json index 0f5bb81b5..ab84957e3 100644 --- a/scripts/exclude-activity-gen.json +++ b/scripts/exclude-activity-gen.json @@ -5,7 +5,6 @@ "MapSnapshotterLocalStyleActivity", "LatLngBoundsActivity", "BottomSheetActivity", - "MapSnapshotterActivity", "MockLocationEngine", "DeleteRegionActivity", "RealTimeGeoJsonActivity", @@ -50,7 +49,5 @@ "EspressoTestActivity", "FragmentBackStackActivity", "ChildFragmentMapInDialogActivity", - "PerformanceMeasurementActivity", - "DownloadRegionActivity", - "CacheManagementActivity" + "PerformanceMeasurementActivity" ] diff --git a/src/file_source.cpp b/src/file_source.cpp index 05b57e5d1..a002d6616 100644 --- a/src/file_source.cpp +++ b/src/file_source.cpp @@ -1,5 +1,7 @@ #include "file_source.hpp" + #include "attach_env.hpp" +#include "mapbox.hpp" #include #include @@ -14,8 +16,15 @@ namespace mbgl { std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { - auto* assetFileSource = reinterpret_cast(options.platformContext()); - auto fileSource = std::make_shared(options.cachePath(), std::unique_ptr(assetFileSource)); + auto env{android::AttachEnv()}; + std::shared_ptr fileSource; + if (android::Mapbox::hasInstance(*env)) { + auto assetManager = android::Mapbox::getAssetManager(*env); + fileSource = std::make_shared(options.cachePath(), + std::make_unique(*env, assetManager)); + } else { + fileSource = std::make_shared(options.cachePath(), options.assetPath()); + } fileSource->setAccessToken(options.accessToken()); return fileSource; } @@ -24,17 +33,12 @@ namespace android { // FileSource // -FileSource::FileSource(jni::JNIEnv& _env, - const jni::String& accessToken, - const jni::String& _cachePath, - const jni::Object& assetManager) { +FileSource::FileSource(jni::JNIEnv& _env, const jni::String& accessToken, const jni::String& _cachePath) { std::string path = jni::Make(_env, _cachePath); mapbox::sqlite::setTempPath(path); - resourceOptions - .withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") - .withCachePath(path + DATABASE_FILE) - .withPlatformContext(reinterpret_cast(new AssetManagerFileSource(_env, assetManager))); + resourceOptions.withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE); // Create a core default file source fileSource = std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(resourceOptions)); @@ -58,14 +62,15 @@ void FileSource::setAPIBaseUrl(jni::JNIEnv& env, const jni::String& url) { void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object& transformCallback) { if (transformCallback) { auto global = jni::NewGlobal(env, transformCallback); - resourceTransform = std::make_unique>(*Scheduler::GetCurrent(), + resourceTransform = std::make_unique>( + *Scheduler::GetCurrent(), // Capture the ResourceTransformCallback object as a managed global into // the lambda. It is released automatically when we're setting a new ResourceTransform in // a subsequent call. // Note: we're converting it to shared_ptr because this lambda is converted to a std::function, // which requires copyability of its captured variables. - [callback = std::make_shared(std::move(global))] - (mbgl::Resource::Kind kind, const std::string&& url_) { + [callback = std::make_shared(std::move(global))](mbgl::Resource::Kind kind, + const std::string& url_) { android::UniqueEnv _env = android::AttachEnv(); return FileSource::ResourceTransformCallback::onURL(*_env, *callback, int(kind), url_); }); @@ -170,20 +175,20 @@ void FileSource::registerNative(jni::JNIEnv& env) { #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&FileSource::getAccessToken, "getAccessToken"), - METHOD(&FileSource::setAccessToken, "setAccessToken"), - METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), - METHOD(&FileSource::setResourceTransform, "setResourceTransform"), - METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), - METHOD(&FileSource::resume, "activate"), - METHOD(&FileSource::pause, "deactivate"), - METHOD(&FileSource::isResumed, "isActivated") - ); + jni::RegisterNativePeer(env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FileSource::getAccessToken, "getAccessToken"), + METHOD(&FileSource::setAccessToken, "setAccessToken"), + METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), + METHOD(&FileSource::setResourceTransform, "setResourceTransform"), + METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), + METHOD(&FileSource::resume, "activate"), + METHOD(&FileSource::pause, "deactivate"), + METHOD(&FileSource::isResumed, "isActivated")); } diff --git a/src/file_source.hpp b/src/file_source.hpp index f3ad33eb3..6a9190fa0 100644 --- a/src/file_source.hpp +++ b/src/file_source.hpp @@ -41,7 +41,7 @@ public: const jni::String&); }; - FileSource(jni::JNIEnv&, const jni::String&, const jni::String&, const jni::Object&); + FileSource(jni::JNIEnv&, const jni::String&, const jni::String&); ~FileSource(); diff --git a/src/i18n/collator.cpp b/src/i18n/collator.cpp new file mode 100644 index 000000000..b3dd8e21b --- /dev/null +++ b/src/i18n/collator.cpp @@ -0,0 +1,194 @@ +#include +#include + +#include + +#include "../attach_env.hpp" +#include "collator_jni.hpp" + +namespace mbgl { +namespace android { + +void Collator::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setStrength"); + collator.Call(env, method, strength); +} + +jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "compare"); + return collator.Call(env, method, lhs, rhs); +} + +void StringUtils::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(env, "unaccent"); + return javaClass.Call(env, method, value); +} + +void Locale::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +/* +We would prefer to use for/toLanguageTag, but they're only available in API level 21+ + +jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { + using Signature = jni::Object(jni::String); + auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); + return javaClass.Call(env, method, languageTag); +} + +jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { + using Signature = jni::String(); + auto static method = javaClass.GetMethod(env, "toLanguageTag"); + return locale.Call(env, method); +} +*/ + +jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getLanguage"); + return locale.Call(env, method); +} + +jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getCountry"); + return locale.Call(env, method); +} + +jni::Local> Locale::getDefault(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); + return javaClass.Call(env, method); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language, region); +} + +} // namespace android + +namespace platform { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + , env(android::AttachEnv()) + { + LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, + android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); + if (!diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); + } else if (diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); + } else if (caseSensitive) { + // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator + // and a fallback implementation of diacritic-insensitivity. + android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); + } + } + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && + diacriticSensitive == other.diacriticSensitive && + resolvedLocale() == other.resolvedLocale(); + } + + int compare(const std::string& lhs, const std::string& rhs) const { + bool useUnaccent = !diacriticSensitive && caseSensitive; + // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation + // order, so we have to compromise here. We use Android's case-sensitive Collator + // against strings that have been "unaccented" using non-locale-aware nunicode logic. + // Because of the difference in locale-awareness, this means turning on case-sensitivity + // can _potentially_ change compare results for strings that don't actually have any case + // differences. + jni::Local jlhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) + : jni::Make(*env, lhs); + jni::Local jrhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) + : jni::Make(*env, rhs); + + jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); + + return result; + } + + std::string resolvedLocale() const { + std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); + std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); + + optional resultLanguage; + if (!language.empty()) resultLanguage = language; + optional resultRegion; + if (!region.empty()) resultRegion = region; + + return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); + } + +private: + bool caseSensitive; + bool diacriticSensitive; + + android::UniqueEnv env; + jni::Global> collator; + jni::Global> locale; +}; + + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) + : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) +{} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/i18n/collator_jni.hpp b/src/i18n/collator_jni.hpp new file mode 100644 index 000000000..612f9b49f --- /dev/null +++ b/src/i18n/collator_jni.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +/* + android::Collator and android::Locale are + the JNI wrappers of + java/text/Collator and java/util/Locale + + mbgl::Collator is the portable interface + Both implementations are in collator.cpp + */ + +namespace mbgl { +namespace android { + +class Locale { +public: + static constexpr auto Name() { return "java/util/Locale"; }; + + /* Requires API level 21+ in order to support script/variant + static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); + static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); + */ + static jni::Local> getDefault(jni::JNIEnv&); + static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); + static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::String&); + static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +class Collator { +public: + static constexpr auto Name() { return "java/text/Collator"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + + static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); + + static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + + +class StringUtils { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; + + static jni::Local unaccent(jni::JNIEnv&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/i18n/number_format.cpp b/src/i18n/number_format.cpp new file mode 100644 index 000000000..c8e0b7056 --- /dev/null +++ b/src/i18n/number_format.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include + +#include "../attach_env.hpp" +#include "number_format_jni.hpp" + +namespace mbgl { +namespace android { + +void NumberFormat::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "format"); + return nf.Call(env, method, number); +} + +void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); + return nf.Call(env, method, value); +} + +void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); + return nf.Call(env, method, value); +} + +} // namespace android + +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + auto env{ android::AttachEnv() }; + + jni::Global> locale; + LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + + jni::Global> formatter; + if (currency.empty()) { + formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); + android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); + android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); + } else { + formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); + } + + auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); + return jni::Make(*env, result); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/i18n/number_format_jni.hpp b/src/i18n/number_format_jni.hpp new file mode 100644 index 000000000..172003892 --- /dev/null +++ b/src/i18n/number_format_jni.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "collator_jni.hpp" + +/* + android::NumberFormat is the JNI wrapper + of java/text/NumberFormat. + */ + +namespace mbgl { +namespace android { + +class NumberFormat { +public: + static constexpr auto Name() { return "java/text/NumberFormat"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); + static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/jni_native.cpp b/src/jni_native.cpp old mode 100755 new mode 100644 index df96ba975..bcbdfcf48 --- a/src/jni_native.cpp +++ b/src/jni_native.cpp @@ -6,8 +6,8 @@ #include "bitmap.hpp" #include "bitmap_factory.hpp" #include "connectivity_listener.hpp" -#include "conversion/conversion.hpp" #include "conversion/collection.hpp" +#include "conversion/conversion.hpp" #include "file_source.hpp" #include "geojson/feature.hpp" #include "geojson/feature_collection.hpp" @@ -32,6 +32,7 @@ #include "java_types.hpp" #include "map_renderer.hpp" #include "map_renderer_runnable.hpp" +#include "mapbox.hpp" #include "native_map_view.hpp" #ifndef MBGL_MODULE_OFFLINE_DISABLE #include "offline/offline_manager.hpp" @@ -50,10 +51,10 @@ #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" #endif -#include "text/collator_jni.hpp" -#include "text/local_glyph_rasterizer_jni.hpp" -#include "text/format_number_jni.hpp" +#include "i18n/collator_jni.hpp" +#include "i18n/number_format_jni.hpp" #include "logger.hpp" +#include "text/local_glyph_rasterizer_jni.hpp" namespace mbgl { namespace android { @@ -158,6 +159,9 @@ void registerNatives(JavaVM *vm) { // Logger Logger::registerNative(env); + + // AssetManager + Mapbox::registerNative(env); } } // namespace android diff --git a/src/jni_native.hpp b/src/jni_native.hpp index c8e284a52..1cc9a7e81 100644 --- a/src/jni_native.hpp +++ b/src/jni_native.hpp @@ -7,7 +7,7 @@ namespace mbgl { namespace android { -MBGL_PUBLIC void registerNatives(JavaVM* vm); +MBGL_EXPORT void registerNatives(JavaVM* vm); } // namespace android } // namespace mbgl diff --git a/src/map/camera_position.cpp b/src/map/camera_position.cpp index 03aca79bd..4266b64fd 100644 --- a/src/map/camera_position.cpp +++ b/src/map/camera_position.cpp @@ -44,19 +44,20 @@ mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni static auto tilt = javaClass.GetField(env, "tilt"); static auto zoom = javaClass.GetField(env, "zoom"); static auto paddingField = javaClass.GetField>(env, "padding"); - static auto padding = position.Get(env, paddingField); + auto padding = position.Get(env, paddingField); auto center = LatLng::getLatLng(env, position.Get(env, target)); - return mbgl::CameraOptions { - center, - EdgeInsets {padding.Get(env, 1) * pixelRatio, padding.Get(env, 0) * pixelRatio, - padding.Get(env, 3) * pixelRatio, padding.Get(env, 2) * pixelRatio}, - {}, - position.Get(env, zoom), - position.Get(env, bearing), - position.Get(env, tilt) - }; + return mbgl::CameraOptions{center, + padding && padding.Length(env) == 4 ? EdgeInsets{padding.Get(env, 1) * pixelRatio, + padding.Get(env, 0) * pixelRatio, + padding.Get(env, 3) * pixelRatio, + padding.Get(env, 2) * pixelRatio} + : (EdgeInsets){}, + {}, + position.Get(env, zoom), + position.Get(env, bearing), + position.Get(env, tilt)}; } void CameraPosition::registerNative(jni::JNIEnv &env) { diff --git a/src/map_renderer.cpp b/src/map_renderer.cpp index 6be708b99..0c0e907f1 100644 --- a/src/map_renderer.cpp +++ b/src/map_renderer.cpp @@ -43,7 +43,7 @@ ActorRef MapRenderer::actor() const { return *rendererRef; } -void MapRenderer::schedule(std::weak_ptr scheduled) { +void MapRenderer::schedule(std::function scheduled) { // Create a runnable android::UniqueEnv _env = android::AttachEnv(); auto runnable = std::make_unique(*_env, std::move(scheduled)); diff --git a/src/map_renderer.hpp b/src/map_renderer.hpp index 5a8ddeeb9..664da20a9 100644 --- a/src/map_renderer.hpp +++ b/src/map_renderer.hpp @@ -67,7 +67,7 @@ public: // From Scheduler. Schedules by using callbacks to the // JVM to process the mailbox on the right thread. - void schedule(std::weak_ptr scheduled) override; + void schedule(std::function scheduled) override; void requestRender(); diff --git a/src/map_renderer_runnable.cpp b/src/map_renderer_runnable.cpp index 77c3aa301..227f49ee3 100644 --- a/src/map_renderer_runnable.cpp +++ b/src/map_renderer_runnable.cpp @@ -5,9 +5,8 @@ namespace mbgl { namespace android { -MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr mailbox_) - : mailbox(std::move(mailbox_)) { - +MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::function function_) + : function(std::move(function_)) { // Create the Java peer and hold on to a global reference // Not using a weak reference here as this might oerflow // the weak reference table on some devices @@ -21,7 +20,7 @@ MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr> MapRendererRunnable::peer() { diff --git a/src/map_renderer_runnable.hpp b/src/map_renderer_runnable.hpp index 21c4369b6..24d0f2af4 100644 --- a/src/map_renderer_runnable.hpp +++ b/src/map_renderer_runnable.hpp @@ -24,7 +24,7 @@ public: static void registerNative(jni::JNIEnv&); - MapRendererRunnable(jni::JNIEnv&, std::weak_ptr); + MapRendererRunnable(jni::JNIEnv&, std::function); // Only for jni registration, unused MapRendererRunnable(jni::JNIEnv&) { @@ -40,7 +40,7 @@ public: private: jni::Global> javaPeer; - std::weak_ptr mailbox; + std::function function; }; } // namespace android diff --git a/src/mapbox.cpp b/src/mapbox.cpp new file mode 100644 index 000000000..5246739cf --- /dev/null +++ b/src/mapbox.cpp @@ -0,0 +1,23 @@ +#include "mapbox.hpp" + +namespace mbgl { +namespace android { + +jni::Local> Mapbox::getAssetManager(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod()>(env, "getAssetManager"); + return javaClass.Call(env, method); +} + +jboolean Mapbox::hasInstance(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod(env, "hasInstance"); + return javaClass.Call(env, method); +} + +void Mapbox::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/src/mapbox.hpp b/src/mapbox.hpp new file mode 100644 index 000000000..813f5bf17 --- /dev/null +++ b/src/mapbox.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "asset_manager.hpp" + +#include + +namespace mbgl { +namespace android { + +class Mapbox { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/Mapbox"; }; + static jboolean hasInstance(jni::JNIEnv&); + static jni::Local> getAssetManager(jni::JNIEnv&); + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/src/native_map_view.cpp b/src/native_map_view.cpp old mode 100755 new mode 100644 index 8ef757de1..8cb637fa3 --- a/src/native_map_view.cpp +++ b/src/native_map_view.cpp @@ -40,19 +40,19 @@ #include "style/conversion/filter.hpp" #include "geojson/feature.hpp" -#include "jni.hpp" -#include "attach_env.hpp" -#include "map_renderer.hpp" #include "android_renderer_frontend.hpp" -#include "file_source.hpp" +#include "attach_env.hpp" #include "bitmap.hpp" -#include "run_loop_impl.hpp" -#include "java/util.hpp" -#include "geometry/lat_lng_bounds.hpp" -#include "map/camera_position.hpp" -#include "map/image.hpp" -#include "style/light.hpp" #include "bitmap_factory.hpp" +#include "file_source.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "java/util.hpp" +#include "jni.hpp" +#include "map/camera_position.hpp" +#include "map/image.hpp" +#include "map_renderer.hpp" +#include "run_loop_impl.hpp" +#include "style/light.hpp" namespace mbgl { namespace android { @@ -185,7 +185,7 @@ void NativeMapView::onWillStartRenderingFrame() { } } -void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode, bool) { +void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderFrameStatus status) { assert(vm != nullptr); android::UniqueEnv _env = android::AttachEnv(); @@ -193,7 +193,7 @@ void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode, bool static auto onDidFinishRenderingFrame = javaClass.GetMethod(*_env, "onDidFinishRenderingFrame"); auto weakReference = javaPeer.get(*_env); if (weakReference) { - weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (mode != MapObserver::RenderMode::Partial)); + weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (status.mode != MapObserver::RenderMode::Partial)); } } @@ -1050,6 +1050,14 @@ jni::jboolean NativeMapView::getPrefetchTiles(JNIEnv&) { return jni::jboolean(map->getPrefetchZoomDelta() > 0); } +void NativeMapView::setPrefetchZoomDelta(JNIEnv&, jni::jint delta) { + map->setPrefetchZoomDelta(uint8_t(delta)); +} + +jni::jint NativeMapView::getPrefetchZoomDelta(JNIEnv&) { + return jni::jint(map->getPrefetchZoomDelta()); +} + mbgl::Map& NativeMapView::getMap() { return *map; } @@ -1063,90 +1071,99 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - jni::MakePeer&, const jni::Object&, const jni::Object&, jni::jfloat, jni::jboolean>, - "nativeInitialize", - "nativeDestroy", - METHOD(&NativeMapView::resizeView, "nativeResizeView"), - METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), - METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), - METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), - METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), - METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), - METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), - METHOD(&NativeMapView::moveBy, "nativeMoveBy"), - METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), - METHOD(&NativeMapView::easeTo, "nativeEaseTo"), - METHOD(&NativeMapView::flyTo, "nativeFlyTo"), - METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), - METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), - METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), - METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), - METHOD(&NativeMapView::setReachability, "nativeSetReachability"), - METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), - METHOD(&NativeMapView::getPitch, "nativeGetPitch"), - METHOD(&NativeMapView::setPitch, "nativeSetPitch"), - METHOD(&NativeMapView::getZoom, "nativeGetZoom"), - METHOD(&NativeMapView::setZoom, "nativeSetZoom"), - METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), - METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), - METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), - METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), - METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), - METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), - METHOD(&NativeMapView::setBearing, "nativeSetBearing"), - METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), - METHOD(&NativeMapView::getBearing, "nativeGetBearing"), - METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), - METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), - METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), - METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), - METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), - METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), - METHOD(&NativeMapView::setDebug, "nativeSetDebug"), - METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), - METHOD(&NativeMapView::getDebug, "nativeGetDebug"), - METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), - METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), - METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), - METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), - METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), - METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), - METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), - METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), - METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), - METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), - METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), - METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), - METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), - METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), - METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), - METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), - METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), - METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), - METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), - METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), - METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), - METHOD(&NativeMapView::getLight, "nativeGetLight"), - METHOD(&NativeMapView::getLayers, "nativeGetLayers"), - METHOD(&NativeMapView::getLayer, "nativeGetLayer"), - METHOD(&NativeMapView::addLayer, "nativeAddLayer"), - METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), - METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), - METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), - METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), - METHOD(&NativeMapView::getSources, "nativeGetSources"), - METHOD(&NativeMapView::getSource, "nativeGetSource"), - METHOD(&NativeMapView::addSource, "nativeAddSource"), - METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), - METHOD(&NativeMapView::addImage, "nativeAddImage"), - METHOD(&NativeMapView::addImages, "nativeAddImages"), - METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), - METHOD(&NativeMapView::getImage, "nativeGetImage"), - METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), - METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), - METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles") - ); + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer&, + const jni::Object&, + const jni::Object&, + jni::jfloat, + jni::jboolean>, + "nativeInitialize", + "nativeDestroy", + METHOD(&NativeMapView::resizeView, "nativeResizeView"), + METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), + METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), + METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), + METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), + METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), + METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), + METHOD(&NativeMapView::moveBy, "nativeMoveBy"), + METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), + METHOD(&NativeMapView::easeTo, "nativeEaseTo"), + METHOD(&NativeMapView::flyTo, "nativeFlyTo"), + METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), + METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), + METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), + METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), + METHOD(&NativeMapView::setReachability, "nativeSetReachability"), + METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), + METHOD(&NativeMapView::getPitch, "nativeGetPitch"), + METHOD(&NativeMapView::setPitch, "nativeSetPitch"), + METHOD(&NativeMapView::getZoom, "nativeGetZoom"), + METHOD(&NativeMapView::setZoom, "nativeSetZoom"), + METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), + METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), + METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), + METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), + METHOD(&NativeMapView::setBearing, "nativeSetBearing"), + METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), + METHOD(&NativeMapView::getBearing, "nativeGetBearing"), + METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), + METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), + METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), + METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), + METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), + METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), + METHOD(&NativeMapView::setDebug, "nativeSetDebug"), + METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), + METHOD(&NativeMapView::getDebug, "nativeGetDebug"), + METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), + METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), + METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), + METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), + METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), + METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), + METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), + METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), + METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), + METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), + METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), + METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), + METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), + METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), + METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), + METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), + METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), + METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), + METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), + METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), + METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), + METHOD(&NativeMapView::getLight, "nativeGetLight"), + METHOD(&NativeMapView::getLayers, "nativeGetLayers"), + METHOD(&NativeMapView::getLayer, "nativeGetLayer"), + METHOD(&NativeMapView::addLayer, "nativeAddLayer"), + METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), + METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), + METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), + METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), + METHOD(&NativeMapView::getSources, "nativeGetSources"), + METHOD(&NativeMapView::getSource, "nativeGetSource"), + METHOD(&NativeMapView::addSource, "nativeAddSource"), + METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), + METHOD(&NativeMapView::addImage, "nativeAddImage"), + METHOD(&NativeMapView::addImages, "nativeAddImages"), + METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), + METHOD(&NativeMapView::getImage, "nativeGetImage"), + METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), + METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), + METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles"), + METHOD(&NativeMapView::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), + METHOD(&NativeMapView::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta")); } } // namespace android diff --git a/src/native_map_view.hpp b/src/native_map_view.hpp index 26567a003..5a340d128 100755 --- a/src/native_map_view.hpp +++ b/src/native_map_view.hpp @@ -62,7 +62,7 @@ public: void onDidFinishLoadingMap() override; void onDidFailLoadingMap(MapLoadError, const std::string&) override; void onWillStartRenderingFrame() override; - void onDidFinishRenderingFrame(MapObserver::RenderMode, bool) override; + void onDidFinishRenderingFrame(MapObserver::RenderFrameStatus) override; void onWillStartRenderingMap() override; void onDidFinishRenderingMap(MapObserver::RenderMode) override; void onDidBecomeIdle() override; @@ -235,6 +235,10 @@ public: jni::jboolean getPrefetchTiles(JNIEnv&); + void setPrefetchZoomDelta(JNIEnv&, jni::jint); + + jni::jint getPrefetchZoomDelta(JNIEnv&); + mbgl::Map& getMap(); private: diff --git a/src/style/sources/source.cpp b/src/style/sources/source.cpp index be4c0367f..786e5cb58 100644 --- a/src/style/sources/source.cpp +++ b/src/style/sources/source.cpp @@ -133,7 +133,7 @@ namespace android { // Release the peer relationships. These will be re-established when the source is added to a map assert(ownedSource->peer.has_value()); ownedSource->peer.get>().release(); - ownedSource->peer = util::peer(); + ownedSource->peer = mapbox::base::TypeWrapper(); // Release the strong reference to the java peer assert(javaPeer); diff --git a/src/test/version-script b/src/test/version-script new file mode 100644 index 000000000..ebc2c1701 --- /dev/null +++ b/src/test/version-script @@ -0,0 +1,8 @@ +{ +global: + EnsureFrontOfChain; + AddSpecialSignalHandlerFn; + RemoveSpecialSignalHandlerFn; +local: + *; +}; diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 89eaac05e..b4e0224a5 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 89eaac05ebc2928e59d3f0404f7b92bdb42b92bb +Subproject commit b4e0224a5786f1d362b2b6b7e7f536be8bb98981 From 83acc3ad3e47d71e57dcd459b54574c709d54ed5 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 18:55:51 +0200 Subject: [PATCH 004/185] [build] use next buildsystem from gl-native --- gradle/native-build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index 9e8f58015..f127cb3ed 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -21,7 +21,7 @@ ext.nativeBuild = { nativeTargets -> if (abi != 'none') { externalNativeBuild { cmake { - path "../vendor/mapbox-gl-native/CMakeLists.txt" + path "../vendor/mapbox-gl-native/next/CMakeLists.txt" version "3.10.2" } } From 7acfd3a243d23b6a6d1489060f47e2deddee9a60 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 14:19:03 +0200 Subject: [PATCH 005/185] [build] rework scripts to new build system --- .gitignore | 5 ++++- README.md | 4 ++-- gradle/android-nitpick.gradle | 2 +- package-lock.json | 26 ++++++++++++++++++++++++ package.json | 25 +++++++++++++++++++++++ scripts/generate-license.py | 6 +++--- scripts/generate-style-code.js | 36 +++++++++++++++++----------------- scripts/generate-test-code.js | 8 ++++---- scripts/metrics.sh | 10 +++++----- scripts/parse-jacoco-report.py | 2 +- scripts/run-render-test.py | 4 ++-- scripts/validate-license.py | 2 +- 12 files changed, 92 insertions(+), 38 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore index ff3db8735..37b7600a5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,7 @@ MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/acti MapboxGLAndroidSDKTestApp/src/main/assets/integration/ # Local AS configuration file -gradle.properties \ No newline at end of file +gradle.properties + +# Node modules +node_modules \ No newline at end of file diff --git a/README.md b/README.md index b7b2cb225..af3968de9 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ make aproj #### linux -run `make android-configuration` in the root folder of the project and open the Android Studio project in `/platform/android`. +run `make android-configuration` in the root folder of the project and open in Android Studio. If you are using Arch Linux, install [ncurses5-compat-libs](https://aur.archlinux.org/packages/ncurses5-compat-libs). @@ -88,7 +88,7 @@ With the first gradle invocation, gradle will take the value of the `MAPBOX_ACCE Run the configuration for the `MapboxGLAndroidSDKTestApp` module and select a device or emulator to deploy on. Based on the selected device, the c++ code will be compiled for the related processor architecture. You can see the project compiling in the `View > Tool Windows > Gradle Console`. -More information about building and distributing this project in [DISTRIBUTE.md](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/DISTRIBUTE.md). +More information about building and distributing this project in [DISTRIBUTE.md](DISTRIBUTE.md). ### Additional resources diff --git a/gradle/android-nitpick.gradle b/gradle/android-nitpick.gradle index 6db351967..9de46d8cf 100644 --- a/gradle/android-nitpick.gradle +++ b/gradle/android-nitpick.gradle @@ -51,7 +51,7 @@ private def verifyVendorSubmodulePin(def dir, def prefix, def version) { throw new IllegalStateException("${dir} vendor repository is not checked out on the consumed binary's tag.\n" + "Expected commit: " + expectedCommit + "(${prefix + version} tag).\n" + "Actual commit: " + actualCommit + ".\n" + - "If you've updated the version in the dependencies.gradle file, make sure to bump the submodule pin in the platform/android/vendor/ directory to match the release tag.\n" + + "If you've updated the version in the dependencies.gradle file, make sure to bump the submodule pin in the /vendor directory to match the release tag.\n" + "If you've bumped the pin, make sure to verify the version tag prefix in the android-nitpick.gradle file.") } output.close() diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..08419e91e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,26 @@ +{ + "name": "@mapbox/mapbox-gl-native-android", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ejs": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", + "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", + "dev": true + }, + "esm": { + "version": "3.0.84", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.0.84.tgz", + "integrity": "sha512-SzSGoZc17S7P+12R9cg21Bdb7eybX25RnIeRZ80xZs+VZ3kdQKzqTp2k4hZJjR7p9l0186TTXSgrxzlMDBktlw==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..08e60e15e --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "@mapbox/mapbox-gl-native-android", + "version": "1.0.0", + "description": "Renders map tiles with the Mapbox Maps SDK for Android", + "keywords": [ + "mapbox", + "gl" + ], + "repository": { + "type": "git", + "url": "git@github.com:mapbox/mapbox-gl-native-android.git" + }, + "license": "BSD-2-Clause", + "dependencies": {}, + "devDependencies": { + "ejs": "^2.5.7", + "esm": "~3.0.84", + "lodash": "^4.16.4", + "pixelmatch": "^4.0.2" + }, + "engines": { + "node": ">=6" + }, + "scripts": {} +} diff --git a/scripts/generate-license.py b/scripts/generate-license.py index 9e59cb418..c78ba9cba 100644 --- a/scripts/generate-license.py +++ b/scripts/generate-license.py @@ -3,11 +3,11 @@ import os import json -path = os.getcwd() + "/platform/android/" -with open(path + "LICENSE.md", 'w') as licenseFile: +path = os.getcwd() +with open(path + "/LICENSE.md", 'w') as licenseFile: licenseFile.write(" \n") licenseFile.write("## Additional Mapbox GL licenses \n") - with open(path + "MapboxGLAndroidSDK/build/reports/licenses/licenseReleaseReport.json", 'r') as dataFile: + with open(path + "/MapboxGLAndroidSDK/build/reports/licenses/licenseReleaseReport.json", 'r') as dataFile: data = json.load(dataFile) gradleLicensePlugin =""" diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index fa814f89a..652b8a98a 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -3,7 +3,7 @@ const fs = require('fs'); const ejs = require('ejs'); -const spec = require('../../../scripts/style-spec'); +const spec = require('../vendor/mapbox-gl-native/scripts/style-spec'); const _ = require('lodash'); // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 @@ -11,7 +11,7 @@ delete spec.layout_circle["circle-sort-key"] delete spec.layout_line["line-sort-key"] delete spec.layout_fill["fill-sort-key"] -require('../../../scripts/style-code'); +require('../vendor/mapbox-gl-native/scripts/style-code'); // Specification parsing // const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => { @@ -361,34 +361,34 @@ global.supportsPropertyFunction = function (property) { // Template processing // // Java + JNI Light (Peer model) -const lightJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs', 'utf8'), {strict: true}); -const lightJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs', 'utf8'), {strict: true}); -writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties})); -writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties})); +const lightJava = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs', 'utf8'), {strict: true}); +const lightJavaUnitTests = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs', 'utf8'), {strict: true}); +writeIfModified(`MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties})); +writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties})); // Java + JNI Layers (Peer model) -const layerHpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); -const layerCpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); -const layerJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs', 'utf8'), {strict: true}); -const layerJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs', 'utf8'), {strict: true}); +const layerHpp = ejs.compile(fs.readFileSync('src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); +const layerCpp = ejs.compile(fs.readFileSync('src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); +const layerJava = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs', 'utf8'), {strict: true}); +const layerJavaUnitTests = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs', 'utf8'), {strict: true}); for (const layer of layers) { - writeIfModified(`platform/android/src/style/layers/${layer.type.replace('-', '_')}_layer.hpp`, layerHpp(layer)); - writeIfModified(`platform/android/src/style/layers/${layer.type.replace('-', '_')}_layer.cpp`, layerCpp(layer)); - writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer)); - writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); + writeIfModified(`src/style/layers/${layer.type.replace('-', '_')}_layer.hpp`, layerHpp(layer)); + writeIfModified(`src/style/layers/${layer.type.replace('-', '_')}_layer.cpp`, layerCpp(layer)); + writeIfModified(`MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer)); + writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); } // Java PropertyFactory -const propertiesTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); +const propertiesTemplate = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); writeIfModified( - `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java`, + `MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java`, propertiesTemplate({layoutProperties: layoutProperties, paintProperties: paintProperties}) ); // Java Property -const enumPropertyJavaTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs', 'utf8'), {strict: true}); +const enumPropertyJavaTemplate = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs', 'utf8'), {strict: true}); writeIfModified( - `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`, + `MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`, enumPropertyJavaTemplate({properties: enumProperties}) ); diff --git a/scripts/generate-test-code.js b/scripts/generate-test-code.js index 64b38e5ac..e3684d181 100644 --- a/scripts/generate-test-code.js +++ b/scripts/generate-test-code.js @@ -13,11 +13,11 @@ global.camelize = function (str) { }); } -const excludeClasses = JSON.parse(fs.readFileSync('platform/android/scripts/exclude-activity-gen.json', 'utf8')); -const appBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity'; -const testBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen'; +const excludeClasses = JSON.parse(fs.readFileSync('scripts/exclude-activity-gen.json', 'utf8')); +const appBasePath = 'MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity'; +const testBasePath = 'MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen'; const subPackages = fs.readdirSync(appBasePath); -const ejsConversionTask = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs', 'utf8'), {strict: true}); +const ejsConversionTask = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs', 'utf8'), {strict: true}); if (!fs.existsSync(testBasePath)){ fs.mkdirSync(testBasePath); diff --git a/scripts/metrics.sh b/scripts/metrics.sh index cc33daf17..a59429b58 100755 --- a/scripts/metrics.sh +++ b/scripts/metrics.sh @@ -4,13 +4,13 @@ set -e set -o pipefail # Track individual architectures -scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/armeabi-v7a/libmapbox-gl.so" "Android arm-v7" -scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/arm64-v8a/libmapbox-gl.so" "Android arm-v8" -scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86/libmapbox-gl.so" "Android x86" -scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86_64/libmapbox-gl.so" "Android x86_64" +scripts/check_binary_size.js "MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/armeabi-v7a/libmapbox-gl.so" "Android arm-v7" +scripts/check_binary_size.js "MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/arm64-v8a/libmapbox-gl.so" "Android arm-v8" +scripts/check_binary_size.js "MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86/libmapbox-gl.so" "Android x86" +scripts/check_binary_size.js "MapboxGLAndroidSDK/build/intermediates/intermediate-jars/release/jni/x86_64/libmapbox-gl.so" "Android x86_64" # Track overall library size -scripts/check_binary_size.js "platform/android/MapboxGLAndroidSDK/build/outputs/aar/MapboxGLAndroidSDK-release.aar" "Android AAR" +scripts/check_binary_size.js "MapboxGLAndroidSDK/build/outputs/aar/MapboxGLAndroidSDK-release.aar" "Android AAR" if [[ $CIRCLE_BRANCH == master ]]; then # Build source data for http://mapbox.github.io/mapbox-gl-native/metrics/binary-size/ diff --git a/scripts/parse-jacoco-report.py b/scripts/parse-jacoco-report.py index 4d06fda6c..3577947de 100755 --- a/scripts/parse-jacoco-report.py +++ b/scripts/parse-jacoco-report.py @@ -4,7 +4,7 @@ import os import re from io import open -reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +reportPath = os.getcwd() + "/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" with open(reportPath, 'r', encoding='utf-8') as jacocoReport: line = jacocoReport.readline().strip() diff --git a/scripts/run-render-test.py b/scripts/run-render-test.py index 940ae7a3d..540dbed15 100644 --- a/scripts/run-render-test.py +++ b/scripts/run-render-test.py @@ -3,13 +3,13 @@ import os import shutil -catPath = os.getcwd() + "/platform/android/build/render-test/" +catPath = os.getcwd() + "/build/render-test/" failCounter = 0 testCounter = 0 for cat in os.listdir(catPath): testPath = catPath + cat + "/" for test in os.listdir(testPath): - inputPath = os.getcwd() + "/mapbox-gl-js/test/integration/render-tests/" + cat + "/" + test + inputPath = os.getcwd() + "vendor/mapbox-gl-native/mapbox-gl-js/test/integration/render-tests/" + cat + "/" + test outputPath = testPath + test expected = outputPath + "/expected.png" diff --git a/scripts/validate-license.py b/scripts/validate-license.py index 1c9a153b8..ae8859537 100644 --- a/scripts/validate-license.py +++ b/scripts/validate-license.py @@ -10,7 +10,7 @@ call('cd ../../ && make android-license', shell=True) ## Git diff changes p = Popen(['git', 'diff', '--name-only', 'LICENSE.md'], stdin=PIPE, stdout=PIPE, stderr=PIPE) output, err = p.communicate(b"input data that is passed to subprocess' stdin") -if b"platform/android/LICENSE.md" in output: +if b"LICENSE.md" in output: raise ValueError("""An error ocurred while validating the license generation. Changes were detected to the license generation output but weren't commited. Run make android-license and From 529616a0e7b05b33998049408bebb86f377bc8f7 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 9 Oct 2019 19:36:30 +0200 Subject: [PATCH 006/185] [build] add continous integration --- .circleci/config.yml | 337 +++++++++++++++++++++++++++ .gitignore | 3 - Makefile | 22 ++ MapboxGLAndroidSDK/gradle.properties | 9 + gradle/native-build.gradle | 3 + package-lock.json | 15 ++ vendor/mapbox-java | 2 +- 7 files changed, 387 insertions(+), 4 deletions(-) create mode 100644 .circleci/config.yml create mode 100644 MapboxGLAndroidSDK/gradle.properties diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..54fb39d29 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,337 @@ +version: 2.1 + +workflows: + version: 2 + mapbox-gl-native-android: + jobs: + - android-arm-template: + name: android-debug-arm-v8 + - android-release: + filters: + tags: + only: /android-v.*/ + +commands: + npm-install: + steps: + - run: + name: npm install + command: npm install --ignore-scripts + prepare-ccache: + steps: + - run: + name: Prepare ccache + command: | + # CircleCI doesn't have any way to embed arbitrary environment variables or command output + # into cache keys, so we're using the workaround of writing the desired content to a file, + # and then using `{{ checksum "filename" }}` in the cache key. + echo "$CIRCLE_BRANCH" + echo "$CIRCLE_BRANCH" > .circle-branch + echo "$CIRCLE_SHA1" + echo "$CIRCLE_SHA1" > .circle-sha1 + echo "$CIRCLE_TARGET_BRANCH" + echo "${CIRCLE_TARGET_BRANCH:master}" > .circle-target-branch + echo "$CIRCLE_MERGE_BASE" + echo "${CIRCLE_MERGE_BASE:master}" > .circle-merge-base + ccache --clear + reset-ccache-stats: + steps: + - run: + name: Clear ccache statistics + command: | + ccache --zero-stats + ccache --max-size=2G + ccache --show-stats + show-ccache-stats: + steps: + - run: + name: Show ccache statistics + command: ccache --show-stats + save-node_modules-cache: + steps: + - save_cache: + name: Save node_modules cache + key: 'node_modules/v1/{{ arch }}/{{ checksum "package.json" }}' + paths: [ "node_modules" ] + restore-node_modules-cache: + steps: + - restore_cache: + name: Restore node_modules cache + keys: + - 'node_modules/v1/{{ arch }}/{{ checksum "package.json" }}' + - 'node_modules/v1/{{ arch }}' + save-ccache: + steps: + - save_cache: + name: Save ccache + key: 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}/{{ checksum ".circle-branch" }}/{{ checksum ".circle-sha1" }}' + paths: [ "~/.ccache" ] + restore-ccache: + steps: + - restore_cache: + name: Restore ccache + keys: + - 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}/{{ checksum ".circle-branch" }}/{{ checksum ".circle-sha1" }}' + - 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}/{{ checksum ".circle-branch" }}' + - 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}/{{ checksum ".circle-target-branch" }}/{{ checksum ".circle-merge-base" }}' + - 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}/{{ checksum ".circle-target-branch" }}' + - 'ccache/v1/{{ arch }}/{{ .Environment.CIRCLE_JOB }}' + save-gradle-cache: + steps: + - save_cache: + name: Save gradle cache + key: 'gradle/v1/{{ checksum "gradle/dependencies.gradle" }}/{{ checksum "build.gradle" }}/{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}' + paths: [ "/root/.gradle" ] + restore-gradle-cache: + steps: + - restore_cache: + name: Restore gradle cache + keys: + - 'gradle/v1/{{ checksum "gradle/dependencies.gradle" }}/{{ checksum "build.gradle" }}/{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}' + - 'gradle/v1' + install-dependencies: + parameters: + node_modules: + type: boolean + default: true + ccache: + type: boolean + default: true + gradle: + type: boolean + default: false + steps: + - checkout + - when: + condition: << parameters.node_modules >> + steps: [ restore-node_modules-cache, npm-install ] + - when: + condition: << parameters.ccache >> + steps: [ prepare-ccache, restore-ccache, reset-ccache-stats ] + - when: + condition: << parameters.gradle >> + steps: [ restore-gradle-cache ] + save-dependencies: + parameters: + node_modules: + type: boolean + default: true + ccache: + type: boolean + default: true + gradle: + type: boolean + default: false + steps: + - when: + condition: << parameters.node_modules >> + steps: [ save-node_modules-cache ] + - when: + condition: << parameters.ccache >> + steps: [ save-ccache, show-ccache-stats ] + - when: + condition: << parameters.gradle >> + steps: [ save-gradle-cache ] + setup-llvm-symbolizer: + steps: + - run: + name: Environment Setup + command: | + # LLVM has a hard check for "llvm-symbolizer" and doesn't support suffixed executables + ln -s /usr/bin/llvm-symbolizer-* /usr/bin/llvm-symbolizer + # We'll use tee to redirect stderr to a file so we can check for sanitiziation + # https://bugs.launchpad.net/ubuntu/+source/xorg-server/+bug/1059947 + sed -i 's/"$@" 2>&1/"$@"/' /usr/bin/xvfb-run + configure-cmake: + steps: + - run: + name: CMake configuration step + command: | + mkdir -p build + cd build + cmake -DWITH_COVERAGE=${WITH_COVERAGE:0} -DWITH_OSMESA=${WITH_OSMESA:0} -DWITH_EGL=${WITH_EGL:0} .. + cd .. + login-google-cloud-platform: + steps: + - run: + name: Log in to Google Cloud Platform + command: | + if [[ -n "${GLCLOUD_SERVICE_JSON}" ]]; then + echo "${GLCLOUD_SERVICE_JSON}" > secret.json + gcloud auth activate-service-account --key-file secret.json --project mapbox-gl-native-android + rm secret.json + fi + +jobs: + # ------------------------------------------------------------------------------ + android-arm-template: + parameters: + stl: + type: string + default: "c++_static" + image: + type: string + default: android-ndk-r20:7b7c4b42cf + firebase_device_id: + type: string + default: sailfish + firebase_device_os: + type: string + default: "26" + abi: + type: string + default: "arm-v8" + docker: + - image: mbgl/<< parameters.image >> + resource_class: xlarge + working_directory: /src + environment: + LIBSYSCONFCPUS: 8 + JOBS: 8 + BUILDTYPE: Debug + IS_LOCAL_DEVELOPMENT: false + MBGL_ANDROID_STL: << parameters.stl >> + steps: + - install-dependencies: { gradle: true } + - run: + name: Initialize vendor submodules + command: git submodule update --init --recursive vendor + - run: + name: Check code style + command: make android-check + - run: + name: Run Android unit tests + command: make run-android-unit-test + - run: + name: Build libmapbox-gl.so for << parameters.abi >> + command: make android-lib-<< parameters.abi >> + - run: + name: Generate Espresso sanity tests + command: make test-code-android + - run: + name: Build Test APK + command: | + if [ -n "${MAPBOX_DEVELOPER_CONFIG_XML}" ]; then + echo "${MAPBOX_DEVELOPER_CONFIG_XML}" > MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml + make android-ui-test-<< parameters.abi >> + fi + - save-dependencies: { gradle: true } + - login-google-cloud-platform + - run: + name: Run instrumentation tests on Firebase + no_output_timeout: 20m + command: | + if [[ -n "${GLCLOUD_SERVICE_JSON}" ]]; then + gcloud firebase test android models list + gcloud firebase test android run --type instrumentation \ + --app MapboxGLAndroidSDKTestApp/build/outputs/apk/debug/MapboxGLAndroidSDKTestApp-debug.apk \ + --test MapboxGLAndroidSDKTestApp/build/outputs/apk/androidTest/debug/MapboxGLAndroidSDKTestApp-debug-androidTest.apk \ + --device-ids << parameters.firebase_device_id >> --os-version-ids << parameters.firebase_device_os >> --locales en --orientations portrait --timeout 20m \ + --environment-variables coverage=true,coverageFile="/sdcard/coverage.ec" --directories-to-pull /sdcard --results-dir mapbox-android-sdk-${CIRCLE_BUILD_NUM} + fi + - store_artifacts: + path: MapboxGLAndroidSDKTestApp/build/outputs/apk/debug + destination: . + - store_artifacts: + path: MapboxGLAndroidSDK/build/reports/lint-results.html + - store_artifacts: + path: MapboxGLAndroidSDK/build/reports/lint-results.xml + - store_artifacts: + path: MapboxGLAndroidSDK/lint-baseline.xml + - store_artifacts: + path: MapboxGLAndroidSDKTestApp/build/reports/lint-results.html + - store_artifacts: + path: MapboxGLAndroidSDKTestApp/build/reports/lint-results.xml + - store_artifacts: + path: MapboxGLAndroidSDKTestApp/lint-baseline.xml + - store_artifacts: + path: MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj + + # ------------------------------------------------------------------------------ + android-release: + docker: + - image: mbgl/android-ndk-r20:7b7c4b42cf + resource_class: xlarge + working_directory: /src + environment: + LIBSYSCONFCPUS: 8 + JOBS: 8 + BUILDTYPE: Release + IS_LOCAL_DEVELOPMENT: false + steps: + - install-dependencies: { gradle: true } + - run: + name: Initialize vendor submodules + command: git submodule update --init --recursive vendor + - run: + name: Android nitpick + command: make run-android-nitpick + - run: + name: Trigger core benchmark run + command: | + if [ -n "${MOBILE_METRICS_TOKEN}" ]; then + if [[ $CIRCLE_BRANCH == master ]]; then + curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-core-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + fi + fi + - run: + name: Trigger android benchmark run + command: | + if [ -n "${MOBILE_METRICS_TOKEN}" ]; then + if [[ $CIRCLE_BRANCH == master ]]; then + curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + fi + fi + - run: + name: Generate Maven credentials + command: | + if [ -n "${BINTRAY_USER}" ]; then + echo "BINTRAY_USER=$BINTRAY_USER + BINTRAY_API_KEY=$BINTRAY_API_KEY + GPG_PASSPHRASE=$GPG_PASSPHRASE" + fi + - run: + name: Update version name + command: | + if [[ $CIRCLE_TAG == android-v* ]]; then + sed -i -e "s/^VERSION_NAME=.*/VERSION_NAME=${CIRCLE_TAG:9}/" MapboxGLAndroidSDK/gradle.properties + fi + - run: + name: Build package + command: make apackage + - run: + name: Build release Test App + command: make android + - run: + name: Generate javadoc + command: make android-javadoc + - save-dependencies: { gradle: true } + - run: + name: gzip debugable .so files + command: | + gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so && \ + gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so && \ + gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so && \ + gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so + - store_artifacts: + path: MapboxGLAndroidSDKTestApp/build/outputs/apk/release + destination: . + - store_artifacts: + path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so.gz + - store_artifacts: + path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so.gz + - store_artifacts: + path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so.gz + - store_artifacts: + path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so.gz + - deploy: + name: Publish to Bintray + command: | + if [[ $CIRCLE_BRANCH == master ]] || [[ $CIRCLE_BRANCH == release-* ]] || [[ $CIRCLE_TAG == android-v* ]]; then + version=$(cat MapboxGLAndroidSDK/gradle.properties | grep "VERSION_NAME") + if [[ $version != *"SNAPSHOT"* ]]; then + make run-android-upload-to-bintray + else + make run-android-upload-to-artifactory + fi + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index 37b7600a5..9362f201a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,8 +31,5 @@ MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/acti # Input files for running render tests MapboxGLAndroidSDKTestApp/src/main/assets/integration/ -# Local AS configuration file -gradle.properties - # Node modules node_modules \ No newline at end of file diff --git a/Makefile b/Makefile index dcff72b4a..bf1afa79c 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,25 @@ +export BUILDTYPE ?= Debug +export IS_LOCAL_DEVELOPMENT ?= true +export TARGET_BRANCH ?= master + +CMAKE ?= cmake + + +ifeq ($(BUILDTYPE), Release) +else ifeq ($(BUILDTYPE), RelWithDebInfo) +else ifeq ($(BUILDTYPE), Sanitize) +else ifeq ($(BUILDTYPE), Debug) +else + $(error BUILDTYPE must be Debug, Sanitize, Release or RelWithDebInfo) +endif + +buildtype := $(shell echo "$(BUILDTYPE)" | tr "[A-Z]" "[a-z]") + +HOST_PLATFORM = linux +HOST_PLATFORM_VERSION = $(shell uname -m) +export NINJA = platform/linux/ninja +export JOBS ?= $(shell grep --count processor /proc/cpuinfo) + #### Android targets ########################################################### MBGL_ANDROID_ABIS = arm-v7;armeabi-v7a diff --git a/MapboxGLAndroidSDK/gradle.properties b/MapboxGLAndroidSDK/gradle.properties new file mode 100644 index 000000000..e3fedcde0 --- /dev/null +++ b/MapboxGLAndroidSDK/gradle.properties @@ -0,0 +1,9 @@ +VERSION_NAME=8.5.0-SNAPSHOT + +# Only build native dependencies for the current ABI +# See https://code.google.com/p/android/issues/detail?id=221098#c20 +android.buildOnlyTargetAbi=true + +# Roboelectric 4.0 required config for < Android Studio v3.3.0 +# http://robolectric.org/migrating/#migrating-to-40 +android.enableUnitTestBinaryResources=true \ No newline at end of file diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index f127cb3ed..eef917c70 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -46,6 +46,9 @@ ext.nativeBuild = { nativeTargets -> arguments "-DANDROID_CCACHE=/usr/bin/ccache" } + cFlags "-Qunused-arguments" + cppFlags "-Qunused-arguments" + for (target in nativeTargets) { targets target } diff --git a/package-lock.json b/package-lock.json index 08419e91e..2e6cd54e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,21 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true + }, + "pixelmatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", + "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=", + "dev": true, + "requires": { + "pngjs": "^3.0.0" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true } } } diff --git a/vendor/mapbox-java b/vendor/mapbox-java index 84de2d4b0..f590c74df 160000 --- a/vendor/mapbox-java +++ b/vendor/mapbox-java @@ -1 +1 @@ -Subproject commit 84de2d4b02e93a9eda9d0254332cd356d17445de +Subproject commit f590c74df50f1b1e8edf2a4cf4908701b85861f2 From 81a57bda176bb27313dbb60f52058c02e31f1c03 Mon Sep 17 00:00:00 2001 From: tobrun Date: Tue, 15 Oct 2019 10:35:31 +0200 Subject: [PATCH 007/185] [doc] update readme --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index af3968de9..cc83efee5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://docs.mapbox.com/android/maps/overview/) -The Mapbox Maps SDK for Android is a library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps onto Android devices. +The Mapbox Maps SDK for Android is a library based on [Mapbox GL Native](https://github.com/mapbox/mapbox-gl-native/) for embedding interactive map views with scalable, customizable vector maps onto Android devices. ## Getting Started @@ -22,10 +22,11 @@ These instructions are for developers interested in making code-level contributi #### Getting the source -Clone the git repository +Clone the git repository and pull in submodules: ```bash -git clone git@github.com:mapbox/mapbox-gl-native.git && cd mapbox-gl-native +git clone git@github.com:mapbox/mapbox-gl-native-android.git && cd mapbox-gl-native-android +git submodule update --init --recursive ``` #### Installing dependencies @@ -73,7 +74,7 @@ If you are using Arch Linux, install [ncurses5-compat-libs](https://aur.archlinu #### Setup Checkstyle Mapbox uses specific IDE settings related to code and check style. -See [checkstyle guide](https://github.com/mapbox/mapbox-gl-native/wiki/Setting-up-Mapbox-checkstyle) for configuration details. +See [checkstyle guide](https://github.com/mapbox/mapbox-gl-native-android/wiki/Setting-up-Mapbox-checkstyle) for configuration details. #### Resolving duplicate file entries With buck build support, Android Studio can complain about duplicate source files. To remove this warning, open `MapboxGLAndroidSDK.iml` find the list of `excludeFolder` entries and add `` line. @@ -98,7 +99,7 @@ Instead of using the latest stable release of the Maps SDK for Android, you can ```java // Mapbox SDK dependency -implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:7.3.0-SNAPSHOT' +implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.5.0-SNAPSHOT' ``` You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies: @@ -115,4 +116,4 @@ allprojects { #### Symbolicating native crashes When hitting native crashes you can use ndk-stack to symbolicate crashes. -More information in [this](https://github.com/mapbox/mapbox-gl-native/wiki/Getting-line-numbers-from-an-Android-crash-with-ndk-stack) guide. +More information in [this](https://github.com/mapbox/mapbox-gl-native-android/wiki/Getting-line-numbers-from-an-Android-crash-with-ndk-stack) guide. From e20703e705c649ca6cc38e2224e2caf9a6dda9c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2019 09:17:53 +0000 Subject: [PATCH 008/185] Bump esm from 3.0.84 to 3.1.0 Bumps [esm](https://github.com/standard-things/esm) from 3.0.84 to 3.1.0. - [Release notes](https://github.com/standard-things/esm/releases) - [Commits](https://github.com/standard-things/esm/compare/3.0.84...3.1.0) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e6cd54e7..27c044c32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dev": true }, "esm": { - "version": "3.0.84", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.0.84.tgz", - "integrity": "sha512-SzSGoZc17S7P+12R9cg21Bdb7eybX25RnIeRZ80xZs+VZ3kdQKzqTp2k4hZJjR7p9l0186TTXSgrxzlMDBktlw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.1.0.tgz", + "integrity": "sha512-r4Go7Wh7Wh0WPinRXeeM9PIajRsUdt8SAyki5R1obVc0+BwtqvtjbngVSSdXg0jCe2xZkY8hyBMx6q/uymUkPw==", "dev": true }, "lodash": { diff --git a/package.json b/package.json index 08e60e15e..8d3f68473 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "dependencies": {}, "devDependencies": { "ejs": "^2.5.7", - "esm": "~3.0.84", + "esm": "~3.1.0", "lodash": "^4.16.4", "pixelmatch": "^4.0.2" }, From 4bc6f10e449544e04ac6e4ad7f8417b17ac3bcd0 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 18 Oct 2019 13:24:12 +0200 Subject: [PATCH 009/185] [vendor] - update project with latest changes --- CHANGELOG.md | 13 ++++++++-- .../mapboxsdk/camera/CameraPosition.java | 25 ++++++++++++++++--- .../mapboxsdk/camera/CameraPositionTest.java | 13 +++++++++- vendor/mapbox-gl-native | 2 +- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3b07dd32..4904d8869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,26 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master +## 8.5.0-alpha.2 - October 10, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.5.0-alpha.1...android-v8.5.0-alpha.2) since [Mapbox Maps SDK for Android v8.5.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.5.0-alpha.1): + +### Features + - Expose pre-fetching zoom delta, allows to granular control the delta on which we prefetch tiles [#15769](https://github.com/mapbox/mapbox-gl-native/pull/15769) ### Performance improvements - Improved rendering performance for the styles with multiple sources [#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756) +### Bug fixes + - Fixed runtime exceptions that occurred when a manually built camera object without padding was serialized. [#15788](https://github.com/mapbox/mapbox-gl-native/pull/15788) + - Keep Mapbox when obfuscating code with proguard [#15762](https://github.com/mapbox/mapbox-gl-native/pull/15762) + ## 8.5.0-alpha.1 - October 3, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0): ### Bug fixes - Suppress network requests for expired tiles update, if these tiles are invisible. [#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741) - Fixed opacity interpolation for composition expressions [#15738](https://github.com/mapbox/mapbox-gl-native/pull/15738) - Fixed an issue where `Projection#getMetersPerPixelAtLatitude` returned a value incorrectly divided by the pixel ratio. This also fixes an issue where `LocationComponent` accuracy circle's radius was artificially increased. [#15742](https://github.com/mapbox/mapbox-gl-native/pull/15742) + - Coalesce requests to the client for the same missing image [#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778) ## 8.4.0 - September 25, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): @@ -1818,4 +1827,4 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major ## 2.1.0 - October 21, 2015 -- Initial Android release. +- Initial Android release. \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java index e2341029f..54e8fc595 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -30,8 +30,16 @@ public final class CameraPosition implements Parcelable { LatLng target = in.readParcelable(LatLng.class.getClassLoader()); double tilt = in.readDouble(); double zoom = in.readDouble(); - double[] padding = new double[4]; - in.readDoubleArray(padding); + + double[] padding = null; + int paddingSize = in.readInt(); + if (paddingSize > 0) { + padding = new double[paddingSize]; + for (int i = 0; i < paddingSize; i++) { + padding[i] = in.readDouble(); + } + } + return new CameraPosition(target, zoom, tilt, bearing, padding); } @@ -139,7 +147,16 @@ public final class CameraPosition implements Parcelable { out.writeParcelable(target, flags); out.writeDouble(tilt); out.writeDouble(zoom); - out.writeDoubleArray(padding); + + if (padding != null) { + int length = padding.length; + out.writeInt(length); + for (double v : padding) { + out.writeDouble(v); + } + } else { + out.writeInt(-1); + } } /** @@ -394,4 +411,4 @@ public final class CameraPosition implements Parcelable { return new CameraPosition(target, zoom, tilt, bearing, padding); } } -} +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java index 6974705fa..a720963e7 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java @@ -117,4 +117,15 @@ public class CameraPositionTest { CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel); assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2); } -} + + @Test + public void testParcelableNulls() { + CameraPosition cameraPosition1 = new CameraPosition(null, 3, 4, 5, null); + Parcel parcel = Parcel.obtain(); + cameraPosition1.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel); + assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2); + } +} \ No newline at end of file diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index b4e0224a5..3ac706edf 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit b4e0224a5786f1d362b2b6b7e7f536be8bb98981 +Subproject commit 3ac706edfefc9c8f2ee1ad9eb38bf688364cdb77 From db0263884404b963048f3ce520f295689e12b114 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 18 Oct 2019 17:46:58 +0200 Subject: [PATCH 010/185] [doc] update changelog for v8.5.0-alpha.3 (#18) --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4904d8869..7873cd364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 8.5.0-alpha.3 - October 18, 2019 + +### Bug fixes + - Fix runtime exceptions that occurred when a manually built camera object without padding was serialized [#15788](https://github.com/mapbox/mapbox-gl-native/pull/15788) + - Fix icon-text-fit to take in account the additional 1px texture padding when scaling [#15634](https://github.com/mapbox/mapbox-gl-native/pull/15634) + - Fix occasional crashes during downloading thousands of offline region tiles [#15818](https://github.com/mapbox/mapbox-gl-native/pull/15818) + +### Project + - Moved project location from `mapbox-gl-native` to `mapbox-gl-native-android` + ## 8.5.0-alpha.2 - October 10, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.5.0-alpha.1...android-v8.5.0-alpha.2) since [Mapbox Maps SDK for Android v8.5.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.5.0-alpha.1): From 70214f1e6b8eaa49d4b1c6daf6b821fe90d650c8 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 23 Oct 2019 11:06:15 +0300 Subject: [PATCH 011/185] Add isLayerReady check in LocationComponent before updating compass listener. (#19) --- .../mapboxsdk/location/LocationComponent.java | 2 +- .../mapboxsdk/location/LocationComponentTest.kt | 17 +++++++++++++++++ .../location/LocationModesActivity.java | 6 ++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 8b014b0e9..952da885f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -1289,7 +1289,7 @@ public final class LocationComponent { return; } - if (!isComponentInitialized || !isComponentStarted || !isEnabled) { + if (!isComponentInitialized || !isComponentStarted || !isEnabled || !isLayerReady) { return; } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index 2994c29d5..648a1d214 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -386,6 +386,23 @@ class LocationComponentTest { verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) } + @Test + fun compass_notAddListenerWhenLayerNotReady() { + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + + verify(compassEngine, times(1)).addCompassListener(any(CompassListener::class.java)) + + locationComponent.onStartLoadingMap() + // Layer should be disabled at this point + locationComponent.setCameraMode(CameraMode.TRACKING_COMPASS) + verify(compassEngine, times(1)).addCompassListener(any(CompassListener::class.java)) + } + @Test fun developerAnimationCalled() { locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java index 6ec64e1d0..0ee99a4fe 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java @@ -233,8 +233,10 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea return; } - String styleUrl = Style.DARK.equals(mapboxMap.getStyle().getUri()) ? Style.LIGHT : Style.DARK; - mapboxMap.setStyle(new Style.Builder().fromUri(styleUrl)); + mapboxMap.getStyle(style -> { + String styleUrl = Style.DARK.equals(style.getUri()) ? Style.LIGHT : Style.DARK; + mapboxMap.setStyle(new Style.Builder().fromUri(styleUrl)); + }); } private void disableGesturesManagement() { From 1a729095f3cde0220592dd99d62fb45d6cf2e7ae Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Thu, 24 Oct 2019 14:25:26 +0300 Subject: [PATCH 012/185] Update soLoader to version 0.8.0. (#23) --- gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 31633488e..9f61b2da3 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -31,7 +31,7 @@ ext { androidPublish : '3.6.2', lint : '26.4.2', gms : '16.0.0', - soLoader : '0.6.1', + soLoader : '0.8.0', jacoco : '0.8.4', appcenter : '1.4', ktlint : '0.34.0', From 32ada212f65ec155af36d141db1636ef4e9a1bb9 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Thu, 24 Oct 2019 16:58:24 +0300 Subject: [PATCH 013/185] Update mapbox-gl-native submodule. (#24) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 3ac706edf..646d4e399 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 3ac706edfefc9c8f2ee1ad9eb38bf688364cdb77 +Subproject commit 646d4e3996513ed3e9247e958d39ce9e9b506652 From 77e7e0e38b595ff76de900369f0b732b91ea9d80 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Thu, 24 Oct 2019 17:22:41 +0300 Subject: [PATCH 014/185] Update changelog for v8.5.0-alpha.4 (#25) --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7873cd364..dfa1add83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 8.5.0-alpha.4 - October 24, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.3...android-v8.5.0-alpha.4) since [Mapbox Maps SDK for Android v8.5.0-alpha.3](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.3): +### Bug fixes + - Add isLayerReady check in LocationComponent before updating compass listener. [#19](https://github.com/mapbox/mapbox-gl-native-android/pull/19) + - Update soLoader to version 0.8.0. [#23](https://github.com/mapbox/mapbox-gl-native-android/pull/23) + - Enable incremental vacuum for Offline DB [#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837) + - Revert coalescing requests to the client for missing images [#15852](https://github.com/mapbox/mapbox-gl-native/pull/15852) + - Avoid edges for labels that use text-variable-anchors [#15854](https://github.com/mapbox/mapbox-gl-native/pull/15854) + ## 8.5.0-alpha.3 - October 18, 2019 ### Bug fixes @@ -1837,4 +1846,4 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major ## 2.1.0 - October 21, 2015 -- Initial Android release. \ No newline at end of file +- Initial Android release. From 8a6dba47ed1aa8e73ba9a3a0357ee4be3091a98e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 25 Oct 2019 12:06:26 +0200 Subject: [PATCH 015/185] [build] remove local c++ src folder, using upstream for now (#27) --- src/android_renderer_backend.cpp | 67 - src/android_renderer_backend.hpp | 43 - src/android_renderer_frontend.cpp | 143 --- src/android_renderer_frontend.hpp | 68 - src/annotation/marker.cpp | 23 - src/annotation/marker.hpp | 28 - src/annotation/multi_point.hpp | 34 - src/annotation/polygon.cpp | 40 - src/annotation/polygon.hpp | 21 - src/annotation/polyline.cpp | 31 - src/annotation/polyline.hpp | 21 - src/asset_manager.hpp | 14 - src/asset_manager_file_source.cpp | 57 - src/asset_manager_file_source.hpp | 29 - src/async_task.cpp | 62 - src/attach_env.cpp | 22 - src/attach_env.hpp | 31 - src/bitmap.cpp | 124 -- src/bitmap.hpp | 43 - src/bitmap_factory.cpp | 25 - src/bitmap_factory.hpp | 20 - src/connectivity_listener.cpp | 41 - src/connectivity_listener.hpp | 29 - src/conversion/collection.cpp | 32 - src/conversion/collection.hpp | 18 - src/conversion/color.cpp | 17 - src/conversion/color.hpp | 18 - src/conversion/constant.cpp | 57 - src/conversion/constant.hpp | 104 -- src/conversion/conversion.hpp | 50 - src/example_custom_layer.cpp | 238 ---- src/file_source.cpp | 207 ---- src/file_source.hpp | 81 -- src/geojson/feature.cpp | 79 -- src/geojson/feature.hpp | 23 - src/geojson/feature_collection.cpp | 37 - src/geojson/feature_collection.hpp | 26 - src/geojson/geometry.cpp | 97 -- src/geojson/geometry.hpp | 28 - src/geojson/geometry_collection.cpp | 47 - src/geojson/geometry_collection.hpp | 26 - src/geojson/line_string.cpp | 55 - src/geojson/line_string.hpp | 36 - src/geojson/multi_line_string.cpp | 56 - src/geojson/multi_line_string.hpp | 34 - src/geojson/multi_point.cpp | 41 - src/geojson/multi_point.hpp | 33 - src/geojson/multi_polygon.cpp | 53 - src/geojson/multi_polygon.hpp | 32 - src/geojson/point.cpp | 34 - src/geojson/point.hpp | 27 - src/geojson/polygon.cpp | 55 - src/geojson/polygon.hpp | 35 - src/geojson/util.hpp | 52 - src/geometry/lat_lng.cpp | 29 - src/geometry/lat_lng.hpp | 29 - src/geometry/lat_lng_bounds.cpp | 30 - src/geometry/lat_lng_bounds.hpp | 26 - src/geometry/lat_lng_quad.cpp | 37 - src/geometry/lat_lng_quad.hpp | 27 - src/geometry/projected_meters.cpp | 17 - src/geometry/projected_meters.hpp | 21 - src/gl_functions.cpp | 156 --- src/graphics/pointf.cpp | 25 - src/graphics/pointf.hpp | 24 - src/graphics/rectf.cpp | 35 - src/graphics/rectf.hpp | 28 - src/gson/json_array.cpp | 50 - src/gson/json_array.hpp | 24 - src/gson/json_element.cpp | 88 -- src/gson/json_element.hpp | 24 - src/gson/json_object.cpp | 65 - src/gson/json_object.hpp | 24 - src/gson/json_primitive.cpp | 13 - src/gson/json_primitive.hpp | 21 - src/http_file_source.cpp | 194 --- src/i18n/collator.cpp | 194 --- src/i18n/collator_jni.hpp | 62 - src/i18n/number_format.cpp | 80 -- src/i18n/number_format_jni.hpp | 29 - src/image.cpp | 21 - src/java/util.cpp | 19 - src/java/util.hpp | 81 -- src/java_types.cpp | 49 - src/java_types.hpp | 43 - src/jni.cpp | 54 - src/jni.hpp | 24 - src/jni_native.cpp | 168 --- src/jni_native.hpp | 13 - src/logger.cpp | 34 - src/logger.hpp | 21 - src/logging_android.cpp | 13 - src/main.cpp | 9 - src/map/camera_position.cpp | 69 -- src/map/camera_position.hpp | 23 - src/map/image.cpp | 41 - src/map/image.hpp | 21 - src/map_renderer.cpp | 236 ---- src/map_renderer.hpp | 128 -- src/map_renderer_runnable.cpp | 49 - src/map_renderer_runnable.hpp | 47 - src/mapbox.cpp | 23 - src/mapbox.hpp | 19 - src/native_map_view.cpp | 1170 ------------------ src/native_map_view.hpp | 265 ---- src/offline/offline_manager.cpp | 330 ----- src/offline/offline_manager.hpp | 109 -- src/offline/offline_region.cpp | 300 ----- src/offline/offline_region.hpp | 92 -- src/offline/offline_region_definition.cpp | 107 -- src/offline/offline_region_definition.hpp | 43 - src/offline/offline_region_error.cpp | 44 - src/offline/offline_region_error.hpp | 19 - src/offline/offline_region_status.cpp | 38 - src/offline/offline_region_status.hpp | 19 - src/run_loop.cpp | 256 ---- src/run_loop_impl.hpp | 58 - src/snapshotter/map_snapshot.cpp | 65 - src/snapshotter/map_snapshot.hpp | 48 - src/snapshotter/map_snapshotter.cpp | 176 --- src/snapshotter/map_snapshotter.hpp | 74 -- src/string_util.cpp | 25 - src/style/android_conversion.hpp | 128 -- src/style/conversion/filter.cpp | 26 - src/style/conversion/filter.hpp | 16 - src/style/conversion/position.cpp | 24 - src/style/conversion/position.hpp | 25 - src/style/conversion/property_expression.hpp | 23 - src/style/conversion/property_value.hpp | 62 - src/style/conversion/transition_options.cpp | 17 - src/style/conversion/transition_options.hpp | 21 - src/style/conversion/url_or_tileset.cpp | 30 - src/style/conversion/url_or_tileset.hpp | 16 - src/style/formatted.cpp | 54 - src/style/formatted.hpp | 23 - src/style/formatted_section.cpp | 11 - src/style/formatted_section.hpp | 18 - src/style/layers/background_layer.cpp | 145 --- src/style/layers/background_layer.hpp | 58 - src/style/layers/circle_layer.cpp | 268 ---- src/style/layers/circle_layer.hpp | 84 -- src/style/layers/custom_layer.cpp | 70 -- src/style/layers/custom_layer.hpp | 44 - src/style/layers/fill_extrusion_layer.cpp | 220 ---- src/style/layers/fill_extrusion_layer.hpp | 74 -- src/style/layers/fill_layer.cpp | 199 --- src/style/layers/fill_layer.hpp | 70 -- src/style/layers/heatmap_layer.cpp | 161 --- src/style/layers/heatmap_layer.hpp | 62 - src/style/layers/hillshade_layer.cpp | 178 --- src/style/layers/hillshade_layer.hpp | 66 - src/style/layers/layer.cpp | 198 --- src/style/layers/layer.cpp.ejs | 137 -- src/style/layers/layer.hpp | 126 -- src/style/layers/layer.hpp.ejs | 62 - src/style/layers/layer_manager.cpp | 172 --- src/style/layers/layer_manager.hpp | 57 - src/style/layers/line_layer.cpp | 307 ----- src/style/layers/line_layer.hpp | 94 -- src/style/layers/raster_layer.cpp | 220 ---- src/style/layers/raster_layer.hpp | 74 -- src/style/layers/symbol_layer.cpp | 592 --------- src/style/layers/symbol_layer.hpp | 180 --- src/style/light.cpp | 143 --- src/style/light.hpp | 53 - src/style/position.cpp | 35 - src/style/position.hpp | 24 - src/style/sources/custom_geometry_source.cpp | 210 ---- src/style/sources/custom_geometry_source.hpp | 50 - src/style/sources/geojson_source.cpp | 265 ---- src/style/sources/geojson_source.hpp | 73 -- src/style/sources/image_source.cpp | 79 -- src/style/sources/image_source.hpp | 39 - src/style/sources/raster_dem_source.cpp | 62 - src/style/sources/raster_dem_source.hpp | 29 - src/style/sources/raster_source.cpp | 61 - src/style/sources/raster_source.hpp | 29 - src/style/sources/source.cpp | 168 --- src/style/sources/source.hpp | 61 - src/style/sources/unknown_source.cpp | 43 - src/style/sources/unknown_source.hpp | 27 - src/style/sources/vector_source.cpp | 84 -- src/style/sources/vector_source.hpp | 33 - src/style/transition_options.cpp | 35 - src/style/transition_options.hpp | 26 - src/style/value.cpp | 83 -- src/style/value.hpp | 43 - src/test/benchmark_runner.cpp | 10 - src/test/runtime.cpp | 74 -- src/test/runtime.hpp | 9 - src/test/test_runner.cpp | 10 - src/test/version-script | 8 - src/text/collator.cpp | 199 --- src/text/collator_jni.hpp | 64 - src/text/format_number.cpp | 81 -- src/text/format_number_jni.hpp | 29 - src/text/local_glyph_rasterizer.cpp | 130 -- src/text/local_glyph_rasterizer_jni.hpp | 33 - src/thread.cpp | 56 - src/timer.cpp | 75 -- src/unaccent.cpp | 18 - 201 files changed, 15502 deletions(-) delete mode 100755 src/android_renderer_backend.cpp delete mode 100755 src/android_renderer_backend.hpp delete mode 100644 src/android_renderer_frontend.cpp delete mode 100644 src/android_renderer_frontend.hpp delete mode 100644 src/annotation/marker.cpp delete mode 100644 src/annotation/marker.hpp delete mode 100644 src/annotation/multi_point.hpp delete mode 100644 src/annotation/polygon.cpp delete mode 100644 src/annotation/polygon.hpp delete mode 100644 src/annotation/polyline.cpp delete mode 100644 src/annotation/polyline.hpp delete mode 100644 src/asset_manager.hpp delete mode 100644 src/asset_manager_file_source.cpp delete mode 100644 src/asset_manager_file_source.hpp delete mode 100644 src/async_task.cpp delete mode 100644 src/attach_env.cpp delete mode 100644 src/attach_env.hpp delete mode 100644 src/bitmap.cpp delete mode 100644 src/bitmap.hpp delete mode 100644 src/bitmap_factory.cpp delete mode 100644 src/bitmap_factory.hpp delete mode 100644 src/connectivity_listener.cpp delete mode 100644 src/connectivity_listener.hpp delete mode 100644 src/conversion/collection.cpp delete mode 100644 src/conversion/collection.hpp delete mode 100644 src/conversion/color.cpp delete mode 100644 src/conversion/color.hpp delete mode 100644 src/conversion/constant.cpp delete mode 100644 src/conversion/constant.hpp delete mode 100644 src/conversion/conversion.hpp delete mode 100644 src/example_custom_layer.cpp delete mode 100644 src/file_source.cpp delete mode 100644 src/file_source.hpp delete mode 100644 src/geojson/feature.cpp delete mode 100644 src/geojson/feature.hpp delete mode 100644 src/geojson/feature_collection.cpp delete mode 100644 src/geojson/feature_collection.hpp delete mode 100644 src/geojson/geometry.cpp delete mode 100644 src/geojson/geometry.hpp delete mode 100644 src/geojson/geometry_collection.cpp delete mode 100644 src/geojson/geometry_collection.hpp delete mode 100644 src/geojson/line_string.cpp delete mode 100644 src/geojson/line_string.hpp delete mode 100644 src/geojson/multi_line_string.cpp delete mode 100644 src/geojson/multi_line_string.hpp delete mode 100644 src/geojson/multi_point.cpp delete mode 100644 src/geojson/multi_point.hpp delete mode 100644 src/geojson/multi_polygon.cpp delete mode 100644 src/geojson/multi_polygon.hpp delete mode 100644 src/geojson/point.cpp delete mode 100644 src/geojson/point.hpp delete mode 100644 src/geojson/polygon.cpp delete mode 100644 src/geojson/polygon.hpp delete mode 100644 src/geojson/util.hpp delete mode 100644 src/geometry/lat_lng.cpp delete mode 100644 src/geometry/lat_lng.hpp delete mode 100644 src/geometry/lat_lng_bounds.cpp delete mode 100644 src/geometry/lat_lng_bounds.hpp delete mode 100644 src/geometry/lat_lng_quad.cpp delete mode 100644 src/geometry/lat_lng_quad.hpp delete mode 100644 src/geometry/projected_meters.cpp delete mode 100644 src/geometry/projected_meters.hpp delete mode 100644 src/gl_functions.cpp delete mode 100644 src/graphics/pointf.cpp delete mode 100644 src/graphics/pointf.hpp delete mode 100644 src/graphics/rectf.cpp delete mode 100644 src/graphics/rectf.hpp delete mode 100644 src/gson/json_array.cpp delete mode 100644 src/gson/json_array.hpp delete mode 100644 src/gson/json_element.cpp delete mode 100644 src/gson/json_element.hpp delete mode 100644 src/gson/json_object.cpp delete mode 100644 src/gson/json_object.hpp delete mode 100644 src/gson/json_primitive.cpp delete mode 100644 src/gson/json_primitive.hpp delete mode 100644 src/http_file_source.cpp delete mode 100644 src/i18n/collator.cpp delete mode 100644 src/i18n/collator_jni.hpp delete mode 100644 src/i18n/number_format.cpp delete mode 100644 src/i18n/number_format_jni.hpp delete mode 100644 src/image.cpp delete mode 100644 src/java/util.cpp delete mode 100644 src/java/util.hpp delete mode 100644 src/java_types.cpp delete mode 100644 src/java_types.hpp delete mode 100755 src/jni.cpp delete mode 100644 src/jni.hpp delete mode 100644 src/jni_native.cpp delete mode 100644 src/jni_native.hpp delete mode 100644 src/logger.cpp delete mode 100644 src/logger.hpp delete mode 100644 src/logging_android.cpp delete mode 100644 src/main.cpp delete mode 100644 src/map/camera_position.cpp delete mode 100644 src/map/camera_position.hpp delete mode 100644 src/map/image.cpp delete mode 100644 src/map/image.hpp delete mode 100644 src/map_renderer.cpp delete mode 100644 src/map_renderer.hpp delete mode 100644 src/map_renderer_runnable.cpp delete mode 100644 src/map_renderer_runnable.hpp delete mode 100644 src/mapbox.cpp delete mode 100644 src/mapbox.hpp delete mode 100644 src/native_map_view.cpp delete mode 100755 src/native_map_view.hpp delete mode 100644 src/offline/offline_manager.cpp delete mode 100644 src/offline/offline_manager.hpp delete mode 100644 src/offline/offline_region.cpp delete mode 100644 src/offline/offline_region.hpp delete mode 100644 src/offline/offline_region_definition.cpp delete mode 100644 src/offline/offline_region_definition.hpp delete mode 100644 src/offline/offline_region_error.cpp delete mode 100644 src/offline/offline_region_error.hpp delete mode 100644 src/offline/offline_region_status.cpp delete mode 100644 src/offline/offline_region_status.hpp delete mode 100644 src/run_loop.cpp delete mode 100644 src/run_loop_impl.hpp delete mode 100644 src/snapshotter/map_snapshot.cpp delete mode 100644 src/snapshotter/map_snapshot.hpp delete mode 100644 src/snapshotter/map_snapshotter.cpp delete mode 100644 src/snapshotter/map_snapshotter.hpp delete mode 100644 src/string_util.cpp delete mode 100644 src/style/android_conversion.hpp delete mode 100644 src/style/conversion/filter.cpp delete mode 100644 src/style/conversion/filter.hpp delete mode 100644 src/style/conversion/position.cpp delete mode 100644 src/style/conversion/position.hpp delete mode 100644 src/style/conversion/property_expression.hpp delete mode 100644 src/style/conversion/property_value.hpp delete mode 100644 src/style/conversion/transition_options.cpp delete mode 100644 src/style/conversion/transition_options.hpp delete mode 100644 src/style/conversion/url_or_tileset.cpp delete mode 100644 src/style/conversion/url_or_tileset.hpp delete mode 100644 src/style/formatted.cpp delete mode 100644 src/style/formatted.hpp delete mode 100644 src/style/formatted_section.cpp delete mode 100644 src/style/formatted_section.hpp delete mode 100644 src/style/layers/background_layer.cpp delete mode 100644 src/style/layers/background_layer.hpp delete mode 100644 src/style/layers/circle_layer.cpp delete mode 100644 src/style/layers/circle_layer.hpp delete mode 100644 src/style/layers/custom_layer.cpp delete mode 100644 src/style/layers/custom_layer.hpp delete mode 100644 src/style/layers/fill_extrusion_layer.cpp delete mode 100644 src/style/layers/fill_extrusion_layer.hpp delete mode 100644 src/style/layers/fill_layer.cpp delete mode 100644 src/style/layers/fill_layer.hpp delete mode 100644 src/style/layers/heatmap_layer.cpp delete mode 100644 src/style/layers/heatmap_layer.hpp delete mode 100644 src/style/layers/hillshade_layer.cpp delete mode 100644 src/style/layers/hillshade_layer.hpp delete mode 100644 src/style/layers/layer.cpp delete mode 100644 src/style/layers/layer.cpp.ejs delete mode 100644 src/style/layers/layer.hpp delete mode 100644 src/style/layers/layer.hpp.ejs delete mode 100644 src/style/layers/layer_manager.cpp delete mode 100644 src/style/layers/layer_manager.hpp delete mode 100644 src/style/layers/line_layer.cpp delete mode 100644 src/style/layers/line_layer.hpp delete mode 100644 src/style/layers/raster_layer.cpp delete mode 100644 src/style/layers/raster_layer.hpp delete mode 100644 src/style/layers/symbol_layer.cpp delete mode 100644 src/style/layers/symbol_layer.hpp delete mode 100644 src/style/light.cpp delete mode 100644 src/style/light.hpp delete mode 100644 src/style/position.cpp delete mode 100644 src/style/position.hpp delete mode 100644 src/style/sources/custom_geometry_source.cpp delete mode 100644 src/style/sources/custom_geometry_source.hpp delete mode 100644 src/style/sources/geojson_source.cpp delete mode 100644 src/style/sources/geojson_source.hpp delete mode 100644 src/style/sources/image_source.cpp delete mode 100644 src/style/sources/image_source.hpp delete mode 100644 src/style/sources/raster_dem_source.cpp delete mode 100644 src/style/sources/raster_dem_source.hpp delete mode 100644 src/style/sources/raster_source.cpp delete mode 100644 src/style/sources/raster_source.hpp delete mode 100644 src/style/sources/source.cpp delete mode 100644 src/style/sources/source.hpp delete mode 100644 src/style/sources/unknown_source.cpp delete mode 100644 src/style/sources/unknown_source.hpp delete mode 100644 src/style/sources/vector_source.cpp delete mode 100644 src/style/sources/vector_source.hpp delete mode 100644 src/style/transition_options.cpp delete mode 100644 src/style/transition_options.hpp delete mode 100644 src/style/value.cpp delete mode 100644 src/style/value.hpp delete mode 100644 src/test/benchmark_runner.cpp delete mode 100644 src/test/runtime.cpp delete mode 100644 src/test/runtime.hpp delete mode 100644 src/test/test_runner.cpp delete mode 100644 src/test/version-script delete mode 100644 src/text/collator.cpp delete mode 100644 src/text/collator_jni.hpp delete mode 100644 src/text/format_number.cpp delete mode 100644 src/text/format_number_jni.hpp delete mode 100644 src/text/local_glyph_rasterizer.cpp delete mode 100644 src/text/local_glyph_rasterizer_jni.hpp delete mode 100644 src/thread.cpp delete mode 100644 src/timer.cpp delete mode 100644 src/unaccent.cpp diff --git a/src/android_renderer_backend.cpp b/src/android_renderer_backend.cpp deleted file mode 100755 index e2d064838..000000000 --- a/src/android_renderer_backend.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "android_renderer_backend.hpp" - -#include -#include -#include - -#include - -#include - -namespace mbgl { -namespace android { - -class AndroidGLRenderableResource final : public mbgl::gl::RenderableResource { -public: - AndroidGLRenderableResource(AndroidRendererBackend& backend_) : backend(backend_) { - } - - void bind() override { - assert(gfx::BackendScope::exists()); - backend.setFramebufferBinding(0); - backend.setViewport(0, 0, backend.getSize()); - } - -private: - AndroidRendererBackend& backend; -}; - -AndroidRendererBackend::AndroidRendererBackend() - : gl::RendererBackend(gfx::ContextMode::Unique), - mbgl::gfx::Renderable({ 64, 64 }, std::make_unique(*this)) { -} - -AndroidRendererBackend::~AndroidRendererBackend() = default; - -gl::ProcAddress AndroidRendererBackend::getExtensionFunctionPointer(const char* name) { - assert(gfx::BackendScope::exists()); - return eglGetProcAddress(name); -} - -void AndroidRendererBackend::updateViewPort() { - assert(gfx::BackendScope::exists()); - setViewport(0, 0, size); -} - -void AndroidRendererBackend::resizeFramebuffer(int width, int height) { - size = { static_cast(width), static_cast(height) }; -} - -PremultipliedImage AndroidRendererBackend::readFramebuffer() { - assert(gfx::BackendScope::exists()); - return gl::RendererBackend::readFramebuffer(size); -} - -void AndroidRendererBackend::updateAssumedState() { - assumeFramebufferBinding(0); - assumeViewport(0, 0, size); -} - -void AndroidRendererBackend::markContextLost() { - if (context) { - getContext().setCleanupOnDestruction(false); - } -} - -} // namespace android -} // namspace mbgl diff --git a/src/android_renderer_backend.hpp b/src/android_renderer_backend.hpp deleted file mode 100755 index f06f38e68..000000000 --- a/src/android_renderer_backend.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -namespace mbgl { -namespace android { - -class AndroidRendererBackend : public gl::RendererBackend, public mbgl::gfx::Renderable { -public: - AndroidRendererBackend(); - ~AndroidRendererBackend() override; - - void updateViewPort(); - - // Ensures the current context is not cleaned up when destroyed - void markContextLost(); - - void resizeFramebuffer(int width, int height); - PremultipliedImage readFramebuffer(); - - // mbgl::gfx::RendererBackend implementation -public: - mbgl::gfx::Renderable& getDefaultRenderable() override { - return *this; - } - -protected: - void activate() override { - // no-op - } - void deactivate() override { - // no-op - } - - // mbgl::gl::RendererBackend implementation -protected: - mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override; - void updateAssumedState() override; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/android_renderer_frontend.cpp b/src/android_renderer_frontend.cpp deleted file mode 100644 index d1a2624f0..000000000 --- a/src/android_renderer_frontend.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "android_renderer_frontend.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "android_renderer_backend.hpp" - -namespace mbgl { -namespace android { - -// Forwards RendererObserver signals to the given -// Delegate RendererObserver on the given RunLoop -class ForwardingRendererObserver : public RendererObserver { -public: - ForwardingRendererObserver(util::RunLoop& mapRunLoop, RendererObserver& delegate_) - : mailbox(std::make_shared(mapRunLoop)) - , delegate(delegate_, mailbox) { - } - - ~ForwardingRendererObserver() { - mailbox->close(); - } - - void onInvalidate() override { - delegate.invoke(&RendererObserver::onInvalidate); - } - - void onResourceError(std::exception_ptr err) override { - delegate.invoke(&RendererObserver::onResourceError, err); - } - - void onWillStartRenderingMap() override { - delegate.invoke(&RendererObserver::onWillStartRenderingMap); - } - - void onWillStartRenderingFrame() override { - delegate.invoke(&RendererObserver::onWillStartRenderingFrame); - } - - void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) override { - delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged); - } - - void onDidFinishRenderingMap() override { - delegate.invoke(&RendererObserver::onDidFinishRenderingMap); - } - - void onStyleImageMissing(const std::string& id, StyleImageMissingCallback done) override { - delegate.invoke(&RendererObserver::onStyleImageMissing, id, done); - } - - void onRemoveUnusedStyleImages(const std::vector& ids) override { - delegate.invoke(&RendererObserver::onRemoveUnusedStyleImages, ids); - } - -private: - std::shared_ptr mailbox; - ActorRef delegate; -}; - -AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_) - : mapRenderer(mapRenderer_) - , mapRunLoop(util::RunLoop::Get()) - , updateAsyncTask(std::make_unique([this]() { - mapRenderer.update(std::move(updateParams)); - mapRenderer.requestRender(); - })) { -} - -AndroidRendererFrontend::~AndroidRendererFrontend() = default; - -void AndroidRendererFrontend::reset() { - mapRenderer.reset(); -} - -void AndroidRendererFrontend::setObserver(RendererObserver& observer) { - assert (util::RunLoop::Get()); - // Don't call the Renderer directly, but use MapRenderer#setObserver to make sure - // the Renderer may be re-initialised without losing the RendererObserver reference. - mapRenderer.setObserver(std::make_unique(*mapRunLoop, observer)); -} - -void AndroidRendererFrontend::update(std::shared_ptr params) { - updateParams = std::move(params); - updateAsyncTask->send(); -} - -void AndroidRendererFrontend::reduceMemoryUse() { - mapRenderer.actor().invoke(&Renderer::reduceMemoryUse); -} - -std::vector AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID, - const SourceQueryOptions& options) const { - // Waits for the result from the orchestration thread and returns - return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get(); -} - -std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box, - const RenderedQueryOptions& options) const { - - // Select the right overloaded method - std::vector (Renderer::*fn)(const ScreenBox&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; - - // Waits for the result from the orchestration thread and returns - return mapRenderer.actor().ask(fn, box, options).get(); -} - -std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenCoordinate& point, - const RenderedQueryOptions& options) const { - - // Select the right overloaded method - std::vector (Renderer::*fn)(const ScreenCoordinate&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; - - // Waits for the result from the orchestration thread and returns - return mapRenderer.actor().ask(fn, point, options).get(); -} - -AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& box) const { - // Waits for the result from the orchestration thread and returns - return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get(); -} - -AnnotationIDs AndroidRendererFrontend::queryShapeAnnotations(const ScreenBox& box) const { - // Waits for the result from the orchestration thread and returns - return mapRenderer.actor().ask(&Renderer::queryShapeAnnotations, box).get(); -} - -FeatureExtensionValue AndroidRendererFrontend::queryFeatureExtensions(const std::string& sourceID, - const Feature& feature, - const std::string& extension, - const std::string& extensionField, - const optional>& args) const { - return mapRenderer.actor().ask(&Renderer::queryFeatureExtensions, sourceID, feature, extension, extensionField, args).get(); -} - -} // namespace android -} // namespace mbgl - diff --git a/src/android_renderer_frontend.hpp b/src/android_renderer_frontend.hpp deleted file mode 100644 index dc5f11e57..000000000 --- a/src/android_renderer_frontend.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "map_renderer.hpp" - -namespace mbgl { - -class RenderedQueryOptions; -class SourceQueryOptions; - -namespace util { - -class AsyncTask; - -} // namespace util - -namespace android { - -class AndroidRendererFrontend : public RendererFrontend { -public: - - AndroidRendererFrontend(MapRenderer&); - ~AndroidRendererFrontend() override; - - void reset() override; - void setObserver(RendererObserver&) override; - - void update(std::shared_ptr) override; - - // Feature querying - std::vector queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const; - std::vector queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const; - std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; - AnnotationIDs queryPointAnnotations(const ScreenBox& box) const; - AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const; - - - // Feature extension query - FeatureExtensionValue - queryFeatureExtensions(const std::string& sourceID, - const Feature& feature, - const std::string& extension, - const std::string& extensionField, - const optional>& args) const; - - // Memory - void reduceMemoryUse(); - -private: - MapRenderer& mapRenderer; - util::RunLoop* mapRunLoop; - std::unique_ptr updateAsyncTask; - std::shared_ptr updateParams; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/annotation/marker.cpp b/src/annotation/marker.cpp deleted file mode 100644 index 899f87a74..000000000 --- a/src/annotation/marker.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "marker.hpp" - -namespace mbgl { -namespace android { - -mbgl::Point Marker::getPosition(jni::JNIEnv& env, const jni::Object& marker) { - static auto& javaClass = jni::Class::Singleton(env); - static auto positionField = javaClass.GetField>(env, "position"); - return LatLng::getGeometry(env, marker.Get(env, positionField)); -} - -std::string Marker::getIconId(jni::JNIEnv& env, const jni::Object& marker) { - static auto& javaClass = jni::Class::Singleton(env); - static auto iconIdField = javaClass.GetField(env, "iconId"); - return jni::Make(env, marker.Get(env, iconIdField)); -} - -void Marker::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/marker.hpp b/src/annotation/marker.hpp deleted file mode 100644 index b38a25b4f..000000000 --- a/src/annotation/marker.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "../geometry/lat_lng.hpp" - -namespace mbgl { -namespace android { - -class Marker : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; }; - - static mbgl::Point getPosition(jni::JNIEnv&, const jni::Object&); - - static std::string getIconId(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); - -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/multi_point.hpp b/src/annotation/multi_point.hpp deleted file mode 100644 index 20f1b3eaf..000000000 --- a/src/annotation/multi_point.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -#include "../geometry/lat_lng.hpp" -#include "../java/util.hpp" - -namespace mbgl { -namespace android { - -class MultiPoint : protected mbgl::util::noncopyable { - -protected: - - template - static Geometry toGeometry(JNIEnv& env, const jni::Object& pointsList) { - auto jarray = java::util::List::toArray(env, pointsList); - - std::size_t size = jarray.Length(env); - - Geometry geometry; - geometry.reserve(size); - - for (std::size_t i = 0; i < size; i++) { - geometry.push_back(LatLng::getGeometry(env, jarray.Get(env, i))); - } - - return geometry; - } -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polygon.cpp b/src/annotation/polygon.cpp deleted file mode 100644 index f22cffb10..000000000 --- a/src/annotation/polygon.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "polygon.hpp" - -#include "../conversion/color.hpp" - -namespace mbgl { -namespace android { - -mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, const jni::Object& polygon) { - static auto& javaClass = jni::Class::Singleton(env); - static auto points = javaClass.GetField>(env, "points"); - static auto holes = javaClass.GetField>(env, "holes"); - static auto alpha = javaClass.GetField(env, "alpha"); - static auto fillColor = javaClass.GetField(env, "fillColor"); - static auto strokeColor = javaClass.GetField(env, "strokeColor"); - - mbgl::Polygon geometry { - MultiPoint::toGeometry>(env, polygon.Get(env, points)) - }; - - auto jHoleListsArray = java::util::List::toArray(env, polygon.Get(env, holes)); - - std::size_t jHoleListsSize = jHoleListsArray.Length(env); - for (std::size_t i = 0; i < jHoleListsSize; i++) { - geometry.push_back(MultiPoint::toGeometry>(env, jHoleListsArray.Get(env, i))); - } - - mbgl::FillAnnotation annotation { geometry }; - annotation.opacity = polygon.Get(env, alpha); - annotation.color = *conversion::convert(env, polygon.Get(env, fillColor)); - annotation.outlineColor = *conversion::convert(env, polygon.Get(env, strokeColor)); - - return annotation; -} - -void Polygon::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polygon.hpp b/src/annotation/polygon.hpp deleted file mode 100644 index bc21878ef..000000000 --- a/src/annotation/polygon.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include "multi_point.hpp" - -namespace mbgl { -namespace android { - -class Polygon : private MultiPoint { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; }; - - static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polyline.cpp b/src/annotation/polyline.cpp deleted file mode 100644 index d6161e856..000000000 --- a/src/annotation/polyline.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "polyline.hpp" - -#include "../conversion/color.hpp" - -namespace mbgl { -namespace android { - -mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, const jni::Object& polyline) { - static auto& javaClass = jni::Class::Singleton(env); - static auto points = javaClass.GetField>(env, "points"); - static auto alpha = javaClass.GetField(env, "alpha"); - static auto color = javaClass.GetField(env, "color"); - static auto width = javaClass.GetField(env, "width"); - - mbgl::LineAnnotation annotation { - MultiPoint::toGeometry>(env, polyline.Get(env, points)) - }; - - annotation.opacity = polyline.Get(env, alpha); - annotation.color = *conversion::convert(env, polyline.Get(env, color)); - annotation.width = polyline.Get(env, width); - - return annotation; -} - -void Polyline::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/annotation/polyline.hpp b/src/annotation/polyline.hpp deleted file mode 100644 index 6178e98cf..000000000 --- a/src/annotation/polyline.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include "multi_point.hpp" - -namespace mbgl { -namespace android { - -class Polyline : private MultiPoint { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; }; - - static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/asset_manager.hpp b/src/asset_manager.hpp deleted file mode 100644 index b87d18951..000000000 --- a/src/asset_manager.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace mbgl { -namespace android { - -class AssetManager { -public: - static constexpr auto Name() { - return "android/content/res/AssetManager"; - }; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/asset_manager_file_source.cpp b/src/asset_manager_file_source.cpp deleted file mode 100644 index b9150deef..000000000 --- a/src/asset_manager_file_source.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "asset_manager_file_source.hpp" - -#include -#include -#include -#include -#include - -#include -#include - -namespace mbgl { - -class AssetManagerFileSource::Impl { -public: - Impl(ActorRef, AAssetManager* assetManager_) : assetManager(assetManager_) { - } - - void request(const std::string& url, ActorRef req) { - // Note: AssetManager already prepends "assets" to the filename. - const std::string path = mbgl::util::percentDecode(url.substr(8)); - - Response response; - - if (AAsset* asset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER)) { - response.data = std::make_shared( - reinterpret_cast(AAsset_getBuffer(asset)), AAsset_getLength64(asset)); - AAsset_close(asset); - } else { - response.error = std::make_unique(Response::Error::Reason::NotFound, - "Could not read asset"); - } - - req.invoke(&FileSourceRequest::setResponse, response); - } - -private: - AAssetManager* assetManager; -}; - -AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, const jni::Object& assetManager_) - : assetManager(jni::NewGlobal(env, assetManager_)), - impl(std::make_unique>("AssetManagerFileSource", - AAssetManager_fromJava(&env, jni::Unwrap(assetManager.get())))) { -} - -AssetManagerFileSource::~AssetManagerFileSource() = default; - -std::unique_ptr AssetManagerFileSource::request(const Resource& resource, Callback callback) { - auto req = std::make_unique(std::move(callback)); - - impl->actor().invoke(&Impl::request, resource.url, req->actor()); - - return std::move(req); -} - -} // namespace mbgl diff --git a/src/asset_manager_file_source.hpp b/src/asset_manager_file_source.hpp deleted file mode 100644 index 4ec5b4c30..000000000 --- a/src/asset_manager_file_source.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "asset_manager.hpp" - -#include - -namespace mbgl { - -namespace util { -template class Thread; -} // namespace util - -class AssetManagerFileSource : public FileSource { -public: - AssetManagerFileSource(jni::JNIEnv&, const jni::Object&); - ~AssetManagerFileSource() override; - - std::unique_ptr request(const Resource&, Callback) override; - -private: - class Impl; - - jni::Global> assetManager; - std::unique_ptr> impl; -}; - -} // namespace mbgl diff --git a/src/async_task.cpp b/src/async_task.cpp deleted file mode 100644 index 6c14e96fa..000000000 --- a/src/async_task.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "run_loop_impl.hpp" - -#include -#include - -#include -#include - -namespace mbgl { -namespace util { - -class AsyncTask::Impl : public RunLoop::Impl::Runnable { -public: - Impl(std::function&& fn) - : queued(true), task(std::move(fn)) { - } - - ~Impl() { - loop->removeRunnable(this); - } - - void maySend() { - if (queued) { - queued = false; - loop->addRunnable(this); - } - } - - TimePoint dueTime() const override { - return due; - } - - void runTask() override { - loop->removeRunnable(this); - queued = true; - task(); - } - -private: - // Always expired, run immediately. - const TimePoint due = Clock::now(); - - RunLoop::Impl* loop = reinterpret_cast(RunLoop::getLoopHandle()); - - // TODO: Use std::atomic_flag if we ever drop - // support for ARMv5 - std::atomic queued; - std::function task; -}; - -AsyncTask::AsyncTask(std::function&& fn) - : impl(std::make_unique(std::move(fn))) { -} - -AsyncTask::~AsyncTask() = default; - -void AsyncTask::send() { - impl->maySend(); -} - -} // namespace util -} // namespace mbgl diff --git a/src/attach_env.cpp b/src/attach_env.cpp deleted file mode 100644 index 6da075ee3..000000000 --- a/src/attach_env.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "attach_env.hpp" -#include "jni.hpp" - -namespace mbgl { -namespace android { - -UniqueEnv AttachEnv() { - JNIEnv* env = nullptr; - jint err = theJVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - - switch (err) { - case JNI_OK: - return UniqueEnv(env, JNIEnvDeleter(*theJVM, false)); - case JNI_EDETACHED: - return UniqueEnv(jni::AttachCurrentThread(*theJVM).release(), JNIEnvDeleter(*theJVM, true)); - default: - throw std::system_error(err, jni::ErrorCategory()); - } -} - -} -} diff --git a/src/attach_env.hpp b/src/attach_env.hpp deleted file mode 100644 index 8a9f4a7f8..000000000 --- a/src/attach_env.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -namespace mbgl { -namespace android { - -class JNIEnvDeleter { -private: - jni::JavaVM* vm = nullptr; - bool detach = false; - -public: - JNIEnvDeleter() = default; - JNIEnvDeleter(jni::JavaVM& v, bool d) - : vm(&v), detach(d) {} - - void operator()(jni::JNIEnv* p) const { - if (p && detach) { - assert(vm); - vm->DetachCurrentThread(); - } - } -}; - -using UniqueEnv = std::unique_ptr; - -UniqueEnv AttachEnv(); - -} -} diff --git a/src/bitmap.cpp b/src/bitmap.cpp deleted file mode 100644 index eb7c676b1..000000000 --- a/src/bitmap.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "bitmap.hpp" - -#include -#include - -namespace mbgl { -namespace android { - -class PixelGuard { -public: - PixelGuard(jni::JNIEnv& env_, const jni::Object& bitmap_) : env(env_), bitmap(bitmap_) { - const int result = AndroidBitmap_lockPixels(&env, jni::Unwrap(*bitmap), - reinterpret_cast(&address)); - if (result != ANDROID_BITMAP_RESULT_SUCCESS) { - throw std::runtime_error("bitmap decoding: could not lock pixels"); - } - } - - ~PixelGuard() { - const int result = AndroidBitmap_unlockPixels(&env, jni::Unwrap(*bitmap)); - if (result != ANDROID_BITMAP_RESULT_SUCCESS) { - Log::Warning(mbgl::Event::General, "Bitmap decoding: could not unlock pixels"); - } - } - - auto* get() { - return address; - } - -private: - jni::JNIEnv& env; - const jni::Object& bitmap; - uint8_t* address; -}; - -jni::Local> Bitmap::Config::Create(jni::JNIEnv& env, Value value) { - static auto& _class = jni::Class::Singleton(env); - switch (value) { - case ALPHA_8: - return _class.Get(env, _class.GetStaticField>(env, "ALPHA_8")); - case ARGB_4444: - return _class.Get(env, _class.GetStaticField>(env, "ARGB_4444")); - case ARGB_8888: - return _class.Get(env, _class.GetStaticField>(env, "ARGB_8888")); - case RGB_565: - return _class.Get(env, _class.GetStaticField>(env, "RGB_565")); - default: - throw std::runtime_error("invalid enum value for Bitmap.Config"); - } -} - -void Bitmap::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); - jni::Class::Singleton(env); -} - -jni::Local> Bitmap::CreateBitmap(jni::JNIEnv& env, - jni::jint width, - jni::jint height, - const jni::Object& config) { - static auto& _class = jni::Class::Singleton(env); - static auto method = _class.GetStaticMethod (jni::jint, jni::jint, jni::Object)>(env, "createBitmap"); - - return _class.Call(env, method, width, height, config); -} - -PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, const jni::Object& bitmap) { - AndroidBitmapInfo info; - const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info); - if (result != ANDROID_BITMAP_RESULT_SUCCESS) { - throw std::runtime_error("bitmap decoding: couldn't get bitmap info"); - } - if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { - return Bitmap::GetImage(env, Bitmap::Copy(env, bitmap)); - } - - PixelGuard guard(env, bitmap); - - // Copy the Android Bitmap into the PremultipliedImage. - auto pixels = - std::make_unique(info.width * info.height * PremultipliedImage::channels); - for (uint32_t y = 0; y < info.height; y++) { - auto begin = guard.get() + y * info.stride; - std::copy(begin, begin + info.width * PremultipliedImage::channels, - pixels.get() + y * info.width * PremultipliedImage::channels); - } - - return { Size{ info.width, info.height }, std::move(pixels) }; -} - -jni::Local> Bitmap::CreateBitmap(jni::JNIEnv& env, const PremultipliedImage& image) { - auto bitmap = CreateBitmap(env, image.size.width, image.size.height, Config::ARGB_8888); - - AndroidBitmapInfo info; - const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info); - if (result != ANDROID_BITMAP_RESULT_SUCCESS) { - // TODO: more specific information - throw std::runtime_error("bitmap creation: couldn't get bitmap info"); - } - - assert(info.width == image.size.width); - assert(info.height == image.size.height); - assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888); - - PixelGuard guard(env, bitmap); - - // Copy the PremultipliedImage into the Android Bitmap - for (uint32_t y = 0; y < image.size.height; y++) { - auto begin = image.data.get() + y * image.stride(); - std::copy(begin, begin + image.stride(), guard.get() + y * info.stride); - } - - return bitmap; -} - -jni::Local> Bitmap::Copy(jni::JNIEnv& env, const jni::Object& bitmap) { - static auto& klass = jni::Class::Singleton(env); - static auto copy = klass.GetMethod (jni::Object, jni::jboolean)>(env, "copy"); - - return bitmap.Call(env, copy, Bitmap::Config::Create(env, Bitmap::Config::Value::ARGB_8888), jni::jni_false); -} - -} // namespace android -} // namespace mbgl diff --git a/src/bitmap.hpp b/src/bitmap.hpp deleted file mode 100644 index 9d96405c2..000000000 --- a/src/bitmap.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class Bitmap { -public: - class Config { - public: - static constexpr auto Name() { return "android/graphics/Bitmap$Config"; }; - - enum Value { - ALPHA_8, - ARGB_4444, - ARGB_8888, - RGB_565, - }; - - static jni::Local> Create(jni::JNIEnv&, Value); - }; - - static constexpr auto Name() { return "android/graphics/Bitmap"; }; - static void registerNative(jni::JNIEnv&); - - static jni::Local> - CreateBitmap(jni::JNIEnv&, jni::jint width, jni::jint height, const jni::Object&); - - static jni::Local> - CreateBitmap(jni::JNIEnv& env, jni::jint width, jni::jint height, Config::Value config) { - return CreateBitmap(env, width, height, Config::Create(env, config)); - } - - static PremultipliedImage GetImage(jni::JNIEnv&, const jni::Object&); - static jni::Local> CreateBitmap(jni::JNIEnv&, const PremultipliedImage&); - static jni::Local> Copy(jni::JNIEnv&, const jni::Object&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/bitmap_factory.cpp b/src/bitmap_factory.cpp deleted file mode 100644 index 170bd52ea..000000000 --- a/src/bitmap_factory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "bitmap_factory.hpp" - -namespace mbgl { -namespace android { - -void BitmapFactory::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> BitmapFactory::DecodeByteArray(jni::JNIEnv& env, - jni::Array& data, - jni::jint offset, - jni::jint length) { - static auto& _class = jni::Class::Singleton(env); - - // Images are loaded with ARGB_8888 config, and premultiplied by default, which is exactly - // what we want, so we're not providing a BitmapFactory.Options object. - using Signature = jni::Object (jni::Array, jni::jint, jni::jint); - static auto method = _class.GetStaticMethod(env, "decodeByteArray"); - - return _class.Call(env, method, data, offset, length); -} - -} // namespace android -} // namespace mbgl diff --git a/src/bitmap_factory.hpp b/src/bitmap_factory.hpp deleted file mode 100644 index f73b7a290..000000000 --- a/src/bitmap_factory.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -#include "bitmap.hpp" - -namespace mbgl { -namespace android { - -class BitmapFactory { -public: - static constexpr auto Name() { return "android/graphics/BitmapFactory"; }; - static void registerNative(jni::JNIEnv&); - - static jni::Local> - DecodeByteArray(jni::JNIEnv&, jni::Array& data, jni::jint offset, jni::jint length); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/connectivity_listener.cpp b/src/connectivity_listener.cpp deleted file mode 100644 index 9c13f1f74..000000000 --- a/src/connectivity_listener.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "connectivity_listener.hpp" - -#include -#include - -#include - -namespace mbgl { -namespace android { - - /** - * Invoked when the construction is initiated from the jvm - */ - ConnectivityListener::ConnectivityListener(jni::JNIEnv&) {} - - ConnectivityListener::~ConnectivityListener() {} - - void ConnectivityListener::onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean connected) { - NetworkStatus::Set(connected ? NetworkStatus::Status::Online : NetworkStatus::Status::Offline); - } - - void ConnectivityListener::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, - javaClass, - "nativePtr", - std::make_unique, - "initialize", - "finalize", - METHOD(&ConnectivityListener::onConnectivityStateChanged, "nativeOnConnectivityStateChanged") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/connectivity_listener.hpp b/src/connectivity_listener.hpp deleted file mode 100644 index a09507c0f..000000000 --- a/src/connectivity_listener.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class ConnectivityListener : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/net/NativeConnectivityListener"; }; - - static void registerNative(jni::JNIEnv&); - - /* - * Called when a Java object was created from the jvm side - */ - ConnectivityListener(jni::JNIEnv&); - - ~ConnectivityListener(); - - void onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean); - -}; - -} // namespace android -} // namespace mbgl diff --git a/src/conversion/collection.cpp b/src/conversion/collection.cpp deleted file mode 100644 index 954a161ba..000000000 --- a/src/conversion/collection.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "collection.hpp" -#include "constant.hpp" - -namespace mbgl { -namespace android { -namespace conversion { - -std::vector toVector(JNIEnv& env, const jni::Array& array) { - std::size_t len = array.Length(env); - std::vector vector; - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - vector.push_back(jni::Make(env, array.Get(env, i))); - } - - return vector; -} - -jni::Local> toArray(JNIEnv& env, const std::vector& vector) { - auto result = jni::Array::New(env, vector.size()); - - for (std::size_t i = 0; i < vector.size(); i++) { - result.Set(env, i, jni::Make(env, vector.at(i))); - } - - return result; -} - -} -} -} diff --git a/src/conversion/collection.hpp b/src/conversion/collection.hpp deleted file mode 100644 index 322ebb62e..000000000 --- a/src/conversion/collection.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "conversion.hpp" - -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -std::vector toVector(JNIEnv& env, const jni::Array& array); -jni::Local> toArray(JNIEnv& env, const std::vector&); - -} -} -} diff --git a/src/conversion/color.cpp b/src/conversion/color.cpp deleted file mode 100644 index ce85943e6..000000000 --- a/src/conversion/color.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "color.hpp" - -namespace mbgl { -namespace android { -namespace conversion { - -Result Converter::operator()(jni::JNIEnv&, const int& color) const { - float r = (color >> 16) & 0xFF; - float g = (color >> 8) & 0xFF; - float b = (color) & 0xFF; - float a = (color >> 24) & 0xFF; - return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/conversion/color.hpp b/src/conversion/color.hpp deleted file mode 100644 index 2b4144b93..000000000 --- a/src/conversion/color.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "conversion.hpp" - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter { - Result operator()(jni::JNIEnv&, const int& color) const; -}; - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/conversion/constant.cpp b/src/conversion/constant.cpp deleted file mode 100644 index a409e5dfd..000000000 --- a/src/conversion/constant.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "constant.hpp" -#include "collection.hpp" -#include "../style/formatted.hpp" - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -Result>> Converter>, bool>::operator()(jni::JNIEnv& env, const bool& value) const { - return jni::Box(env, value ? jni::jni_true : jni::jni_false); -} - -Result>> Converter>, float>::operator()(jni::JNIEnv& env, const float& value) const { - return jni::Box(env, value); -} - -Result>> Converter>, double>::operator()(jni::JNIEnv& env, const double& value) const { - return jni::Box(env, value); -} - -Result>> Converter>, std::string>::operator()(jni::JNIEnv& env, const std::string& value) const { - return jni::Make(env, value); -} - -Result>> Converter>, Color>::operator()(jni::JNIEnv& env, const Color& value) const { - return jni::Make(env, value.stringify()); -} - -Result>> Converter>, style::expression::Formatted>::operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const { - return Formatted::New(env, value); -} - -Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { - auto result = jni::Array::New(env, value.size()); - - for (std::size_t i = 0; i < value.size(); i++) { - result.Set(env, i, jni::Make(env, value.at(i))); - } - - return result; -} - -Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { - auto result = jni::Array::New(env, value.size()); - - for (std::size_t i = 0; i < value.size(); i++) { - result.Set(env, i, jni::Box(env, value.at(i))); - } - - return result; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/conversion/constant.hpp b/src/conversion/constant.hpp deleted file mode 100644 index 839e6e84d..000000000 --- a/src/conversion/constant.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include "conversion.hpp" - -#include -#include - -#include - -#include - -#include -#include -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter>, bool> { - Result>> operator()(jni::JNIEnv& env, const bool& value) const; -}; - -template <> -struct Converter>, float> { - Result>> operator()(jni::JNIEnv& env, const float& value) const; -}; - -template <> -struct Converter>, double> { - Result>> operator()(jni::JNIEnv& env, const double& value) const; -}; - -/** - * All integrals. java is limited to 64 bit signed, so... - * TODO: use BigDecimal for > 64 / unsigned? - */ -template -struct Converter>, T, typename std::enable_if::value>::type> { - Result>> operator()(jni::JNIEnv& env, const T& value) const { - return jni::Box(env, jni::jlong(value)); - } -}; - -// TODO: convert integral types to primitive jni types - -template <> -struct Converter>, std::string> { - Result>> operator()(jni::JNIEnv& env, const std::string& value) const; -}; - -template <> -struct Converter>, Color> { - Result>> operator()(jni::JNIEnv& env, const Color& value) const; -}; - -template <> -struct Converter>, style::expression::Formatted> { - Result>> operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const; -}; - -template -struct Converter>, std::array> { - Result>> operator()(jni::JNIEnv& env, const std::array& value) const { - std::vector v; - for (const float& id : value) { - v.push_back(id); - } - return convert>, std::vector>(env, v); - } -}; - -template <> -struct Converter>, std::vector> { - Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; -}; - -template <> -struct Converter>, std::vector> { - Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; -}; - -template -struct Converter>, T, typename std::enable_if_t::value>> { - Result>> operator()(jni::JNIEnv& env, const T& value) const { - return convert>, std::string>(env, Enum::toString(value)); - } -}; - -template -struct Converter>, std::vector, typename std::enable_if_t::value>> { - Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { - auto result = jni::Array::New(env, value.size()); - for (std::size_t i = 0; i < value.size(); ++i) { - result.Set(env, i, jni::Make(env, Enum::toString(value.at(i)))); - } - return result; - } -}; - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/src/conversion/conversion.hpp b/src/conversion/conversion.hpp deleted file mode 100644 index d1766f975..000000000 --- a/src/conversion/conversion.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -struct Error { std::string message; }; - -template -class Result : private variant { -public: - using variant::variant; - - explicit operator bool() const { - return this->template is(); - } - - T& operator*() { - assert(this->template is()); - return this->template get(); - } - - const T& operator*() const { - assert(this->template is()); - return this->template get(); - } - - const Error& error() const { - assert(this->template is()); - return this->template get(); - } -}; - -template -struct Converter; - -template -Result convert(jni::JNIEnv& env, const V& value, Args&&...args) { - return Converter()(env, value, std::forward(args)...); -} - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/src/example_custom_layer.cpp b/src/example_custom_layer.cpp deleted file mode 100644 index e80553254..000000000 --- a/src/example_custom_layer.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include -#include -#include -#include -#include - -// DEBUGGING - -const char* LOG_TAG = "Custom Layer Example"; - -const char* stringFromError(GLenum err) { - switch (err) { - case GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - - case GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - - case GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - - case GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - -#ifdef GL_TABLE_TOO_LARGE - case GL_TABLE_TOO_LARGE: - return "GL_TABLE_TOO_LARGE"; -#endif - -#ifdef GL_STACK_OVERFLOW - case GL_STACK_OVERFLOW: - return "GL_STACK_OVERFLOW"; -#endif - -#ifdef GL_STACK_UNDERFLOW - case GL_STACK_UNDERFLOW: - return "GL_STACK_UNDERFLOW"; -#endif - -#ifdef GL_CONTEXT_LOST - case GL_CONTEXT_LOST: - return "GL_CONTEXT_LOST"; -#endif - - default: - return "GL_UNKNOWN"; - } -} - -struct Error : std::runtime_error { - using std::runtime_error::runtime_error; -}; - -void checkError(const char *cmd, const char *file, int line) { - - GLenum err = GL_NO_ERROR; - if ((err = glGetError()) != GL_NO_ERROR) { - std::ostringstream message; - message << cmd << ": Error " << stringFromError(err); - - // Check for further errors - while ((err = glGetError()) != GL_NO_ERROR) { - message << ", " << stringFromError(err); - } - - message << " at " << file << ":" << line; - __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, message.str().c_str()); - throw Error(message.str()); - } -} - -#ifndef NDEBUG -#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) -#else -#define GL_CHECK_ERROR(cmd) (cmd) -#endif - -void checkLinkStatus(GLuint program) { - GLint isLinked = 0; - glGetProgramiv(program, GL_LINK_STATUS, &isLinked); - if (isLinked == GL_FALSE) { - GLint maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - GLchar infoLog[maxLength]; - glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); - __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &infoLog[0]); - throw Error(infoLog); - } - -} - -void checkCompileStatus(GLuint shader) { - GLint isCompiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) { - GLint maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - - // The maxLength includes the NULL character - GLchar errorLog[maxLength]; - glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); - __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &errorLog[0]); - throw Error(errorLog); - } -} - -// /DEBUGGING - -static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; -static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; - -class ExampleCustomLayer: mbgl::style::CustomLayerHost { -public: - ~ExampleCustomLayer() { - } - - void initialize() { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Initialize"); - - // Debug info - int maxAttrib; - GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); - __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Max vertex attributes: %i", maxAttrib); - - program = GL_CHECK_ERROR(glCreateProgram()); - vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); - fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); - - GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr)); - GL_CHECK_ERROR(glCompileShader(vertexShader)); - checkCompileStatus(vertexShader); - GL_CHECK_ERROR(glAttachShader(program, vertexShader)); - GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr)); - GL_CHECK_ERROR(glCompileShader(fragmentShader)); - checkCompileStatus(fragmentShader); - GL_CHECK_ERROR(glAttachShader(program, fragmentShader)); - GL_CHECK_ERROR(glLinkProgram(program)); - checkLinkStatus(program); - - a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); - fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color")); - - GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; - GL_CHECK_ERROR(glGenBuffers(1, &buffer)); - GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); - GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); - } - - void render(const mbgl::style::CustomLayerRenderParameters&) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); - glUseProgram(program); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glUniform4fv(fill_color, 1, color); - - GL_CHECK_ERROR(glUseProgram(program)); - GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); - GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); - GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL)); - GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); - GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST)); - GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color)); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); - - } - - void contextLost() { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "ContextLost"); - program = 0; - } - - void deinitialize() { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "DeInitialize"); - if (program) { - glDeleteBuffers(1, &buffer); - glDetachShader(program, vertexShader); - glDetachShader(program, fragmentShader); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - glDeleteProgram(program); - } - } - - GLuint program = 0; - GLuint vertexShader = 0; - GLuint fragmentShader = 0; - GLuint buffer = 0; - GLuint a_pos = 0; - GLuint fill_color = 0; - - static GLfloat color[]; -}; - -GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; - -jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); - auto exampleCustomLayer = std::make_unique(); - return reinterpret_cast(exampleCustomLayer.release()); -} - -void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { - __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); - ExampleCustomLayer::color[0] = red; - ExampleCustomLayer::color[1] = green; - ExampleCustomLayer::color[2] = blue; - ExampleCustomLayer::color[3] = alpha; -} - -extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); - - JNIEnv *env = nullptr; - vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - - jclass customLayerClass = env->FindClass("com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer"); - - JNINativeMethod methods[] = { - {"createContext", "()J", reinterpret_cast(&nativeCreateContext)}, - {"setColor", "(FFFF)V", reinterpret_cast(&nativeSetColor)} - }; - - if (env->RegisterNatives(customLayerClass, methods, 2) < 0) { - env->ExceptionDescribe(); - return JNI_ERR; - } - - return JNI_VERSION_1_6; -} - -extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *, void *) { -} diff --git a/src/file_source.cpp b/src/file_source.cpp deleted file mode 100644 index a002d6616..000000000 --- a/src/file_source.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "file_source.hpp" - -#include "attach_env.hpp" -#include "mapbox.hpp" - -#include -#include -#include -#include -#include - -#include - -#include "asset_manager_file_source.hpp" - -namespace mbgl { - -std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { - auto env{android::AttachEnv()}; - std::shared_ptr fileSource; - if (android::Mapbox::hasInstance(*env)) { - auto assetManager = android::Mapbox::getAssetManager(*env); - fileSource = std::make_shared(options.cachePath(), - std::make_unique(*env, assetManager)); - } else { - fileSource = std::make_shared(options.cachePath(), options.assetPath()); - } - fileSource->setAccessToken(options.accessToken()); - return fileSource; -} - -namespace android { - -// FileSource // - -FileSource::FileSource(jni::JNIEnv& _env, const jni::String& accessToken, const jni::String& _cachePath) { - std::string path = jni::Make(_env, _cachePath); - mapbox::sqlite::setTempPath(path); - - resourceOptions.withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") - .withCachePath(path + DATABASE_FILE); - - // Create a core default file source - fileSource = std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(resourceOptions)); -} - -FileSource::~FileSource() { -} - -jni::Local FileSource::getAccessToken(jni::JNIEnv& env) { - return jni::Make(env, fileSource->getAccessToken()); -} - -void FileSource::setAccessToken(jni::JNIEnv& env, const jni::String& token) { - fileSource->setAccessToken(token ? jni::Make(env, token) : ""); -} - -void FileSource::setAPIBaseUrl(jni::JNIEnv& env, const jni::String& url) { - fileSource->setAPIBaseURL(jni::Make(env, url)); -} - -void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object& transformCallback) { - if (transformCallback) { - auto global = jni::NewGlobal(env, transformCallback); - resourceTransform = std::make_unique>( - *Scheduler::GetCurrent(), - // Capture the ResourceTransformCallback object as a managed global into - // the lambda. It is released automatically when we're setting a new ResourceTransform in - // a subsequent call. - // Note: we're converting it to shared_ptr because this lambda is converted to a std::function, - // which requires copyability of its captured variables. - [callback = std::make_shared(std::move(global))](mbgl::Resource::Kind kind, - const std::string& url_) { - android::UniqueEnv _env = android::AttachEnv(); - return FileSource::ResourceTransformCallback::onURL(*_env, *callback, int(kind), url_); - }); - fileSource->setResourceTransform(resourceTransform->self()); - } else { - // Reset the callback - resourceTransform.reset(); - fileSource->setResourceTransform({}); - } -} - -void FileSource::setResourceCachePath(jni::JNIEnv& env, const jni::String& path, - const jni::Object& _callback) { - if (pathChangeCallback) { - FileSource::ResourcesCachePathChangeCallback::onError(env, _callback, jni::Make(env, "Another resources cache path change is in progress")); - return; - } - - std::string newPath = jni::Make(env, path); - mapbox::sqlite::setTempPath(newPath); - - auto global = jni::NewGlobal(env, _callback); - pathChangeCallback = std::make_unique>(*Scheduler::GetCurrent(), - [this, callback = std::make_shared(std::move(global)), newPath] { - android::UniqueEnv _env = android::AttachEnv(); - FileSource::ResourcesCachePathChangeCallback::onSuccess(*_env, *callback, jni::Make(*_env, newPath)); - pathChangeCallback.reset(); - }); - - fileSource->setResourceCachePath(newPath + DATABASE_FILE, pathChangeCallback->self()); -} - -void FileSource::resume(jni::JNIEnv&) { - if (!activationCounter) { - activationCounter = optional(1) ; - return; - } - - activationCounter.value()++; - if (activationCounter == 1) { - fileSource->resume(); - } -} - -void FileSource::pause(jni::JNIEnv&) { - if (activationCounter) { - activationCounter.value()--; - if (activationCounter == 0) { - fileSource->pause(); - } - } -} - -jni::jboolean FileSource::isResumed(jni::JNIEnv&) { - if (activationCounter) { - return (jboolean) (activationCounter > 0); - } - return (jboolean) false; -} - -FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object& jFileSource) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "nativePtr"); - return reinterpret_cast(jFileSource.Get(env, field)); -} - -mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object& jFileSource) { - FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); - assert(fileSource != nullptr); - return fileSource->resourceOptions.clone(); -} - -// FileSource::ResourcesCachePathChangeCallback // - -void FileSource::ResourcesCachePathChangeCallback::onSuccess(jni::JNIEnv& env, - const jni::Object& callback, - const jni::String& path) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onSuccess"); - - callback.Call(env, method, path); -} - -void FileSource::ResourcesCachePathChangeCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - const jni::String& message) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, message); -} - -void FileSource::registerNative(jni::JNIEnv& env) { - // Ensure the classes are cached. If they're requested for the - // first time on a background thread, Android's class loader heuristics will fail. - // https://developer.android.com/training/articles/perf-jni#faq_FindClass - jni::Class::Singleton(env); - jni::Class::Singleton(env); - - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, - javaClass, - "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&FileSource::getAccessToken, "getAccessToken"), - METHOD(&FileSource::setAccessToken, "setAccessToken"), - METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), - METHOD(&FileSource::setResourceTransform, "setResourceTransform"), - METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), - METHOD(&FileSource::resume, "activate"), - METHOD(&FileSource::pause, "deactivate"), - METHOD(&FileSource::isResumed, "isActivated")); -} - - -// FileSource::ResourceTransformCallback // - -std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, const jni::Object& callback, int kind, std::string url_) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onURL"); - - return jni::Make(env, - callback.Call(env, method, kind, - jni::Make(env, url_))); -} - -} // namespace android -} // namespace mbgl diff --git a/src/file_source.hpp b/src/file_source.hpp deleted file mode 100644 index 6a9190fa0..000000000 --- a/src/file_source.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include -#include - -#include "asset_manager.hpp" - -#include - -namespace mbgl { - -template class Actor; -class ResourceTransform; -using mbgl::PathChangeCallback; - -namespace android { - -/** - * Peer class for the Android FileSource holder. Ensures that a single DefaultFileSource is used - */ -class FileSource { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; }; - - struct ResourceTransformCallback { - static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; } - - static std::string onURL(jni::JNIEnv&, const jni::Object&, int, std::string); - }; - - struct ResourcesCachePathChangeCallback { - static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourcesCachePathChangeCallback";} - - static void onSuccess(jni::JNIEnv&, - const jni::Object&, - const jni::String&); - - static void onError(jni::JNIEnv&, - const jni::Object&, - const jni::String&); - }; - - FileSource(jni::JNIEnv&, const jni::String&, const jni::String&); - - ~FileSource(); - - jni::Local getAccessToken(jni::JNIEnv&); - - void setAccessToken(jni::JNIEnv&, const jni::String&); - - void setAPIBaseUrl(jni::JNIEnv&, const jni::String&); - - void setResourceTransform(jni::JNIEnv&, const jni::Object&); - - void setResourceCachePath(jni::JNIEnv&, const jni::String&, const jni::Object&); - - void resume(jni::JNIEnv&); - - void pause(jni::JNIEnv&); - - jni::jboolean isResumed(jni::JNIEnv&); - - static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object&); - - static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); - -private: - const std::string DATABASE_FILE = "/mbgl-offline.db"; - optional activationCounter; - mbgl::ResourceOptions resourceOptions; - std::unique_ptr> resourceTransform; - std::unique_ptr> pathChangeCallback; - std::shared_ptr fileSource; -}; - - -} // namespace android -} // namespace mbgl diff --git a/src/geojson/feature.cpp b/src/geojson/feature.cpp deleted file mode 100644 index 8d30404a5..000000000 --- a/src/geojson/feature.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "feature.hpp" -#include "geometry.hpp" -#include "../gson/json_object.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -using namespace gson; - -mbgl::Feature Feature::convert(jni::JNIEnv& env, const jni::Object& jFeature) { - static auto& javaClass = jni::Class::Singleton(env); - static auto id = javaClass.GetMethod(env, "id"); - static auto geometry = javaClass.GetMethod ()>(env, "geometry"); - static auto properties = javaClass.GetMethod ()>(env, "properties"); - - auto jId = jFeature.Call(env, id); - - using mbid = mapbox::feature::identifier; - - return mbgl::Feature { - Geometry::convert(env, jFeature.Call(env, geometry)), - JsonObject::convert(env, jFeature.Call(env, properties)), - jId ? mbid { jni::Make(env, jId) } : mbid { mapbox::feature::null_value } - }; -} - -/** - * Turn feature identifier into std::string - */ -class FeatureIdVisitor { -public: - template - std::string operator()(const T& i) const { - return util::toString(i); - } - - std::string operator()(const std::string& i) const { - return i; - } - - std::string operator()(const std::nullptr_t&) const { - return {}; - } - - std::string operator()(const mapbox::feature::null_value_t&) const { - return {}; - } -}; - -jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::Feature& value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); - - return javaClass.Call(env, method, - Geometry::New(env, value.geometry), - JsonObject::New(env, value.properties), - jni::Make(env, value.id.is() ? std::string {} : value.id.match(FeatureIdVisitor()))); -} - -jni::Local>> Feature::convert(jni::JNIEnv& env, const std::vector& value) { - auto features = jni::Array>::New(env, value.size()); - - for (size_t i = 0; i < value.size(); i = i + 1) { - features.Set(env, i, convertFeature(env, value.at(i))); - } - - return features; -} - -void Feature::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl diff --git a/src/geojson/feature.hpp b/src/geojson/feature.hpp deleted file mode 100644 index fdf5d977b..000000000 --- a/src/geojson/feature.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class Feature { -public: - static constexpr auto Name() { return "com/mapbox/geojson/Feature"; }; - - static mbgl::Feature convert(jni::JNIEnv&, const jni::Object&); - static jni::Local>> convert(jni::JNIEnv&, const std::vector&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/feature_collection.cpp b/src/geojson/feature_collection.cpp deleted file mode 100644 index f90d5226b..000000000 --- a/src/geojson/feature_collection.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "feature_collection.hpp" - -#include "feature.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, const jni::Object& jCollection) { - auto collection = mbgl::FeatureCollection(); - - if (jCollection) { - auto jFeatureList = FeatureCollection::features(env, jCollection); - auto jFeatures = java::util::List::toArray(env, jFeatureList); - auto size = size_t(jFeatures.Length(env)); - collection.reserve(size); - - for (size_t i = 0; i < size; i++) { - collection.push_back(Feature::convert(env, jFeatures.Get(env, i))); - } - } - return collection; -} - -jni::Local> FeatureCollection::features(jni::JNIEnv& env, const jni::Object& jCollection) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "features"); - return jCollection.Call(env, method); -} - -void FeatureCollection::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/feature_collection.hpp b/src/geojson/feature_collection.hpp deleted file mode 100644 index 66e92eaca..000000000 --- a/src/geojson/feature_collection.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "../java/util.hpp" - -#include - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class FeatureCollection { -public: - static constexpr auto Name() { return "com/mapbox/geojson/FeatureCollection"; }; - - static mbgl::FeatureCollection convert(jni::JNIEnv&, const jni::Object&); - - static jni::Local> features(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry.cpp b/src/geojson/geometry.cpp deleted file mode 100644 index 0598b9fc5..000000000 --- a/src/geojson/geometry.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "geometry.hpp" - -#include "point.hpp" -#include "multi_point.hpp" -#include "line_string.hpp" -#include "multi_line_string.hpp" -#include "polygon.hpp" -#include "multi_polygon.hpp" -#include "geometry_collection.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -/** - * Turn mapbox::geometry type into Java GeoJson Geometries - */ -class GeometryEvaluator { -public: - - jni::JNIEnv& env; - - jni::Local> operator()(const mbgl::EmptyGeometry &) const { - // FIXME: mapbox-java needs to have its own Empty type. - return GeometryCollection::New(env, {}); - } - - jni::Local> operator()(const mbgl::Point &geometry) const { - return Point::New(env, geometry); - } - - jni::Local> operator()(const mbgl::LineString &geometry) const { - return LineString::New(env, geometry); - } - - jni::Local> operator()(const mbgl::MultiLineString &geometry) const { - return MultiLineString::New(env, geometry); - } - - jni::Local> operator()(const mbgl::MultiPoint &geometry) const { - return MultiPoint::New(env, geometry); - } - - jni::Local> operator()(const mbgl::Polygon &geometry) const { - return Polygon::New(env, geometry); - } - - jni::Local> operator()(const mbgl::MultiPolygon &geometry) const { - return MultiPolygon::New(env, geometry); - } - - jni::Local> operator()(const mapbox::geometry::geometry_collection &geometry) const { - return GeometryCollection::New(env, geometry); - } -}; - -jni::Local> Geometry::New(jni::JNIEnv& env, mbgl::Geometry geometry) { - GeometryEvaluator evaluator { env } ; - return mbgl::Geometry::visit(geometry, evaluator); -} - -mbgl::Geometry Geometry::convert(jni::JNIEnv &env, const jni::Object& jGeometry) { - auto type = Geometry::getType(env, jGeometry); - if (type == Point::Type()) { - return { Point::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == MultiPoint::Type()) { - return { MultiPoint::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == LineString::Type()) { - return { LineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == MultiLineString::Type()) { - return { MultiLineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == Polygon::Type()) { - return { Polygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == MultiPolygon::Type()) { - return { MultiPolygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } else if (type == GeometryCollection::Type()) { - return { GeometryCollection::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; - } - - throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); -} - -std::string Geometry::getType(jni::JNIEnv &env, const jni::Object& jGeometry) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "type"); - return jni::Make(env, jGeometry.Call(env, method)); -} - -void Geometry::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl diff --git a/src/geojson/geometry.hpp b/src/geojson/geometry.hpp deleted file mode 100644 index 4bf55c858..000000000 --- a/src/geojson/geometry.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include "../java/util.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class Geometry { -public: - static constexpr auto Name() { return "com/mapbox/geojson/Geometry"; }; - - static jni::Local> New(jni::JNIEnv&, mbgl::Geometry); - - static mbgl::Geometry convert(jni::JNIEnv&, const jni::Object&); - - static std::string getType(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry_collection.cpp b/src/geojson/geometry_collection.cpp deleted file mode 100644 index cca909126..000000000 --- a/src/geojson/geometry_collection.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "geometry_collection.hpp" -#include "../java/util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> GeometryCollection::New(jni::JNIEnv& env, const mapbox::geometry::geometry_collection& collection) { - // Create an array of geometries - auto jarray = jni::Array>::New(env, collection.size()); - - for (size_t i = 0; i < collection.size(); i++) { - jarray.Set(env, i, Geometry::New(env, collection.at(i))); - } - - // create the GeometryCollection - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromGeometries"); - return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); -} - -mapbox::geometry::geometry_collection GeometryCollection::convert(jni::JNIEnv &env, const jni::Object& jCollection) { - // Get geometries - static auto& javaClass = jni::Class::Singleton(env); - static auto getGeometries = javaClass.GetMethod ()>(env, "geometries"); - - // Turn into array - auto jarray = java::util::List::toArray(env, jCollection.Call(env, getGeometries)); - - // Convert each geometry - mapbox::geometry::geometry_collection collection{}; - - auto size = jarray.Length(env); - for (jni::jsize i = 0; i < size; i++) { - collection.push_back(Geometry::convert(env, jarray.Get(env, i))); - } - - return collection; -} - -void GeometryCollection::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/geometry_collection.hpp b/src/geojson/geometry_collection.hpp deleted file mode 100644 index 9f02ac848..000000000 --- a/src/geojson/geometry_collection.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "geometry.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class GeometryCollection { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/GeometryCollection"; }; - static constexpr auto Type() { return "GeometryCollection"; }; - - static jni::Local> New(jni::JNIEnv&, const mapbox::geometry::geometry_collection&); - - static mapbox::geometry::geometry_collection convert(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/line_string.cpp b/src/geojson/line_string.cpp deleted file mode 100644 index ae1345c95..000000000 --- a/src/geojson/line_string.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "line_string.hpp" -#include "point.hpp" -#include "util.hpp" -#include "../java/util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> LineString::New(jni::JNIEnv& env, const mbgl::LineString& lineString) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); - - return javaClass.Call(env, method, asPointsList(env, lineString)); -} - -mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object& jLineString) { - mapbox::geojson::line_string lineString; - - if (jLineString) { - lineString = LineString::convert(env, LineString::coordinates(env, jLineString)); - } - - return lineString; -} - -mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object*/>& jPointList) { - mapbox::geojson::line_string lineString; - - if (jPointList) { - auto jPointArray = java::util::List::toArray(env, jPointList); - auto size = jPointArray.Length(env); - lineString.reserve(size); - - for (std::size_t i = 0; i < size; i++) { - lineString.push_back(Point::convert(env, jPointArray.Get(env, i))); - } - } - - return lineString; -} - -jni::Local> LineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "coordinates"); - return jLineString.Call(env, method); -} - -void LineString::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/line_string.hpp b/src/geojson/line_string.hpp deleted file mode 100644 index 906d809fa..000000000 --- a/src/geojson/line_string.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "geometry.hpp" -#include "../java/util.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - - -class LineString { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/LineString"; }; - static constexpr auto Type() { return "LineString"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::LineString&); - - static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object&); - - static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object*/>&); - - static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_line_string.cpp b/src/geojson/multi_line_string.cpp deleted file mode 100644 index 1aaf53c01..000000000 --- a/src/geojson/multi_line_string.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "multi_line_string.hpp" - -#include "line_string.hpp" -#include "util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> MultiLineString::New(jni::JNIEnv& env, const mbgl::MultiLineString& multiLineString) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); - - return javaClass.Call(env, method, asPointsListsList(env, multiLineString)); -} - -mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object& jMultiLineString) { - mapbox::geojson::multi_line_string multiLineString; - - if (jMultiLineString) { - multiLineString = MultiLineString::convert(env, MultiLineString::coordinates(env, jMultiLineString)); - } - - return multiLineString; -} - -mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { - mapbox::geojson::multi_line_string multiLineString; - - if (jPointListsList) { - auto jPositionListsArray = java::util::List::toArray(env, jPointListsList); - - auto size = jPositionListsArray.Length(env); - multiLineString.reserve(size); - - for (std::size_t i = 0; i < size; i++) { - multiLineString.push_back(LineString::convert(env, jPositionListsArray.Get(env, i))); - } - } - - return multiLineString; -} - -jni::Local> MultiLineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "coordinates"); - return jLineString.Call(env, method); -} - -void MultiLineString::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_line_string.hpp b/src/geojson/multi_line_string.hpp deleted file mode 100644 index 65ce43bd1..000000000 --- a/src/geojson/multi_line_string.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -#include "../java/util.hpp" -#include "geometry.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class MultiLineString { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/MultiLineString"; }; - static constexpr auto Type() { return "MultiLineString"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::MultiLineString&); - - static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object&); - - static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object>*/>&); - - static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_point.cpp b/src/geojson/multi_point.cpp deleted file mode 100644 index d530ef721..000000000 --- a/src/geojson/multi_point.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "multi_point.hpp" - -#include "line_string.hpp" - -#include "util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> MultiPoint::New(JNIEnv& env, const mbgl::MultiPoint& multiPoint) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); - - return javaClass.Call(env, method, asPointsList(env, multiPoint)); -} - -mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv& env, const jni::Object& jMultiPoint) { - mapbox::geojson::multi_point multiPoint; - - if (jMultiPoint) { - multiPoint = convertExplicit( - LineString::convert(env, MultiPoint::coordinates(env, jMultiPoint))); - } - - return multiPoint; -} - -jni::Local> MultiPoint::coordinates(jni::JNIEnv& env, const jni::Object& jMultiPoint) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "coordinates"); - return jMultiPoint.Call(env, method); -} - -void MultiPoint::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_point.hpp b/src/geojson/multi_point.hpp deleted file mode 100644 index a3ca49b73..000000000 --- a/src/geojson/multi_point.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "geometry.hpp" -#include "../java/util.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class MultiPoint { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/MultiPoint"; }; - static constexpr auto Type() { return "MultiPoint"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPoint&); - - static mapbox::geojson::multi_point convert(jni::JNIEnv&, const jni::Object&); - - static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_polygon.cpp b/src/geojson/multi_polygon.cpp deleted file mode 100644 index 3c5c3ec33..000000000 --- a/src/geojson/multi_polygon.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "multi_polygon.hpp" - -#include "polygon.hpp" -#include "util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> MultiPolygon::New(JNIEnv& env, const mbgl::MultiPolygon& multiPolygon) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); - - auto jarray = jni::Array>::New(env, multiPolygon.size()); - - for (size_t i = 0; i < multiPolygon.size(); i++) { - jarray.Set(env, i, asPointsListsList(env, multiPolygon.at(i))); - } - - return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); -} - -mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv& env, const jni::Object& jMultiPolygon) { - mapbox::geojson::multi_polygon multiPolygon; - - if (jMultiPolygon) { - auto jPointListsListList = MultiPolygon::coordinates(env, jMultiPolygon); - auto jPointListsListArray = java::util::List::toArray(env, jPointListsListList); - - auto size = jPointListsListArray.Length(env); - multiPolygon.reserve(size); - - for (size_t i = 0; i < size; i++) { - multiPolygon.push_back(Polygon::convert(env, jPointListsListArray.Get(env, i))); - } - } - - return multiPolygon; -} - -jni::Local> MultiPolygon::coordinates(jni::JNIEnv& env, const jni::Object& jPolygon) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "coordinates"); - return jPolygon.Call(env, method); -} - -void MultiPolygon::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/multi_polygon.hpp b/src/geojson/multi_polygon.hpp deleted file mode 100644 index fd7b08016..000000000 --- a/src/geojson/multi_polygon.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -#include "../java/util.hpp" -#include "geometry.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class MultiPolygon { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/MultiPolygon"; }; - static constexpr auto Type() { return "MultiPolygon"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPolygon&); - - static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, const jni::Object&); - - static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/point.cpp b/src/geojson/point.cpp deleted file mode 100644 index 2000447c0..000000000 --- a/src/geojson/point.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "point.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> Point::New(jni::JNIEnv& env, const mbgl::Point& point) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::jdouble, jni::jdouble)>(env, "fromLngLat"); - return javaClass.Call(env, method, point.x, point.y); -} - -mbgl::Point Point::convert(jni::JNIEnv &env, const jni::Object& jPoint) { - static auto& javaClass = jni::Class::Singleton(env); - static auto longitude = javaClass.GetMethod(env, "longitude"); - static auto latitude = javaClass.GetMethod(env, "latitude"); - - if (!jPoint) { - return {}; - } - - return { - jPoint.Call(env, longitude), - jPoint.Call(env, latitude) - }; -} - -void Point::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl diff --git a/src/geojson/point.hpp b/src/geojson/point.hpp deleted file mode 100644 index b5d71ecae..000000000 --- a/src/geojson/point.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -#include "geometry.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -class Point { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/Point"; }; - static constexpr auto Type() { return "Point"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::Point&); - static mbgl::Point convert(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/polygon.cpp b/src/geojson/polygon.cpp deleted file mode 100644 index 4437d134a..000000000 --- a/src/geojson/polygon.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "polygon.hpp" - -#include "multi_line_string.hpp" - -#include "util.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -jni::Local> Polygon::New(jni::JNIEnv& env, const mbgl::Polygon& polygon) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); - - return javaClass.Call(env, method, asPointsListsList(env, polygon)); -} - -mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object& jPolygon) { - mapbox::geojson::polygon polygon; - - if (jPolygon) { - polygon = Polygon::convert(env, Polygon::coordinates(env, jPolygon)); - } - - return polygon; -} - -mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { - mapbox::geojson::polygon polygon; - - if (jPointListsList) { - auto multiLine = MultiLineString::convert(env, jPointListsList); - polygon.reserve(multiLine.size()); - for (auto&& line : multiLine) { - polygon.emplace_back(convertExplicit(std::move(line))); - } - } - - return polygon; -} - - -jni::Local> Polygon::coordinates(jni::JNIEnv &env, const jni::Object& jPolygon) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "coordinates"); - return jPolygon.Call(env, method); -} - -void Polygon::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/polygon.hpp b/src/geojson/polygon.hpp deleted file mode 100644 index 8e1761fed..000000000 --- a/src/geojson/polygon.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -#include "geometry.hpp" -#include "../java/util.hpp" - -#include - - -namespace mbgl { -namespace android { -namespace geojson { - -class Polygon { -public: - using SuperTag = Geometry; - static constexpr auto Name() { return "com/mapbox/geojson/Polygon"; }; - static constexpr auto Type() { return "Polygon"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::Polygon&); - - static mapbox::geojson::polygon convert(jni::JNIEnv &, const jni::Object&); - - static mapbox::geojson::polygon convert(jni::JNIEnv&, const jni::Object>*/>&); - - static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv &); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geojson/util.hpp b/src/geojson/util.hpp deleted file mode 100644 index 59154516f..000000000 --- a/src/geojson/util.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "point.hpp" - -#include - -namespace mbgl { -namespace android { -namespace geojson { - -// Clang 3.8 fails to implicitly convert matching types, so we'll have to do it explicitly. -template -To convertExplicit(From&& src) { - static_assert(std::is_same::container_type, - typename To::container_type>::value, - "container types do not match"); - static_assert(std::is_rvalue_reference::value, - "argument must be rvalue reference"); - return *reinterpret_cast>(&src); -} - -/** - * Geometry -> List - */ -template -static jni::Local> asPointsList(jni::JNIEnv& env, const T& pointsList) { - auto jarray = jni::Array>::New(env, pointsList.size()); - - for (jni::jsize i = 0; i < pointsList.size(); i++) { - jarray.Set(env, i, Point::New(env, pointsList.at(i))); - } - - return java::util::Arrays::asList(env, jarray); -} - -/** - * Geometry -> List> - */ -template -static jni::Local> asPointsListsList(JNIEnv& env, const SHAPE& value) { - auto jarray = jni::Array>::New(env, value.size()); - - for (size_t i = 0; i < value.size(); i++) { - jarray.Set(env, i, asPointsList(env, value[i])); - } - - return java::util::Arrays::asList(env, jarray); -} - -} // namespace geojson -} // namespace android -} // namespace mbgl diff --git a/src/geometry/lat_lng.cpp b/src/geometry/lat_lng.cpp deleted file mode 100644 index 5d8313cb2..000000000 --- a/src/geometry/lat_lng.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "lat_lng.hpp" - -namespace mbgl { -namespace android { - -jni::Local> LatLng::New(jni::JNIEnv& env, const mbgl::LatLng& latLng) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, latLng.latitude(), latLng.longitude()); -} - -mbgl::Point LatLng::getGeometry(jni::JNIEnv& env, const jni::Object& latLng) { - static auto& javaClass = jni::Class::Singleton(env); - static auto latitudeField = javaClass.GetField(env, "latitude"); - static auto longitudeField = javaClass.GetField(env, "longitude"); - return mbgl::Point(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField)); -} - -mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, const jni::Object& latLng) { - auto point = LatLng::getGeometry(env, latLng); - return mbgl::LatLng(point.y, point.x); -} - -void LatLng::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng.hpp b/src/geometry/lat_lng.hpp deleted file mode 100644 index 30b7db1ef..000000000 --- a/src/geometry/lat_lng.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -namespace mbgl { -namespace android { - -class LatLng : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::LatLng&); - - static mbgl::Point getGeometry(jni::JNIEnv&, const jni::Object&); - - static mbgl::LatLng getLatLng(jni::JNIEnv&, const jni::Object&); - - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_bounds.cpp b/src/geometry/lat_lng_bounds.cpp deleted file mode 100644 index cf534a06e..000000000 --- a/src/geometry/lat_lng_bounds.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "lat_lng_bounds.hpp" - -namespace mbgl { -namespace android { - -jni::Local> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west()); -} - -mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, const jni::Object& bounds) { - static auto& javaClass = jni::Class::Singleton(env); - static auto swLatField = javaClass.GetField(env, "latitudeSouth"); - static auto swLonField = javaClass.GetField(env, "longitudeWest"); - static auto neLatField = javaClass.GetField(env, "latitudeNorth"); - static auto neLonField = javaClass.GetField(env, "longitudeEast"); - - mbgl::LatLng sw = { bounds.Get(env, swLatField), bounds.Get(env, swLonField) }; - mbgl::LatLng ne = { bounds.Get(env, neLatField), bounds.Get(env, neLonField) }; - - return mbgl::LatLngBounds::hull(sw, ne); -} - -void LatLngBounds::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_bounds.hpp b/src/geometry/lat_lng_bounds.hpp deleted file mode 100644 index d51026711..000000000 --- a/src/geometry/lat_lng_bounds.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -namespace mbgl { -namespace android { - -class LatLngBounds : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; }; - - static jni::Local> New(jni::JNIEnv&, mbgl::LatLngBounds); - - static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_quad.cpp b/src/geometry/lat_lng_quad.cpp deleted file mode 100644 index 1a1e49048..000000000 --- a/src/geometry/lat_lng_quad.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "lat_lng_quad.hpp" -#include "lat_lng.hpp" - -namespace mbgl { -namespace android { - -jni::Local> LatLngQuad::New(jni::JNIEnv& env, std::array coordinates) { - static auto& javaClass = jni::Class::Singleton(env); - static auto quadConstructor = javaClass.GetConstructor, jni::Object, jni::Object, jni::Object>(env); - return javaClass.New(env, quadConstructor, - LatLng::New(env, coordinates[0]), - LatLng::New(env, coordinates[1]), - LatLng::New(env, coordinates[2]), - LatLng::New(env, coordinates[3])); -} - -std::array LatLngQuad::getLatLngArray(jni::JNIEnv& env, const jni::Object& quad) { - static auto& javaClass = jni::Class::Singleton(env); - static auto topLeftField = javaClass.GetField >(env, "topLeft"); - static auto topRightField = javaClass.GetField >(env, "topRight"); - static auto bottomRightField = javaClass.GetField >(env, "bottomRight"); - static auto bottomLeftField = javaClass.GetField >(env, "bottomLeft"); - - return std::array < mbgl::LatLng, 4 > {{ - LatLng::getLatLng(env, quad.Get(env, topLeftField)), - LatLng::getLatLng(env, quad.Get(env, topRightField)), - LatLng::getLatLng(env, quad.Get(env, bottomRightField)), - LatLng::getLatLng(env, quad.Get(env, bottomLeftField)) - }}; -} - -void LatLngQuad::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/lat_lng_quad.hpp b/src/geometry/lat_lng_quad.hpp deleted file mode 100644 index f6560b57b..000000000 --- a/src/geometry/lat_lng_quad.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -namespace mbgl { -namespace android { - -class LatLngQuad : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngQuad"; }; - - static jni::Local> New(jni::JNIEnv&, std::array); - - static std::array getLatLngArray(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/projected_meters.cpp b/src/geometry/projected_meters.cpp deleted file mode 100644 index e079de006..000000000 --- a/src/geometry/projected_meters.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "projected_meters.hpp" - -namespace mbgl { -namespace android { - -jni::Local> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, northing, easting); -} - -void ProjectedMeters::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/geometry/projected_meters.hpp b/src/geometry/projected_meters.hpp deleted file mode 100644 index baad1efc8..000000000 --- a/src/geometry/projected_meters.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace mbgl { -namespace android { - -class ProjectedMeters : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; }; - - static jni::Local> New(jni::JNIEnv&, double, double); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gl_functions.cpp b/src/gl_functions.cpp deleted file mode 100644 index 637788e4a..000000000 --- a/src/gl_functions.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include - -#define GL_GLEXT_PROTOTYPES -#include -#include - -namespace mbgl { -namespace platform { - -void (* const glActiveTexture)(GLenum) = ::glActiveTexture; -void (* const glAttachShader)(GLuint, GLuint) = ::glAttachShader; -void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar *) = ::glBindAttribLocation; -void (* const glBindBuffer)(GLenum, GLuint) = ::glBindBuffer; -void (* const glBindFramebuffer)(GLenum, GLuint) = ::glBindFramebuffer; -void (* const glBindRenderbuffer)(GLenum, GLuint) = ::glBindRenderbuffer; -void (* const glBindTexture)(GLenum, GLuint) = ::glBindTexture; -void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glBlendColor; -void (* const glBlendEquation)(GLenum) = ::glBlendEquation; -void (* const glBlendEquationSeparate)(GLenum, GLenum) = ::glBlendEquationSeparate; -void (* const glBlendFunc)(GLenum, GLenum) = ::glBlendFunc; -void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glBlendFuncSeparate; -void (* const glBufferData)(GLenum, GLsizeiptr, const void *, GLenum) = ::glBufferData; -void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void *) = ::glBufferSubData; -GLenum (* const glCheckFramebufferStatus)(GLenum) = ::glCheckFramebufferStatus; -void (* const glClear)(GLbitfield) = ::glClear; -void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glClearColor; -void (* const glClearDepthf)(GLfloat) = ::glClearDepthf; -void (* const glClearStencil)(GLint) = ::glClearStencil; -void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean) = ::glColorMask; -void (* const glCompileShader)(GLuint) = ::glCompileShader; -void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void *) = ::glCompressedTexImage2D; -void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void *) = ::glCompressedTexSubImage2D; -void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) = ::glCopyTexImage2D; -void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) = ::glCopyTexSubImage2D; -GLuint (* const glCreateProgram)() = ::glCreateProgram; -GLuint (* const glCreateShader)(GLenum) = ::glCreateShader; -void (* const glCullFace)(GLenum) = ::glCullFace; -void (* const glDeleteBuffers)(GLsizei, const GLuint *) = ::glDeleteBuffers; -void (* const glDeleteFramebuffers)(GLsizei, const GLuint *) = ::glDeleteFramebuffers; -void (* const glDeleteProgram)(GLuint) = ::glDeleteProgram; -void (* const glDeleteRenderbuffers)(GLsizei, const GLuint *) = ::glDeleteRenderbuffers; -void (* const glDeleteShader)(GLuint) = ::glDeleteShader; -void (* const glDeleteTextures)(GLsizei, const GLuint *) = ::glDeleteTextures; -void (* const glDepthFunc)(GLenum) = ::glDepthFunc; -void (* const glDepthMask)(GLboolean) = ::glDepthMask; -void (* const glDepthRangef)(GLfloat, GLfloat) = ::glDepthRangef; -void (* const glDetachShader)(GLuint, GLuint) = ::glDetachShader; -void (* const glDisable)(GLenum) = ::glDisable; -void (* const glDisableVertexAttribArray)(GLuint) = ::glDisableVertexAttribArray; -void (* const glDrawArrays)(GLenum, GLint, GLsizei) = ::glDrawArrays; -void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void *) = ::glDrawElements; -void (* const glEnable)(GLenum) = ::glEnable; -void (* const glEnableVertexAttribArray)(GLuint) = ::glEnableVertexAttribArray; -void (* const glFinish)() = ::glFinish; -void (* const glFlush)() = ::glFlush; -void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint) = ::glFramebufferRenderbuffer; -void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint) = ::glFramebufferTexture2D; -void (* const glFrontFace)(GLenum) = ::glFrontFace; -void (* const glGenBuffers)(GLsizei, GLuint *) = ::glGenBuffers; -void (* const glGenerateMipmap)(GLenum) = ::glGenerateMipmap; -void (* const glGenFramebuffers)(GLsizei, GLuint *) = ::glGenFramebuffers; -void (* const glGenRenderbuffers)(GLsizei, GLuint *) = ::glGenRenderbuffers; -void (* const glGenTextures)(GLsizei, GLuint *) = ::glGenTextures; -void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveAttrib; -void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveUniform; -void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei *, GLuint *) = ::glGetAttachedShaders; -GLint (* const glGetAttribLocation)(GLuint, const GLchar *) = ::glGetAttribLocation; -void (* const glGetBooleanv)(GLenum, GLboolean *) = ::glGetBooleanv; -void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetBufferParameteriv; -GLenum (* const glGetError)() = ::glGetError; -void (* const glGetFloatv)(GLenum, GLfloat *) = ::glGetFloatv; -void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint *) = ::glGetFramebufferAttachmentParameteriv; -void (* const glGetIntegerv)(GLenum, GLint *) = ::glGetIntegerv; -void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetProgramInfoLog; -void (* const glGetProgramiv)(GLuint, GLenum, GLint *) = ::glGetProgramiv; -void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetRenderbufferParameteriv; -void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderInfoLog; -void (* const glGetShaderiv)(GLuint, GLenum, GLint *) = ::glGetShaderiv; -void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderSource; -const GLubyte *(*glGetString)(GLenum) = ::glGetString; -void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat *) = ::glGetTexParameterfv; -void (* const glGetTexParameteriv)(GLenum, GLenum, GLint *) = ::glGetTexParameteriv; -void (* const glGetUniformfv)(GLuint, GLint, GLfloat *) = ::glGetUniformfv; -void (* const glGetUniformiv)(GLuint, GLint, GLint *) = ::glGetUniformiv; -GLint (* const glGetUniformLocation)(GLuint, const GLchar *) = ::glGetUniformLocation; -void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat *) = ::glGetVertexAttribfv; -void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint *) = ::glGetVertexAttribiv; -void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void **) = ::glGetVertexAttribPointerv; -void (* const glHint)(GLenum, GLenum) = ::glHint; -GLboolean (* const glIsBuffer)(GLuint) = ::glIsBuffer; -GLboolean (* const glIsEnabled)(GLenum) = ::glIsEnabled; -GLboolean (* const glIsFramebuffer)(GLuint) = ::glIsFramebuffer; -GLboolean (* const glIsProgram)(GLuint) = ::glIsProgram; -GLboolean (* const glIsRenderbuffer)(GLuint) = ::glIsRenderbuffer; -GLboolean (* const glIsShader)(GLuint) = ::glIsShader; -GLboolean (* const glIsTexture)(GLuint) = ::glIsTexture; -void (* const glLineWidth)(GLfloat) = ::glLineWidth; -void (* const glLinkProgram)(GLuint) = ::glLinkProgram; -void (* const glPixelStorei)(GLenum, GLint) = ::glPixelStorei; -void (* const glPolygonOffset)(GLfloat, GLfloat) = ::glPolygonOffset; -void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void *) = ::glReadPixels; -void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei) = ::glRenderbufferStorage; -void (* const glSampleCoverage)(GLfloat, GLboolean) = ::glSampleCoverage; -void (* const glScissor)(GLint, GLint, GLsizei, GLsizei) = ::glScissor; - -// Some implementations use `const GLchar* const*` and others `const GLchar**`. -void (* const glShaderSource)(GLuint, GLsizei, const GLchar * const*, const GLint *) = [](GLuint shader, GLsizei count, const GLchar * const * string, const GLint *length) { - ::glShaderSource(shader, count, const_cast(string), length); -}; - -void (* const glStencilFunc)(GLenum, GLint, GLuint) = ::glStencilFunc; -void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint) = ::glStencilFuncSeparate; -void (* const glStencilMask)(GLuint) = ::glStencilMask; -void (* const glStencilMaskSeparate)(GLenum, GLuint) = ::glStencilMaskSeparate; -void (* const glStencilOp)(GLenum, GLenum, GLenum) = ::glStencilOp; -void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glStencilOpSeparate; -void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *) = ::glTexImage2D; -void (* const glTexParameterf)(GLenum, GLenum, GLfloat) = ::glTexParameterf; -void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat *) = ::glTexParameterfv; -void (* const glTexParameteri)(GLenum, GLenum, GLint) = ::glTexParameteri; -void (* const glTexParameteriv)(GLenum, GLenum, const GLint *) = ::glTexParameteriv; -void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *) = ::glTexSubImage2D; -void (* const glUniform1f)(GLint, GLfloat) = ::glUniform1f; -void (* const glUniform1fv)(GLint, GLsizei, const GLfloat *) = ::glUniform1fv; -void (* const glUniform1i)(GLint, GLint) = ::glUniform1i; -void (* const glUniform1iv)(GLint, GLsizei, const GLint *) = ::glUniform1iv; -void (* const glUniform2f)(GLint, GLfloat, GLfloat) = ::glUniform2f; -void (* const glUniform2fv)(GLint, GLsizei, const GLfloat *) = ::glUniform2fv; -void (* const glUniform2i)(GLint, GLint, GLint) = ::glUniform2i; -void (* const glUniform2iv)(GLint, GLsizei, const GLint *) = ::glUniform2iv; -void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat) = ::glUniform3f; -void (* const glUniform3fv)(GLint, GLsizei, const GLfloat *) = ::glUniform3fv; -void (* const glUniform3i)(GLint, GLint, GLint, GLint) = ::glUniform3i; -void (* const glUniform3iv)(GLint, GLsizei, const GLint *) = ::glUniform3iv; -void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glUniform4f; -void (* const glUniform4fv)(GLint, GLsizei, const GLfloat *) = ::glUniform4fv; -void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint) = ::glUniform4i; -void (* const glUniform4iv)(GLint, GLsizei, const GLint *) = ::glUniform4iv; -void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix2fv; -void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix3fv; -void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix4fv; -void (* const glUseProgram)(GLuint) = ::glUseProgram; -void (* const glValidateProgram)(GLuint) = ::glValidateProgram; -void (* const glVertexAttrib1f)(GLuint, GLfloat) = ::glVertexAttrib1f; -void (* const glVertexAttrib1fv)(GLuint, const GLfloat *) = ::glVertexAttrib1fv; -void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat) = ::glVertexAttrib2f; -void (* const glVertexAttrib2fv)(GLuint, const GLfloat *) = ::glVertexAttrib2fv; -void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib3f; -void (* const glVertexAttrib3fv)(GLuint, const GLfloat *) = ::glVertexAttrib3fv; -void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib4f; -void (* const glVertexAttrib4fv)(GLuint, const GLfloat *) = ::glVertexAttrib4fv; -void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *) = ::glVertexAttribPointer; -void (* const glViewport)(GLint, GLint, GLsizei, GLsizei) = ::glViewport; - -} // namespace platform -} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/pointf.cpp b/src/graphics/pointf.cpp deleted file mode 100644 index 2fc762d6e..000000000 --- a/src/graphics/pointf.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "pointf.hpp" - -namespace mbgl { -namespace android { - -jni::Local> PointF::New(jni::JNIEnv& env, float x, float y) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, x, y); -} - -mbgl::ScreenCoordinate PointF::getScreenCoordinate(jni::JNIEnv& env, const jni::Object& point) { - static auto& javaClass = jni::Class::Singleton(env); - static auto xField = javaClass.GetField(env, "x"); - static auto yField = javaClass.GetField(env, "y"); - return mbgl::ScreenCoordinate{point.Get(env, xField), point.Get(env, yField)}; -} - -void PointF::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/pointf.hpp b/src/graphics/pointf.hpp deleted file mode 100644 index 899468b8e..000000000 --- a/src/graphics/pointf.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class PointF : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "android/graphics/PointF"; }; - - static jni::Local> New(jni::JNIEnv&, float, float); - - static mbgl::ScreenCoordinate getScreenCoordinate(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/rectf.cpp b/src/graphics/rectf.cpp deleted file mode 100644 index 8f418da03..000000000 --- a/src/graphics/rectf.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "rectf.hpp" - -namespace mbgl { -namespace android { - -float RectF::getLeft(jni::JNIEnv& env, const jni::Object& rectf) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "left"); - return rectf.Get(env, field); -} - -float RectF::getTop(jni::JNIEnv& env, const jni::Object& rectf) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "top"); - return rectf.Get(env, field); -} - -float RectF::getRight(jni::JNIEnv& env, const jni::Object& rectf) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "right"); - return rectf.Get(env, field); -} - -float RectF::getBottom(jni::JNIEnv& env, const jni::Object& rectf) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "bottom"); - return rectf.Get(env, field); -} - -void RectF::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/graphics/rectf.hpp b/src/graphics/rectf.hpp deleted file mode 100644 index ba611f226..000000000 --- a/src/graphics/rectf.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class RectF : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "android/graphics/RectF"; }; - - static float getLeft(jni::JNIEnv&, const jni::Object&); - - static float getTop(jni::JNIEnv&, const jni::Object&); - - static float getRight(jni::JNIEnv&, const jni::Object&); - - static float getBottom(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_array.cpp b/src/gson/json_array.cpp deleted file mode 100644 index 8ffa658b7..000000000 --- a/src/gson/json_array.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "json_array.hpp" -#include "json_element.hpp" - -namespace mbgl { -namespace android { -namespace gson { - -jni::Local> JsonArray::New(jni::JNIEnv& env, const std::vector& values){ - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - static auto addMethod = javaClass.GetMethod)>(env, "add"); - - auto jsonArray = javaClass.New(env, constructor); - - for (const auto &v : values) { - jsonArray.Call(env, addMethod, JsonElement::New(env, v)); - } - - return jsonArray; -} - -std::vector JsonArray::convert(jni::JNIEnv& env, const jni::Object& jsonArray) { - std::vector values; - - if (jsonArray) { - static auto& javaClass = jni::Class::Singleton(env); - static auto getMethod = javaClass.GetMethod (jni::jint)>(env, "get"); - static auto sizeMethod = javaClass.GetMethod(env, "size"); - - int size = jsonArray.Call(env, sizeMethod); - values.reserve(uint(size)); - - for (int i = 0; i < size; i++) { - auto entry = jsonArray.Call(env, getMethod, i); - if (entry) { - values.push_back(JsonElement::convert(env, entry)); - } - } - } - - return values; -} - -void JsonArray::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_array.hpp b/src/gson/json_array.hpp deleted file mode 100644 index 24d5d3d29..000000000 --- a/src/gson/json_array.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "json_element.hpp" - -#include - -namespace mbgl { -namespace android { -namespace gson { - -class JsonArray { -public: - using SuperTag = JsonElement; - static constexpr auto Name() { return "com/google/gson/JsonArray"; }; - - static jni::Local> New(jni::JNIEnv&, const std::vector&); - static std::vector convert(JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_element.cpp b/src/gson/json_element.cpp deleted file mode 100644 index ba22304d0..000000000 --- a/src/gson/json_element.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "json_element.hpp" -#include "json_array.hpp" -#include "json_object.hpp" -#include "json_primitive.hpp" - -namespace mbgl { -namespace android { -namespace gson { - -jni::Local> JsonElement::New(jni::JNIEnv& env, const mbgl::Value& value) { - static auto& primitive = jni::Class::Singleton(env); - static auto stringConstructor = primitive.GetConstructor(env); - static auto numberConstructor = primitive.GetConstructor(env); - static auto booleanConstructor = primitive.GetConstructor(env); - - return value.match( - [&] (const mbgl::NullValue&) { - return jni::Local>(); - }, - [&] (const std::string& value) { - return primitive.New(env, stringConstructor, jni::Make(env, value)); - }, - [&] (const double value) { - return primitive.New(env, numberConstructor, jni::Box(env, value)); - }, - [&] (const int64_t value) { - return primitive.New(env, numberConstructor, jni::Box(env, value)); - }, - [&] (const uint64_t value) { - return primitive.New(env, numberConstructor, jni::Box(env, int64_t(value))); // TODO: should use BigInteger - }, - [&] (const bool value) { - return primitive.New(env, booleanConstructor, jni::Box(env, value ? jni::jni_true : jni::jni_false)); - }, - [&] (const std::vector& values) { - return JsonArray::New(env, values); - }, - [&] (const mbgl::PropertyMap& values) { - return JsonObject::New(env, values); - } - ); -} - -mbgl::Value JsonElement::convert(jni::JNIEnv &env, const jni::Object& jsonElement) { - if (!jsonElement) { - return mbgl::NullValue(); - } - - static auto& elementClass = jni::Class::Singleton(env); - static auto isJsonObject = elementClass.GetMethod(env, "isJsonObject"); - static auto isJsonArray = elementClass.GetMethod(env, "isJsonArray"); - static auto isJsonPrimitive = elementClass.GetMethod(env, "isJsonPrimitive"); - - static auto& primitiveClass = jni::Class::Singleton(env); - static auto isBoolean = primitiveClass.GetMethod(env, "isBoolean"); - static auto isString = primitiveClass.GetMethod(env, "isString"); - static auto isNumber = primitiveClass.GetMethod(env, "isNumber"); - static auto getAsBoolean = primitiveClass.GetMethod(env, "getAsBoolean"); - static auto getAsString = primitiveClass.GetMethod(env, "getAsString"); - static auto getAsDouble = primitiveClass.GetMethod(env, "getAsDouble"); - - if (jsonElement.Call(env, isJsonPrimitive)) { - auto primitive = jni::Cast(env, primitiveClass, jsonElement); - if (primitive.Call(env, isBoolean)) { - return bool(primitive.Call(env, getAsBoolean)); - } else if (primitive.Call(env, isNumber)) { - return primitive.Call(env, getAsDouble); - } else if (primitive.Call(env, isString)) { - return jni::Make(env, primitive.Call(env, getAsString)); - } else { - return mbgl::NullValue(); - } - } else if (jsonElement.Call(env, isJsonObject)) { - return JsonObject::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); - } else if (jsonElement.Call(env, isJsonArray)) { - return JsonArray::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); - } else { - return mbgl::NullValue(); - } -} - -void JsonElement::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_element.hpp b/src/gson/json_element.hpp deleted file mode 100644 index e3b8a0268..000000000 --- a/src/gson/json_element.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { -namespace gson { - -class JsonElement { -public: - using SuperTag = jni::ObjectTag; - static constexpr auto Name() { return "com/google/gson/JsonElement"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::Value&); - static mbgl::Value convert(JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_object.cpp b/src/gson/json_object.cpp deleted file mode 100644 index 10d244ee4..000000000 --- a/src/gson/json_object.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "json_object.hpp" - -#include "json_element.hpp" - -#include "../java/util.hpp" - -namespace mbgl { -namespace android { -namespace gson { - - -jni::Local> JsonObject::New(jni::JNIEnv& env, const mbgl::PropertyMap& values) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - static auto addMethod = javaClass.GetMethod)>(env, "add"); - - auto jsonObject = javaClass.New(env, constructor); - - for (auto &item : values) { - jsonObject.Call(env, addMethod, - jni::Make(env, item.first), - JsonElement::New(env, item.second)); - } - - return jsonObject; -} - -template // void (jni::String, jni::Object) -static void iterateEntrySet(jni::JNIEnv& env, const jni::Object& jsonObject, F callback) { - // Get Set> - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "entrySet"); - - auto entryArray = java::util::Set::toArray(env, jsonObject.Call(env, method)); - - size_t size = entryArray.Length(env); - for (size_t i = 0; i < size; i++) { - auto entry = entryArray.Get(env, i); - if (entry) { - callback( - java::util::Map::Entry::getKey(env, entry), - java::util::Map::Entry::getValue(env, entry)); - } - } -} - -mbgl::PropertyMap JsonObject::convert(jni::JNIEnv& env, const jni::Object& jsonObject) { - mbgl::PropertyMap map; - - if (jsonObject) { - iterateEntrySet(env, jsonObject, [&map, &env](const jni::String& jId, const jni::Object& jsonElement) { - map[jni::Make(env, jId)] = JsonElement::convert(env, jsonElement); - }); - } - - return map; -} - -void JsonObject::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_object.hpp b/src/gson/json_object.hpp deleted file mode 100644 index b8916f8ae..000000000 --- a/src/gson/json_object.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "json_element.hpp" - -#include - -namespace mbgl { -namespace android { -namespace gson { - -class JsonObject { -public: - using SuperTag = JsonElement; - static constexpr auto Name() { return "com/google/gson/JsonObject"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::PropertyMap&); - static mbgl::PropertyMap convert(JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_primitive.cpp b/src/gson/json_primitive.cpp deleted file mode 100644 index 79d6b0761..000000000 --- a/src/gson/json_primitive.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "json_primitive.hpp" - -namespace mbgl { -namespace android { -namespace gson { - -void JsonPrimitive::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/gson/json_primitive.hpp b/src/gson/json_primitive.hpp deleted file mode 100644 index 36f138d90..000000000 --- a/src/gson/json_primitive.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "json_element.hpp" - -#include - -namespace mbgl { -namespace android { -namespace gson { - -class JsonPrimitive { -public: - using SuperTag = JsonElement; - static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; }; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace gson -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/http_file_source.cpp b/src/http_file_source.cpp deleted file mode 100644 index 7066918fe..000000000 --- a/src/http_file_source.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "attach_env.hpp" - -namespace mbgl { - -class HTTPFileSource::Impl { -public: - android::UniqueEnv env { android::AttachEnv() }; -}; - -class HTTPRequest : public AsyncRequest { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/NativeHttpRequest"; }; - - HTTPRequest(jni::JNIEnv&, const Resource&, FileSource::Callback); - ~HTTPRequest(); - - void onFailure(jni::JNIEnv&, int type, const jni::String& message); - void onResponse(jni::JNIEnv&, int code, - const jni::String& etag, const jni::String& modified, - const jni::String& cacheControl, const jni::String& expires, - const jni::String& retryAfter, const jni::String& xRateLimitReset, - const jni::Array& body); - - jni::Global> javaRequest; - -private: - Resource resource; - FileSource::Callback callback; - Response response; - - util::AsyncTask async { [this] { - // Calling `callback` may result in deleting `this`. Copy data to temporaries first. - auto callback_ = callback; - auto response_ = response; - callback_(response_); - } }; - - static const int connectionError = 0; - static const int temporaryError = 1; - static const int permanentError = 2; -}; - -namespace android { - -void RegisterNativeHTTPRequest(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - jni::RegisterNativePeer(env, javaClass, "nativePtr", - METHOD(&HTTPRequest::onFailure, "nativeOnFailure"), - METHOD(&HTTPRequest::onResponse, "nativeOnResponse")); -} - -} // namespace android - -HTTPRequest::HTTPRequest(jni::JNIEnv& env, const Resource& resource_, FileSource::Callback callback_) - : resource(resource_), - callback(callback_) { - std::string etagStr; - std::string modifiedStr; - - if (resource.priorEtag) { - etagStr = *resource.priorEtag; - } else if (resource.priorModified) { - modifiedStr = util::rfc1123(*resource.priorModified); - } - - jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 10); - - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = - javaClass.GetConstructor(env); - - javaRequest = jni::NewGlobal(env, - javaClass.New(env, constructor, - reinterpret_cast(this), - jni::Make(env, resource.url), - jni::Make(env, etagStr), - jni::Make(env, modifiedStr), - (jboolean) (resource_.usage == Resource::Usage::Offline) - ) - ); -} - -HTTPRequest::~HTTPRequest() { - android::UniqueEnv env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*env); - static auto cancel = javaClass.GetMethod(*env, "cancel"); - - javaRequest.Call(*env, cancel); -} - -void HTTPRequest::onResponse(jni::JNIEnv& env, int code, - const jni::String& etag, const jni::String& modified, - const jni::String& cacheControl, const jni::String& expires, - const jni::String& jRetryAfter, const jni::String& jXRateLimitReset, - const jni::Array& body) { - - using Error = Response::Error; - - if (etag) { - response.etag = jni::Make(env, etag); - } - - if (modified) { - response.modified = util::parseTimestamp(jni::Make(env, modified).c_str()); - } - - if (cacheControl) { - const auto cc = http::CacheControl::parse(jni::Make(env, cacheControl).c_str()); - response.expires = cc.toTimePoint(); - response.mustRevalidate = cc.mustRevalidate; - } - - if (expires) { - response.expires = util::parseTimestamp(jni::Make(env, expires).c_str()); - } - - if (code == 200) { - if (body) { - auto data = std::make_shared(body.Length(env), char()); - jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast(&(*data)[0])); - response.data = data; - } else { - response.data = std::make_shared(); - } - } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) { - response.noContent = true; - } else if (code == 304) { - response.notModified = true; - } else if (code == 404) { - response.error = std::make_unique(Error::Reason::NotFound, "HTTP status code 404"); - } else if (code == 429) { - optional retryAfter; - optional xRateLimitReset; - if (jRetryAfter) { - retryAfter = jni::Make(env, jRetryAfter); - } - if (jXRateLimitReset) { - xRateLimitReset = jni::Make(env, jXRateLimitReset); - } - response.error = std::make_unique(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset)); - } else if (code >= 500 && code < 600) { - response.error = std::make_unique(Error::Reason::Server, std::string{ "HTTP status code " } + util::toString(code)); - } else { - response.error = std::make_unique(Error::Reason::Other, std::string{ "HTTP status code " } + util::toString(code)); - } - - async.send(); -} - -void HTTPRequest::onFailure(jni::JNIEnv& env, int type, const jni::String& message) { - std::string messageStr = jni::Make(env, message); - - using Error = Response::Error; - - switch (type) { - case connectionError: - response.error = std::make_unique(Error::Reason::Connection, messageStr); - break; - case temporaryError: - response.error = std::make_unique(Error::Reason::Server, messageStr); - break; - default: - response.error = std::make_unique(Error::Reason::Other, messageStr); - } - - async.send(); -} - -HTTPFileSource::HTTPFileSource() - : impl(std::make_unique()) { -} - -HTTPFileSource::~HTTPFileSource() = default; - -std::unique_ptr HTTPFileSource::request(const Resource& resource, Callback callback) { - return std::make_unique(*impl->env, resource, callback); -} - -} // namespace mbgl diff --git a/src/i18n/collator.cpp b/src/i18n/collator.cpp deleted file mode 100644 index b3dd8e21b..000000000 --- a/src/i18n/collator.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include - -#include - -#include "../attach_env.hpp" -#include "collator_jni.hpp" - -namespace mbgl { -namespace android { - -void Collator::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setStrength"); - collator.Call(env, method, strength); -} - -jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "compare"); - return collator.Call(env, method, lhs, rhs); -} - -void StringUtils::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod(env, "unaccent"); - return javaClass.Call(env, method, value); -} - -void Locale::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -/* -We would prefer to use for/toLanguageTag, but they're only available in API level 21+ - -jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { - using Signature = jni::Object(jni::String); - auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); - return javaClass.Call(env, method, languageTag); -} - -jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { - using Signature = jni::String(); - auto static method = javaClass.GetMethod(env, "toLanguageTag"); - return locale.Call(env, method); -} -*/ - -jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getLanguage"); - return locale.Call(env, method); -} - -jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getCountry"); - return locale.Call(env, method); -} - -jni::Local> Locale::getDefault(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); - return javaClass.Call(env, method); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language, region); -} - -} // namespace android - -namespace platform { - -class Collator::Impl { -public: - Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) - : caseSensitive(caseSensitive_) - , diacriticSensitive(diacriticSensitive_) - , env(android::AttachEnv()) - { - LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, - android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); - if (!diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); - } else if (diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); - } else if (caseSensitive) { - // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator - // and a fallback implementation of diacritic-insensitivity. - android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); - } - } - - bool operator==(const Impl& other) const { - return caseSensitive == other.caseSensitive && - diacriticSensitive == other.diacriticSensitive && - resolvedLocale() == other.resolvedLocale(); - } - - int compare(const std::string& lhs, const std::string& rhs) const { - bool useUnaccent = !diacriticSensitive && caseSensitive; - // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation - // order, so we have to compromise here. We use Android's case-sensitive Collator - // against strings that have been "unaccented" using non-locale-aware nunicode logic. - // Because of the difference in locale-awareness, this means turning on case-sensitivity - // can _potentially_ change compare results for strings that don't actually have any case - // differences. - jni::Local jlhs = useUnaccent - ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) - : jni::Make(*env, lhs); - jni::Local jrhs = useUnaccent - ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) - : jni::Make(*env, rhs); - - jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); - - return result; - } - - std::string resolvedLocale() const { - std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); - std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); - - optional resultLanguage; - if (!language.empty()) resultLanguage = language; - optional resultRegion; - if (!region.empty()) resultRegion = region; - - return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); - } - -private: - bool caseSensitive; - bool diacriticSensitive; - - android::UniqueEnv env; - jni::Global> collator; - jni::Global> locale; -}; - - -Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) - : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) -{} - -bool Collator::operator==(const Collator& other) const { - return *impl == *(other.impl); -} - -int Collator::compare(const std::string& lhs, const std::string& rhs) const { - return impl->compare(lhs, rhs); -} - -std::string Collator::resolvedLocale() const { - return impl->resolvedLocale(); -} - -} // namespace platform -} // namespace mbgl diff --git a/src/i18n/collator_jni.hpp b/src/i18n/collator_jni.hpp deleted file mode 100644 index 612f9b49f..000000000 --- a/src/i18n/collator_jni.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include - -/* - android::Collator and android::Locale are - the JNI wrappers of - java/text/Collator and java/util/Locale - - mbgl::Collator is the portable interface - Both implementations are in collator.cpp - */ - -namespace mbgl { -namespace android { - -class Locale { -public: - static constexpr auto Name() { return "java/util/Locale"; }; - - /* Requires API level 21+ in order to support script/variant - static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); - static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); - */ - static jni::Local> getDefault(jni::JNIEnv&); - static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); - static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); - - static jni::Local> New(jni::JNIEnv&, const jni::String&); - static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -class Collator { -public: - static constexpr auto Name() { return "java/text/Collator"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - - static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); - - static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - - -class StringUtils { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; - - static jni::Local unaccent(jni::JNIEnv&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/i18n/number_format.cpp b/src/i18n/number_format.cpp deleted file mode 100644 index c8e0b7056..000000000 --- a/src/i18n/number_format.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include - -#include - -#include "../attach_env.hpp" -#include "number_format_jni.hpp" - -namespace mbgl { -namespace android { - -void NumberFormat::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "format"); - return nf.Call(env, method, number); -} - -void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); - return nf.Call(env, method, value); -} - -void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); - return nf.Call(env, method, value); -} - -} // namespace android - -namespace platform { - -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - auto env{ android::AttachEnv() }; - - jni::Global> locale; - LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - - jni::Global> formatter; - if (currency.empty()) { - formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); - android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); - android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); - } else { - formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); - } - - auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); - return jni::Make(*env, result); -} - -} // namespace platform -} // namespace mbgl diff --git a/src/i18n/number_format_jni.hpp b/src/i18n/number_format_jni.hpp deleted file mode 100644 index 172003892..000000000 --- a/src/i18n/number_format_jni.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "collator_jni.hpp" - -/* - android::NumberFormat is the JNI wrapper - of java/text/NumberFormat. - */ - -namespace mbgl { -namespace android { - -class NumberFormat { -public: - static constexpr auto Name() { return "java/text/NumberFormat"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); - static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/image.cpp b/src/image.cpp deleted file mode 100644 index 31515ff16..000000000 --- a/src/image.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -#include - -#include "attach_env.hpp" -#include "bitmap_factory.hpp" - -namespace mbgl { - -PremultipliedImage decodeImage(const std::string& string) { - auto env{ android::AttachEnv() }; - - auto array = jni::Array::New(*env, string.size()); - jni::SetArrayRegion(*env, *array, 0, string.size(), - reinterpret_cast(string.data())); - - return android::Bitmap::GetImage(*env, android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size())); -} - -} // namespace mbgl diff --git a/src/java/util.cpp b/src/java/util.cpp deleted file mode 100644 index b3aebb36c..000000000 --- a/src/java/util.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "util.hpp" - -namespace mbgl { -namespace android { -namespace java { -namespace util { - -void registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); -} - -} // namespace util -} // namespace java -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/java/util.hpp b/src/java/util.hpp deleted file mode 100644 index 9b0c01459..000000000 --- a/src/java/util.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { -namespace java { -namespace util { - -class List : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "java/util/List"; }; - - template - static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { - static auto& javaClass = jni::Class::Singleton(env); - static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); - - return jni::Local>>(env, list.Call(env, toArray).release()); - }; -}; - -class Arrays : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "java/util/Arrays"; }; - - template - static jni::Local> asList(jni::JNIEnv& env, const jni::Array>& array) { - static auto& javaClass = jni::Class::Singleton(env); - static auto asList = javaClass.GetStaticMethod(jni::Array>)>(env, "asList"); - - auto typeErasedArray = jni::Local>>(env, jni::NewLocal(env, array).release()); - return javaClass.Call(env, asList, typeErasedArray); - } -}; - -class Set : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "java/util/Set"; }; - - template - static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { - static auto& javaClass = jni::Class::Singleton(env); - static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); - - return jni::Local>>(env, list.Call(env, toArray).release()); - }; -}; - -class Map : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "java/util/Map"; }; - - class Entry : private mbgl::util::noncopyable { - public: - static constexpr auto Name() { return "java/util/Map$Entry"; }; - - template - static jni::Local> getKey(jni::JNIEnv& env, const jni::Object& entry) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "getKey"); - return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); - } - - template - static jni::Local> getValue(jni::JNIEnv& env, const jni::Object& entry) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod ()>(env, "getValue"); - return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); - } - }; -}; - -void registerNative(jni::JNIEnv&); - -} // namespace util -} // namespace java -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/java_types.cpp b/src/java_types.cpp deleted file mode 100644 index 7a1ba93a5..000000000 --- a/src/java_types.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "java_types.hpp" - -namespace mbgl { -namespace android { -namespace java { - - jni::jclass* ObjectArray::jclass; - - jni::jclass* String::jclass; - - jni::jclass* Boolean::jclass; - jni::jmethodID* Boolean::booleanValueMethodId; - - jni::jclass* Number::jclass; - jni::jmethodID* Number::floatValueMethodId; - jni::jmethodID* Number::doubleValueMethodId; - jni::jmethodID* Number::longValueMethodId; - - jni::jclass* Map::jclass; - jni::jmethodID* Map::getMethodId; - jni::jmethodID* Map::keySetMethodId; - - jni::jclass* Set::jclass; - jni::jmethodID* Set::toArrayMethodId; - - void registerNatives(JNIEnv& env) { - ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release(); - - String::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); - - Boolean::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); - Boolean::booleanValueMethodId = &jni::GetMethodID(env, *Boolean::jclass, "booleanValue", "()Z"); - - Number::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Number")).release(); - Number::floatValueMethodId = &jni::GetMethodID(env, *Number::jclass, "floatValue", "()F"); - Number::doubleValueMethodId = &jni::GetMethodID(env, *Number::jclass, "doubleValue", "()D"); - Number::longValueMethodId = &jni::GetMethodID(env, *Number::jclass, "longValue", "()J"); - - Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release(); - Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); - Map::keySetMethodId = &jni::GetMethodID(env, *Map::jclass, "keySet", "()Ljava/util/Set;"); - - Set::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Set")).release(); - Set::toArrayMethodId = &jni::GetMethodID(env, *Set::jclass, "toArray", "()[Ljava/lang/Object;"); - } - -} -} -} diff --git a/src/java_types.hpp b/src/java_types.hpp deleted file mode 100644 index c7c93ce71..000000000 --- a/src/java_types.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -namespace mbgl { -namespace android { -namespace java { - - struct ObjectArray { - static jni::jclass* jclass; - }; - - struct String { - static jni::jclass* jclass; - }; - - struct Boolean { - static jni::jclass* jclass; - static jni::jmethodID* booleanValueMethodId; - }; - - struct Number { - static jni::jclass* jclass; - static jni::jmethodID* floatValueMethodId; - static jni::jmethodID* doubleValueMethodId; - static jni::jmethodID* longValueMethodId; - }; - - struct Map { - static jni::jclass* jclass; - static jni::jmethodID* getMethodId; - static jni::jmethodID* keySetMethodId; - }; - - struct Set { - static jni::jclass* jclass; - static jni::jmethodID* toArrayMethodId; - }; - - void registerNatives(JNIEnv&); -} -} -} diff --git a/src/jni.cpp b/src/jni.cpp deleted file mode 100755 index 189ec29dc..000000000 --- a/src/jni.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "jni.hpp" - -#include - -namespace mbgl { -namespace android { - -JavaVM* theJVM; - -//TODO: remove -bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) { - assert(vm != nullptr); - assert(env != nullptr); - - JavaVMAttachArgs args = {JNI_VERSION_1_2, threadName.c_str(), NULL}; - - jint ret; - *env = nullptr; - bool detach = false; - ret = vm->GetEnv(reinterpret_cast(env), JNI_VERSION_1_6); - if (ret != JNI_OK) { - if (ret != JNI_EDETACHED) { - mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret); - throw std::runtime_error("GetEnv() failed"); - } else { - ret = vm->AttachCurrentThread(env, &args); - if (ret != JNI_OK) { - mbgl::Log::Error(mbgl::Event::JNI, "AttachCurrentThread() failed with %i", ret); - throw std::runtime_error("AttachCurrentThread() failed"); - } - detach = true; - } - } - - return detach; -} - -//TODO: remove -void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) { - if (detach) { - assert(vm != nullptr); - assert(env != nullptr); - - jint ret; - if ((ret = vm->DetachCurrentThread()) != JNI_OK) { - mbgl::Log::Error(mbgl::Event::JNI, "DetachCurrentThread() failed with %i", ret); - throw std::runtime_error("DetachCurrentThread() failed"); - } - } - *env = nullptr; -} - -} // namespace android -} // namespace mbgl diff --git a/src/jni.hpp b/src/jni.hpp deleted file mode 100644 index 9bfe2ce5b..000000000 --- a/src/jni.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include -#include - -typedef struct _jmethodID* jmethodID; -typedef struct _JavaVM JavaVM; -typedef struct _JNIEnv JNIEnv; - -namespace mbgl { -namespace android { - -extern JavaVM* theJVM; - -extern std::string cachePath; -extern std::string dataPath; - -bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName); -void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach); - -} // namespace android -} // namespace mbgl diff --git a/src/jni_native.cpp b/src/jni_native.cpp deleted file mode 100644 index bcbdfcf48..000000000 --- a/src/jni_native.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "jni_native.hpp" - -#include "annotation/marker.hpp" -#include "annotation/polygon.hpp" -#include "annotation/polyline.hpp" -#include "bitmap.hpp" -#include "bitmap_factory.hpp" -#include "connectivity_listener.hpp" -#include "conversion/collection.hpp" -#include "conversion/conversion.hpp" -#include "file_source.hpp" -#include "geojson/feature.hpp" -#include "geojson/feature_collection.hpp" -#include "geojson/geometry.hpp" -#include "geojson/geometry_collection.hpp" -#include "geojson/line_string.hpp" -#include "geojson/multi_line_string.hpp" -#include "geojson/multi_point.hpp" -#include "geojson/multi_polygon.hpp" -#include "geojson/point.hpp" -#include "geojson/polygon.hpp" -#include "geometry/lat_lng.hpp" -#include "geometry/lat_lng_bounds.hpp" -#include "geometry/lat_lng_quad.hpp" -#include "geometry/projected_meters.hpp" -#include "graphics/pointf.hpp" -#include "graphics/rectf.hpp" -#include "gson/json_array.hpp" -#include "gson/json_element.hpp" -#include "gson/json_object.hpp" -#include "gson/json_primitive.hpp" -#include "java_types.hpp" -#include "map_renderer.hpp" -#include "map_renderer_runnable.hpp" -#include "mapbox.hpp" -#include "native_map_view.hpp" -#ifndef MBGL_MODULE_OFFLINE_DISABLE -#include "offline/offline_manager.hpp" -#include "offline/offline_region.hpp" -#include "offline/offline_region_definition.hpp" -#include "offline/offline_region_error.hpp" -#include "offline/offline_region_status.hpp" -#endif -#include "style/transition_options.hpp" -#include "style/layers/layer_manager.hpp" -#include "style/sources/source.hpp" -#include "style/light.hpp" -#include "style/formatted.hpp" -#include "style/formatted_section.hpp" -#ifndef MBGL_MODULE_SNAPSHOT_DISABLE -#include "snapshotter/map_snapshotter.hpp" -#include "snapshotter/map_snapshot.hpp" -#endif -#include "i18n/collator_jni.hpp" -#include "i18n/number_format_jni.hpp" -#include "logger.hpp" -#include "text/local_glyph_rasterizer_jni.hpp" - -namespace mbgl { -namespace android { - -void RegisterNativeHTTPRequest(JNIEnv&); - -void registerNatives(JavaVM *vm) { - theJVM = vm; - - jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6); - - // For the DefaultFileSource - static mbgl::util::RunLoop mainRunLoop; - FileSource::registerNative(env); - - // Basic types - java::registerNatives(env); - java::util::registerNative(env); - PointF::registerNative(env); - RectF::registerNative(env); - - // GeoJSON - geojson::Feature::registerNative(env); - geojson::FeatureCollection::registerNative(env); - geojson::Geometry::registerNative(env); - geojson::GeometryCollection::registerNative(env); - geojson::LineString::registerNative(env); - geojson::MultiLineString::registerNative(env); - geojson::MultiPoint::registerNative(env); - geojson::MultiPolygon::registerNative(env); - geojson::Point::registerNative(env); - geojson::Polygon::registerNative(env); - - // Geometry - LatLng::registerNative(env); - LatLngBounds::registerNative(env); - LatLngQuad::registerNative(env); - ProjectedMeters::registerNative(env); - - // GSon - gson::JsonArray::registerNative(env); - gson::JsonElement::registerNative(env); - gson::JsonObject::registerNative(env); - gson::JsonPrimitive::registerNative(env); - - //Annotation - Marker::registerNative(env); - Polygon::registerNative(env); - Polyline::registerNative(env); - - // Map - MapRenderer::registerNative(env); - MapRendererRunnable::registerNative(env); - NativeMapView::registerNative(env); - - // Http - RegisterNativeHTTPRequest(env); - - // Bitmap - Bitmap::registerNative(env); - BitmapFactory::registerNative(env); - - // Style - TransitionOptions::registerNative(env); - LayerManagerAndroid::get()->registerNative(env); - Source::registerNative(env); - Light::registerNative(env); - Position::registerNative(env); - Formatted::registerNative(env); - FormattedSection::registerNative(env); - - // Map - CameraPosition::registerNative(env); - Image::registerNative(env); - - // Connectivity - ConnectivityListener::registerNative(env); - - // Offline -#ifndef MBGL_MODULE_OFFLINE_DISABLE - OfflineManager::registerNative(env); - OfflineRegion::registerNative(env); - OfflineRegionDefinition::registerNative(env); - OfflineTilePyramidRegionDefinition::registerNative(env); - OfflineGeometryRegionDefinition::registerNative(env); - OfflineRegionError::registerNative(env); - OfflineRegionStatus::registerNative(env); -#endif - - // Snapshotter -#ifndef MBGL_MODULE_SNAPSHOT_DISABLE - MapSnapshotter::registerNative(env); - MapSnapshot::registerNative(env); -#endif - - // text - LocalGlyphRasterizer::registerNative(env); - Locale::registerNative(env); - Collator::registerNative(env); - StringUtils::registerNative(env); - NumberFormat::registerNative(env); - - // Logger - Logger::registerNative(env); - - // AssetManager - Mapbox::registerNative(env); -} - -} // namespace android -} // namespace mbgl diff --git a/src/jni_native.hpp b/src/jni_native.hpp deleted file mode 100644 index 1cc9a7e81..000000000 --- a/src/jni_native.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -#include "jni.hpp" - -namespace mbgl { -namespace android { - -MBGL_EXPORT void registerNatives(JavaVM* vm); - -} // namespace android -} // namespace mbgl diff --git a/src/logger.cpp b/src/logger.cpp deleted file mode 100644 index f5d78cc83..000000000 --- a/src/logger.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "logger.hpp" -#include "java_types.hpp" - -namespace mbgl { -namespace android { - -void Logger::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -void Logger::log(jni::JNIEnv& env, EventSeverity severity, const std::string &msg) { - static auto& _class = jni::Class::Singleton(env); - - auto tag = jni::Make(env, "Mbgl"); - auto message = jni::Make(env, msg); - using Signature = void(jni::String, jni::String); - - if (severity == EventSeverity::Debug) { - auto static debug = _class.GetStaticMethod(env, "d"); - _class.Call(env, debug, tag, message); - } else if (severity == EventSeverity::Info) { - auto static info = _class.GetStaticMethod(env, "i"); - _class.Call(env, info, tag, message); - } else if(severity == EventSeverity::Warning) { - auto static warning = _class.GetStaticMethod(env, "w"); - _class.Call(env, warning, tag, message); - } else { - auto static error = _class.GetStaticMethod(env, "e"); - _class.Call(env, error, tag, message); - } -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/logger.hpp b/src/logger.hpp deleted file mode 100644 index 7481ecb26..000000000 --- a/src/logger.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include "bitmap.hpp" - -namespace mbgl { -namespace android { - -class Logger { -public: - static constexpr auto Name() { - return "com/mapbox/mapboxsdk/log/Logger"; - }; - static void registerNative(jni::JNIEnv&); - - static void log(jni::JNIEnv&, EventSeverity severity, const std::string &msg); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/logging_android.cpp b/src/logging_android.cpp deleted file mode 100644 index 130136728..000000000 --- a/src/logging_android.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -#include "logger.hpp" -#include "attach_env.hpp" - -namespace mbgl { - -void Log::platformRecord(EventSeverity severity, const std::string &msg) { - auto env{ android::AttachEnv() }; - android::Logger::log(*env, severity, msg); -} - -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 9b5c6c197..000000000 --- a/src/main.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "jni.hpp" -#include "jni_native.hpp" -#include - -extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { - assert(vm != nullptr); - mbgl::android::registerNatives(vm); - return JNI_VERSION_1_6; -} diff --git a/src/map/camera_position.cpp b/src/map/camera_position.cpp deleted file mode 100644 index 4266b64fd..000000000 --- a/src/map/camera_position.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "camera_position.hpp" -#include "../geometry/lat_lng.hpp" - -namespace mbgl { -namespace android { - -jni::Local> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options, float pixelRatio) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor, double, double, double, jni::Array>(env); - - // wrap LatLng values coming from core - auto center = options.center.value(); - center.wrap(); - - // convert bearing, measured in radians counterclockwise from true north. - // Wrapped to [−π rad, π rad). Android binding from 0 to 360 degrees - double bearing_degrees = options.bearing.value_or(0); - while (bearing_degrees > 360) { - bearing_degrees -= 360; - } - while (bearing_degrees < 0) { - bearing_degrees += 360; - } - - // convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60 - double tilt_degrees = options.pitch.value_or(0); - - std::vector paddingVect; - auto insets = options.padding.value_or(EdgeInsets {0, 0, 0, 0}); - auto padding = jni::Array::New(env, 4); - paddingVect.push_back(insets.left() * pixelRatio); - paddingVect.push_back(insets.top() * pixelRatio); - paddingVect.push_back(insets.right() * pixelRatio); - paddingVect.push_back(insets.bottom() * pixelRatio); - padding.SetRegion>(env, 0, paddingVect); - - return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees, padding); -} - -mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object& position, float pixelRatio) { - static auto& javaClass = jni::Class::Singleton(env); - static auto bearing = javaClass.GetField(env, "bearing"); - static auto target = javaClass.GetField>(env, "target"); - static auto tilt = javaClass.GetField(env, "tilt"); - static auto zoom = javaClass.GetField(env, "zoom"); - static auto paddingField = javaClass.GetField>(env, "padding"); - - auto padding = position.Get(env, paddingField); - auto center = LatLng::getLatLng(env, position.Get(env, target)); - - return mbgl::CameraOptions{center, - padding && padding.Length(env) == 4 ? EdgeInsets{padding.Get(env, 1) * pixelRatio, - padding.Get(env, 0) * pixelRatio, - padding.Get(env, 3) * pixelRatio, - padding.Get(env, 2) * pixelRatio} - : (EdgeInsets){}, - {}, - position.Get(env, zoom), - position.Get(env, bearing), - position.Get(env, tilt)}; -} - -void CameraPosition::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mb - diff --git a/src/map/camera_position.hpp b/src/map/camera_position.hpp deleted file mode 100644 index b677f04ea..000000000 --- a/src/map/camera_position.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace mbgl { -namespace android { - -class CameraPosition : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; }; - - static jni::Local> New(jni::JNIEnv&, mbgl::CameraOptions, float pixelRatio); - - static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object&, float pixelRatio); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/map/image.cpp b/src/map/image.cpp deleted file mode 100644 index a91cc938e..000000000 --- a/src/map/image.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include "image.hpp" - -namespace mbgl { -namespace android { - -mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& image) { - static auto& javaClass = jni::Class::Singleton(env); - static auto widthField = javaClass.GetField(env, "width"); - static auto heightField = javaClass.GetField(env, "height"); - static auto pixelRatioField = javaClass.GetField(env, "pixelRatio"); - static auto bufferField = javaClass.GetField>(env, "buffer"); - static auto nameField = javaClass.GetField(env, "name"); - static auto sdfField = javaClass.GetField(env, "sdf"); - - auto height = image.Get(env, heightField); - auto width = image.Get(env, widthField); - auto pixelRatio = image.Get(env, pixelRatioField); - auto pixels = image.Get(env, bufferField); - auto name = jni::Make(env, image.Get(env, nameField)); - auto sdf = (bool) image.Get(env, sdfField); - - jni::NullCheck(env, pixels.get()); - std::size_t size = pixels.Length(env); - - mbgl::PremultipliedImage premultipliedImage({ static_cast(width), static_cast(height) }); - if (premultipliedImage.bytes() != uint32_t(size)) { - throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); - } - - jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); - return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf}; -} - -void Image::registerNative(jni::JNIEnv &env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mb diff --git a/src/map/image.hpp b/src/map/image.hpp deleted file mode 100644 index 7549bc646..000000000 --- a/src/map/image.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace mbgl { -namespace android { - -class Image : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/Image"; }; - - static mbgl::style::Image getImage(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/map_renderer.cpp b/src/map_renderer.cpp deleted file mode 100644 index 0c0e907f1..000000000 --- a/src/map_renderer.cpp +++ /dev/null @@ -1,236 +0,0 @@ -#include "map_renderer.hpp" - -#include -#include -#include - -#include - -#include "attach_env.hpp" -#include "android_renderer_backend.hpp" -#include "map_renderer_runnable.hpp" - -namespace mbgl { -namespace android { - -MapRenderer::MapRenderer(jni::JNIEnv& _env, - const jni::Object& obj, - jni::jfloat pixelRatio_, - const jni::String& localIdeographFontFamily_) - : javaPeer(_env, obj) - , pixelRatio(pixelRatio_) - , localIdeographFontFamily(localIdeographFontFamily_ ? jni::Make(_env, localIdeographFontFamily_) : optional{}) - , mailbox(std::make_shared(*this)) { -} - -MapRenderer::~MapRenderer() = default; - -void MapRenderer::reset() { - destroyed = true; - - if (renderer) { - // Make sure to destroy the renderer on the GL Thread - auto self = ActorRef(*this, mailbox); - self.ask(&MapRenderer::resetRenderer).wait(); - } - - // Lock to make sure there is no concurrent initialisation on the gl thread - std::lock_guard lock(initialisationMutex); - rendererObserver.reset(); -} - -ActorRef MapRenderer::actor() const { - return *rendererRef; -} - -void MapRenderer::schedule(std::function scheduled) { - // Create a runnable - android::UniqueEnv _env = android::AttachEnv(); - auto runnable = std::make_unique(*_env, std::move(scheduled)); - - // Obtain ownership of the peer (gets transferred to the MapRenderer on the JVM for later GC) - auto peer = runnable->peer(); - - // Queue the event on the Java Peer - static auto& javaClass = jni::Class::Singleton(*_env); - static auto queueEvent = javaClass.GetMethod)>(*_env, "queueEvent"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, queueEvent, peer); - } - - // Release the c++ peer as it will be destroyed on GC of the Java Peer - runnable.release(); -} - -void MapRenderer::requestRender() { - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onInvalidate = javaClass.GetMethod(*_env, "requestRender"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onInvalidate); - } -} - -void MapRenderer::update(std::shared_ptr params) { - // Lock on the parameters - std::lock_guard lock(updateMutex); - updateParameters = std::move(params); -} - -void MapRenderer::setObserver(std::shared_ptr _rendererObserver) { - // Lock as the initialization can come from the main thread or the GL thread first - std::lock_guard lock(initialisationMutex); - - rendererObserver = std::move(_rendererObserver); - - // Set the new observer on the Renderer implementation - if (renderer) { - renderer->setObserver(rendererObserver.get()); - } -} - -void MapRenderer::requestSnapshot(SnapshotCallback callback) { - auto self = ActorRef(*this, mailbox); - self.invoke( - &MapRenderer::scheduleSnapshot, - std::make_unique([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) { - runloop->invoke([callback=std::move(callback), image=std::move(image), renderer=std::move(this)]() mutable { - if (renderer && !renderer->destroyed) { - callback(std::move(image)); - } - }); - snapshotCallback.reset(); - }) - ); -} - -// Called on OpenGL thread // - -void MapRenderer::resetRenderer() { - renderer.reset(); -} - -void MapRenderer::scheduleSnapshot(std::unique_ptr callback) { - snapshotCallback = std::move(callback); - requestRender(); -} - -void MapRenderer::render(JNIEnv&) { - assert (renderer); - - std::shared_ptr params; - { - // Lock on the parameters - std::unique_lock lock(updateMutex); - if (!updateParameters) return; - - // Hold on to the update parameters during render - params = updateParameters; - } - - // Activate the backend - gfx::BackendScope backendGuard { *backend }; - - // Ensure that the "current" scheduler on the render thread is - // this scheduler. - Scheduler::SetCurrent(this); - - if (framebufferSizeChanged) { - backend->updateViewPort(); - framebufferSizeChanged = false; - } - - renderer->render(*params); - - // Deliver the snapshot if requested - if (snapshotCallback) { - snapshotCallback->operator()(backend->readFramebuffer()); - snapshotCallback.reset(); - } -} - -void MapRenderer::onSurfaceCreated(JNIEnv&) { - // Lock as the initialization can come from the main thread or the GL thread first - std::lock_guard lock(initialisationMutex); - - // The GL context is already active if get a new surface. - gfx::BackendScope backendGuard { *backend, gfx::BackendScope::ScopeType::Implicit }; - - // The android system will have already destroyed the underlying - // GL resources if this is not the first initialization and an - // attempt to clean them up will fail - if (backend) backend->markContextLost(); - if (renderer) renderer->markContextLost(); - - // Reset in opposite order - renderer.reset(); - backend.reset(); - - // Create the new backend and renderer - backend = std::make_unique(); - renderer = std::make_unique(*backend, pixelRatio, localIdeographFontFamily); - rendererRef = std::make_unique>(*renderer, mailbox); - - // Set the observer on the new Renderer implementation - if (rendererObserver) { - renderer->setObserver(rendererObserver.get()); - } -} - -void MapRenderer::onSurfaceChanged(JNIEnv& env, jint width, jint height) { - if (!renderer) { - // In case the surface has been destroyed (due to app back-grounding) - onSurfaceCreated(env); - } - - backend->resizeFramebuffer(width, height); - framebufferSizeChanged = true; - requestRender(); -} - -void MapRenderer::onRendererReset(JNIEnv&) { - // Make sure to destroy the renderer on the GL Thread - auto self = ActorRef(*this, mailbox); - self.ask(&MapRenderer::resetRenderer).wait(); -} - -// needs to be called on GL thread -void MapRenderer::onSurfaceDestroyed(JNIEnv&) { - resetRenderer(); -} - -// Static methods // - -void MapRenderer::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - -#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - jni::MakePeer&, jni::jfloat, const jni::String&>, - "nativeInitialize", "finalize", - METHOD(&MapRenderer::render, "nativeRender"), - METHOD(&MapRenderer::onRendererReset, "nativeReset"), - METHOD(&MapRenderer::onSurfaceCreated, - "nativeOnSurfaceCreated"), - METHOD(&MapRenderer::onSurfaceChanged, - "nativeOnSurfaceChanged"), - METHOD(&MapRenderer::onSurfaceDestroyed, - "nativeOnSurfaceDestroyed")); -} - -MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, const jni::Object& jObject) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "nativePtr"); - MapRenderer* mapRenderer = reinterpret_cast(jObject.Get(env, field)); - assert(mapRenderer != nullptr); - return *mapRenderer; -} - -} // namespace android -} // namespace mbgl diff --git a/src/map_renderer.hpp b/src/map_renderer.hpp deleted file mode 100644 index 664da20a9..000000000 --- a/src/map_renderer.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -#include - -namespace mbgl { - -template -class ActorRef; -class Mailbox; -class Renderer; -class RendererBackend; -class RendererObserver; -class ThreadPool; -class UpdateParameters; - -namespace android { - -class AndroidRendererBackend; - -/** - * The MapRenderer is a peer class that encapsulates the actions - * performed on the GL Thread. - * - * The public methods are safe to call from the main thread, others are not. - */ -class MapRenderer : public Scheduler { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRenderer"; }; - - static void registerNative(jni::JNIEnv&); - - static MapRenderer& getNativePeer(JNIEnv&, const jni::Object&); - - MapRenderer(jni::JNIEnv& _env, - const jni::Object&, - jni::jfloat pixelRatio, - const jni::String& localIdeographFontFamily); - - ~MapRenderer() override; - - // Resets the renderer to clean up on the calling thread - void reset(); - - // Takes the RendererObserver by shared_ptr so we - // don't have to make the header public. Use - // this instead of Renderer#setObserver directly - void setObserver(std::shared_ptr); - - // Sets the new update parameters to use on subsequent - // renders. Be sure to trigger a render with - // requestRender(). - void update(std::shared_ptr); - - // Gives a handle to the Renderer to enable actions on - // any thread. - ActorRef actor() const; - - // From Scheduler. Schedules by using callbacks to the - // JVM to process the mailbox on the right thread. - void schedule(std::function scheduled) override; - - void requestRender(); - - // Snapshot - requires a RunLoop on the calling thread - using SnapshotCallback = std::function; - void requestSnapshot(SnapshotCallback); - -protected: - // Called from the GL Thread // - - void scheduleSnapshot(std::unique_ptr); - -private: - // Called from the GL Thread // - - // Resets the renderer - void resetRenderer(); - - // Renders a frame. - void render(JNIEnv&); - - void onSurfaceCreated(JNIEnv&); - - void onSurfaceChanged(JNIEnv&, jint width, jint height); - - void onSurfaceDestroyed(JNIEnv&); - -private: - // Called on either Main or GL thread // - void onRendererReset(JNIEnv&); - -private: - jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; - - float pixelRatio; - optional localIdeographFontFamily; - - std::shared_ptr threadPool; - std::shared_ptr mailbox; - - std::mutex initialisationMutex; - std::shared_ptr rendererObserver; - - std::unique_ptr backend; - std::unique_ptr renderer; - std::unique_ptr> rendererRef; - - std::shared_ptr updateParameters; - std::mutex updateMutex; - - bool framebufferSizeChanged = false; - std::atomic destroyed {false}; - - std::unique_ptr snapshotCallback; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/map_renderer_runnable.cpp b/src/map_renderer_runnable.cpp deleted file mode 100644 index 227f49ee3..000000000 --- a/src/map_renderer_runnable.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "map_renderer_runnable.hpp" - -#include - -namespace mbgl { -namespace android { - -MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::function function_) - : function(std::move(function_)) { - // Create the Java peer and hold on to a global reference - // Not using a weak reference here as this might oerflow - // the weak reference table on some devices - jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5); - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - auto instance = javaClass.New(env, constructor, reinterpret_cast(this)); - javaPeer = jni::NewGlobal(env, instance); -} - -MapRendererRunnable::~MapRendererRunnable() = default; - -void MapRendererRunnable::run(jni::JNIEnv&) { - if (function) function(); -} - -jni::Global> MapRendererRunnable::peer() { - return std::move(javaPeer); -} - -// Static methods // - -void MapRendererRunnable::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - -#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - jni::RegisterNativePeer( - env, - javaClass, - "nativePtr", - std::make_unique, - "nativeInitialize", - "finalize", - METHOD(&MapRendererRunnable::run, "run")); -} - -} // namespace android -} // namespace mbgl diff --git a/src/map_renderer_runnable.hpp b/src/map_renderer_runnable.hpp deleted file mode 100644 index 24d0f2af4..000000000 --- a/src/map_renderer_runnable.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#include - -namespace mbgl { -namespace android { - -/** - * The MapRendererRunnable is a peer class that encapsulates - * a scheduled mailbox in a Java Runnable so it can be - * scheduled on the map renderer thread. - * - */ -class MapRendererRunnable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable"; }; - - static void registerNative(jni::JNIEnv&); - - MapRendererRunnable(jni::JNIEnv&, std::function); - - // Only for jni registration, unused - MapRendererRunnable(jni::JNIEnv&) { - assert(false); - } - - ~MapRendererRunnable(); - - void run(jni::JNIEnv&); - - // Transfers ownership of the Peer object to the caller - jni::Global> peer(); - -private: - jni::Global> javaPeer; - std::function function; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/mapbox.cpp b/src/mapbox.cpp deleted file mode 100644 index 5246739cf..000000000 --- a/src/mapbox.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "mapbox.hpp" - -namespace mbgl { -namespace android { - -jni::Local> Mapbox::getAssetManager(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - auto method = javaClass.GetStaticMethod()>(env, "getAssetManager"); - return javaClass.Call(env, method); -} - -jboolean Mapbox::hasInstance(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - auto method = javaClass.GetStaticMethod(env, "hasInstance"); - return javaClass.Call(env, method); -} - -void Mapbox::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl diff --git a/src/mapbox.hpp b/src/mapbox.hpp deleted file mode 100644 index 813f5bf17..000000000 --- a/src/mapbox.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "asset_manager.hpp" - -#include - -namespace mbgl { -namespace android { - -class Mapbox { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/Mapbox"; }; - static jboolean hasInstance(jni::JNIEnv&); - static jni::Local> getAssetManager(jni::JNIEnv&); - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/native_map_view.cpp b/src/native_map_view.cpp deleted file mode 100644 index 8cb637fa3..000000000 --- a/src/native_map_view.cpp +++ /dev/null @@ -1,1170 +0,0 @@ -#include "native_map_view.hpp" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Java -> C++ conversion -#include "style/android_conversion.hpp" -#include -#include - -// C++ -> Java conversion -#include "conversion/conversion.hpp" -#include "conversion/collection.hpp" -#include "style/conversion/filter.hpp" -#include "geojson/feature.hpp" - -#include "android_renderer_frontend.hpp" -#include "attach_env.hpp" -#include "bitmap.hpp" -#include "bitmap_factory.hpp" -#include "file_source.hpp" -#include "geometry/lat_lng_bounds.hpp" -#include "java/util.hpp" -#include "jni.hpp" -#include "map/camera_position.hpp" -#include "map/image.hpp" -#include "map_renderer.hpp" -#include "run_loop_impl.hpp" -#include "style/light.hpp" - -namespace mbgl { -namespace android { - -NativeMapView::NativeMapView(jni::JNIEnv& _env, - const jni::Object& _obj, - const jni::Object& jFileSource, - const jni::Object& jMapRenderer, - jni::jfloat _pixelRatio, - jni::jboolean _crossSourceCollisions) - : javaPeer(_env, _obj) - , mapRenderer(MapRenderer::getNativePeer(_env, jMapRenderer)) - , pixelRatio(_pixelRatio) { - - // Get a reference to the JavaVM for callbacks - if (_env.GetJavaVM(&vm) < 0) { - _env.ExceptionDescribe(); - return; - } - - // Create a renderer frontend - rendererFrontend = std::make_unique(mapRenderer); - - // Create Map options - MapOptions options; - options.withMapMode(MapMode::Continuous) - .withSize(mbgl::Size{ static_cast(width), static_cast(height) }) - .withPixelRatio(pixelRatio) - .withConstrainMode(ConstrainMode::HeightOnly) - .withViewportMode(ViewportMode::Default) - .withCrossSourceCollisions(_crossSourceCollisions); - - // Create the core map - map = std::make_unique( - *rendererFrontend, *this, options, - mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource)); -} - -/** - * Called through NativeMapView#destroy() - */ -NativeMapView::~NativeMapView() { - map.reset(); - vm = nullptr; -} - -void NativeMapView::onCameraWillChange(MapObserver::CameraChangeMode mode) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onCameraWillChange = javaClass.GetMethod(*_env, "onCameraWillChange"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onCameraWillChange, (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); - } -} - - -void NativeMapView::onCameraIsChanging() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onCameraIsChanging = javaClass.GetMethod(*_env, "onCameraIsChanging"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onCameraIsChanging); - } -} - -void NativeMapView::onCameraDidChange(MapObserver::CameraChangeMode mode) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onCameraDidChange = javaClass.GetMethod(*_env, "onCameraDidChange"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onCameraDidChange, - (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); - } -} - -void NativeMapView::onWillStartLoadingMap() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onWillStartLoadingMap = javaClass.GetMethod(*_env, "onWillStartLoadingMap"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onWillStartLoadingMap); - } -} - -void NativeMapView::onDidFinishLoadingMap() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFinishLoadingMap = javaClass.GetMethod(*_env, "onDidFinishLoadingMap"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidFinishLoadingMap); - } -} - -void NativeMapView::onDidFailLoadingMap(MapLoadError, const std::string& error) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFailLoadingMap = javaClass.GetMethod(*_env, "onDidFailLoadingMap"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidFailLoadingMap, jni::Make(*_env, error)); - } -} - -void NativeMapView::onWillStartRenderingFrame() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onWillStartRenderingFrame = javaClass.GetMethod(*_env, "onWillStartRenderingFrame"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onWillStartRenderingFrame); - } -} - -void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderFrameStatus status) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFinishRenderingFrame = javaClass.GetMethod(*_env, "onDidFinishRenderingFrame"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (status.mode != MapObserver::RenderMode::Partial)); - } -} - - -void NativeMapView::onWillStartRenderingMap() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onWillStartRenderingMap = javaClass.GetMethod(*_env, "onWillStartRenderingMap"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onWillStartRenderingMap); - } -} - -void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFinishRenderingMap = javaClass.GetMethod(*_env, "onDidFinishRenderingMap"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidFinishRenderingMap, (jboolean) (mode != MapObserver::RenderMode::Partial)); - } -} - -void NativeMapView::onDidBecomeIdle() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidBecomeIdle = javaClass.GetMethod(*_env, "onDidBecomeIdle"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidBecomeIdle); - } -} - -void NativeMapView::onDidFinishLoadingStyle() { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFinishLoadingStyle = javaClass.GetMethod(*_env, "onDidFinishLoadingStyle"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onDidFinishLoadingStyle); - } -} - -void NativeMapView::onSourceChanged(mbgl::style::Source& source) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onSourceChanged = javaClass.GetMethod(*_env, "onSourceChanged"); - auto sourceId = jni::Make(*_env, source.getID()); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onSourceChanged, sourceId); - } -} - -void NativeMapView::onStyleImageMissing(const std::string& imageId) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onStyleImageMissing = javaClass.GetMethod(*_env, "onStyleImageMissing"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onStyleImageMissing, jni::Make(*_env, imageId)); - } -} - -bool NativeMapView::onCanRemoveUnusedStyleImage(const std::string& imageId) { - assert(vm != nullptr); - - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onCanRemoveUnusedStyleImage = javaClass.GetMethod(*_env, "onCanRemoveUnusedStyleImage"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - return weakReference.Call(*_env, onCanRemoveUnusedStyleImage, jni::Make(*_env, imageId)); - } - - return true; -} - -// JNI Methods // - -void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) { - width = util::max(64, w); - height = util::max(64, h); - map->setSize({ static_cast(width), static_cast(height) }); -} - -jni::Local NativeMapView::getStyleUrl(jni::JNIEnv& env) { - return jni::Make(env, map->getStyle().getURL()); -} - -void NativeMapView::setStyleUrl(jni::JNIEnv& env, const jni::String& url) { - map->getStyle().loadURL(jni::Make(env, url)); -} - -jni::Local NativeMapView::getStyleJson(jni::JNIEnv& env) { - return jni::Make(env, map->getStyle().getJSON()); -} - -void NativeMapView::setStyleJson(jni::JNIEnv& env, const jni::String& json) { - map->getStyle().loadJSON(jni::Make(env, json)); -} - -void NativeMapView::setLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds) { - mbgl::BoundOptions bounds; - if (jBounds) { - bounds.withLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds)); - } else { - bounds.withLatLngBounds(mbgl::LatLngBounds::unbounded()); - } - map->setBounds(bounds); -} - -void NativeMapView::cancelTransitions(jni::JNIEnv&) { - map->cancelTransitions(); -} - -void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) { - map->setGestureInProgress(inProgress); -} - -void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::jlong duration) { - mbgl::AnimationOptions animationOptions; - if (duration > 0) { - animationOptions.duration.emplace(mbgl::Milliseconds(duration)); - animationOptions.easing.emplace(mbgl::util::UnitBezier {0.25, 0.46, 0.45, 0.94}); - } - map->moveBy({dx, dy}, animationOptions); -} - -void NativeMapView::jumpTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { - mbgl::CameraOptions options; - if (bearing != -1) { - options.bearing = bearing; - } - options.center = mbgl::LatLng(latitude, longitude); - if (padding) { - assert(padding.Length(env) == 4); - options.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), - padding.Get(env, 2), padding.Get(env, 3)}; - } - if (pitch != -1) { - options.pitch = pitch; - } - if (zoom != -1) { - options.zoom = zoom; - } - - map->jumpTo(options); -} - -void NativeMapView::easeTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding, jni::jboolean easing) { - mbgl::CameraOptions cameraOptions; - if (bearing != -1) { - cameraOptions.bearing = bearing; - } - cameraOptions.center = mbgl::LatLng(latitude, longitude); - if (padding) { - assert(padding.Length(env) == 4); - cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), - padding.Get(env, 2), padding.Get(env, 3)}; - } - if (pitch != -1) { - cameraOptions.pitch = pitch; - } - if (zoom != -1) { - cameraOptions.zoom = zoom; - } - - mbgl::AnimationOptions animationOptions; - animationOptions.duration.emplace(mbgl::Milliseconds(duration)); - if (!easing) { - // add a linear interpolator instead of easing - animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 }); - } - - map->easeTo(cameraOptions, animationOptions); -} - -void NativeMapView::flyTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { - mbgl::CameraOptions cameraOptions; - if (bearing != -1) { - cameraOptions.bearing = bearing; - } - cameraOptions.center = mbgl::LatLng(latitude, longitude); - if (padding) { - assert(padding.Length(env) == 4); - cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), - padding.Get(env, 2), padding.Get(env, 3)}; - } - if (pitch != -1) { - cameraOptions.pitch = pitch; - } - if (zoom != -1) { - cameraOptions.zoom = zoom; - } - - mbgl::AnimationOptions animationOptions; - animationOptions.duration.emplace(mbgl::Milliseconds(duration)); - map->flyTo(cameraOptions, animationOptions); -} - -jni::Local> NativeMapView::getLatLng(JNIEnv& env) { - return LatLng::New(env, *map->getCameraOptions(mbgl::nullopt).center); -} - -void NativeMapView::setLatLng(jni::JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude, const jni::Array& padding, jni::jlong duration) { - mbgl::CameraOptions cameraOptions; - cameraOptions.center = mbgl::LatLng(latitude, longitude); - if (padding) { - assert(padding.Length(env) == 4); - cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), - padding.Get(env, 2), padding.Get(env, 3)}; - } - map->easeTo(cameraOptions, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); -} - -jni::Local> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds, double top, double left, double bottom, double right, double bearing, double tilt) { - mbgl::EdgeInsets padding = {top, left, bottom, right}; - return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt), pixelRatio); -} - -jni::Local> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, const jni::Object& jGeometry, double top, double left, double bottom, double right, double bearing, double tilt) { - auto geometry = geojson::Geometry::convert(env, jGeometry); - mbgl::EdgeInsets padding = {top, left, bottom, right}; - return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt), pixelRatio); -} - -void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) { - if (reachable) { - mbgl::NetworkStatus::Reachable(); - } -} - -void NativeMapView::resetPosition(jni::JNIEnv&) { - map->jumpTo(mbgl::CameraOptions().withCenter(mbgl::LatLng {}).withZoom(0.0).withBearing(0.0).withPitch(0.0)); -} - -jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) { - return *map->getCameraOptions().pitch; -} - -void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) { - map->easeTo(mbgl::CameraOptions().withPitch(pitch), - mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); -} - -void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jdouble x, jni::jdouble y, jni::jlong duration) { - map->easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate{ x, y }), - mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); -} - -jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) { - return *map->getCameraOptions().zoom; -} - -void NativeMapView::resetZoom(jni::JNIEnv&) { - map->jumpTo(mbgl::CameraOptions().withZoom(0.0)); -} - -void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) { - map->setBounds(BoundOptions().withMinZoom(zoom)); -} - -jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) { - return *map->getBounds().minZoom; -} - -void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) { - map->setBounds(BoundOptions().withMaxZoom(zoom)); -} - -jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) { - return *map->getBounds().maxZoom; -} - -void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) { - mbgl::ScreenCoordinate first(sx, sy); - mbgl::ScreenCoordinate second(ex, ey); - map->rotateBy(first, second, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); -} - -void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) { - map->easeTo(mbgl::CameraOptions().withBearing(degrees), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); -} - -void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) { - mbgl::ScreenCoordinate anchor(cx, cy); - map->easeTo(mbgl::CameraOptions().withBearing(degrees).withAnchor(anchor), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); -} - -jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) { - return *map->getCameraOptions().bearing; -} - -void NativeMapView::resetNorth(jni::JNIEnv&) { - map->easeTo(mbgl::CameraOptions().withBearing(0.0), mbgl::AnimationOptions {{mbgl::Milliseconds(500)}}); -} - -void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, const jni::Array>& coordinates, const jni::Object& padding, jdouble direction, jni::jlong duration) { - NullCheck(env, &coordinates); - std::size_t count = coordinates.Length(env); - - std::vector latLngs; - latLngs.reserve(count); - - for (std::size_t i = 0; i < count; i++) { - latLngs.push_back(LatLng::getLatLng(env, coordinates.Get(env, i))); - } - - mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) }; - mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets); - if (direction >= 0) { - cameraOptions.bearing = direction; - } - - mbgl::AnimationOptions animationOptions; - if (duration > 0) { - animationOptions.duration.emplace(mbgl::Milliseconds(duration)); - // equivalent to kCAMediaTimingFunctionDefault in iOS - animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 }); - } - - map->easeTo(cameraOptions, animationOptions); -} - -void NativeMapView::scheduleSnapshot(jni::JNIEnv&) { - mapRenderer.requestSnapshot([&](PremultipliedImage image) { - auto _env = android::AttachEnv(); - // Convert image to bitmap - auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image)); - - // invoke Mapview#OnSnapshotReady - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onSnapshotReady, bitmap); - } - }); -} - -jni::Local> NativeMapView::getCameraPosition(jni::JNIEnv& env) { - return CameraPosition::New(env, map->getCameraOptions(mbgl::nullopt), pixelRatio); -} - -void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, const jni::String& jid) { - if (markerId == -1) { - return; - } - - std::string iconId = jni::Make(env, jid); - // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. - map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point(lon, lat), iconId }); -} - -jni::Local> NativeMapView::addMarkers(jni::JNIEnv& env, const jni::Array>& jmarkers) { - jni::NullCheck(env, &jmarkers); - std::size_t len = jmarkers.Length(env); - - std::vector ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - auto marker = jmarkers.Get(env, i); - ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation { - Marker::getPosition(env, marker), - Marker::getIconId(env, marker) - })); - } - - auto result = jni::Array::New(env, len); - result.SetRegion>(env, 0, ids); - - return result; -} - -void NativeMapView::onLowMemory(JNIEnv&) { - rendererFrontend->reduceMemoryUse(); -} - -using DebugOptions = mbgl::MapDebugOptions; - -void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) { - DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision - : DebugOptions::NoDebug; - map->setDebug(debugOptions); -} - -void NativeMapView::cycleDebugOptions(JNIEnv&) { - map->cycleDebugOptions(); -} - -jni::jboolean NativeMapView::getDebug(JNIEnv&) { - return map->getDebug() != DebugOptions::NoDebug; -} - -jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) { - return map->isFullyLoaded(); -} - -jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) { - return mbgl::Projection::getMetersPerPixelAtLatitude(lat, zoom); -} - -jni::Local> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) { - mbgl::ProjectedMeters projectedMeters = mbgl::Projection::projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); - return ProjectedMeters::New(env, projectedMeters.northing(), projectedMeters.easting()); -} - -jni::Local> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) { - return LatLng::New(env, mbgl::Projection::latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting))); -} - -jni::Local> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) { - mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude)); - return PointF::New(env, static_cast(pixel.x), static_cast(pixel.y)); -} - -jni::Local> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) { - return LatLng::New(env, map->latLngForPixel(mbgl::ScreenCoordinate(x, y))); -} - -jni::Local> NativeMapView::addPolylines(JNIEnv& env, const jni::Array>& polylines) { - NullCheck(env, &polylines); - std::size_t len = polylines.Length(env); - - std::vector ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polylines.Get(env, i)); - ids.push_back(map->addAnnotation(annotation)); - } - - auto result = jni::Array::New(env, len); - result.SetRegion>(env, 0, ids); - - return result; -} - - -jni::Local> NativeMapView::addPolygons(JNIEnv& env, const jni::Array>& polygons) { - NullCheck(env, &polygons); - std::size_t len = polygons.Length(env); - - std::vector ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygons.Get(env, i)); - ids.push_back(map->addAnnotation(annotation)); - } - - auto result = jni::Array::New(env, len); - result.SetRegion>(env, 0, ids); - - return result; -} - -void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, const jni::Object& polyline) { - mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline); - map->updateAnnotation(polylineId, annotation); -} - -void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, const jni::Object& polygon) { - mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon); - map->updateAnnotation(polygonId, annotation); -} - -void NativeMapView::removeAnnotations(JNIEnv& env, const jni::Array& ids) { - NullCheck(env, &ids); - std::size_t len = ids.Length(env); - auto elements = jni::GetArrayElements(env, *ids); - jlong* jids = std::get<0>(elements).get(); - - for (std::size_t i = 0; i < len; i++) { - if(jids[i] == -1L) { - continue; - } - map->removeAnnotation(jids[i]); - } -} - -void NativeMapView::addAnnotationIcon(JNIEnv& env, const jni::String& symbol, jint w, jint h, jfloat scale, const jni::Array& jpixels) { - const std::string symbolName = jni::Make(env, symbol); - - NullCheck(env, &jpixels); - std::size_t size = jpixels.Length(env); - - mbgl::PremultipliedImage premultipliedImage({ static_cast(w), static_cast(h) }); - if (premultipliedImage.bytes() != uint32_t(size)) { - throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); - } - - jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); - map->addAnnotationImage(std::make_unique( - symbolName, std::move(premultipliedImage), float(scale))); -} - -void NativeMapView::removeAnnotationIcon(JNIEnv& env, const jni::String& symbol) { - const std::string symbolName = jni::Make(env, symbol); - map->removeAnnotationImage(symbolName); -} - -jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, const jni::String& symbolName) { - return map->getTopOffsetPixelsForAnnotationImage(jni::Make(env, symbolName)); -} - -jni::Local> NativeMapView::getTransitionOptions(JNIEnv& env) { - const auto transitionOptions = map->getStyle().getTransitionOptions(); - const auto duration = std::chrono::duration_cast(transitionOptions.duration.value_or(mbgl::Duration::zero())).count(); - const auto delay = std::chrono::duration_cast(transitionOptions.delay.value_or(mbgl::Duration::zero())).count(); - const auto enablePlacementTransitions = (jboolean) transitionOptions.enablePlacementTransitions; - return TransitionOptions::fromTransitionOptions(env, duration, delay, enablePlacementTransitions); -} - -void NativeMapView::setTransitionOptions(JNIEnv& env, const jni::Object& options) { - const mbgl::style::TransitionOptions transitionOptions( - Duration(mbgl::Milliseconds(TransitionOptions::getDuration(env, options))), - Duration(mbgl::Milliseconds(TransitionOptions::getDelay(env, options))), - TransitionOptions::isEnablePlacementTransitions(env, options) - ); - map->getStyle().setTransitionOptions(transitionOptions); -} - -jni::Local> NativeMapView::queryPointAnnotations(JNIEnv& env, const jni::Object& rect) { - using namespace mbgl::style; - using namespace mbgl::style::conversion; - - // Convert input - mbgl::ScreenBox box = { - { RectF::getLeft(env, rect), RectF::getTop(env, rect) }, - { RectF::getRight(env, rect), RectF::getBottom(env, rect) }, - }; - - // Assume only points for now - mbgl::AnnotationIDs ids = rendererFrontend->queryPointAnnotations(box); - - // Convert result - std::vector longIds(ids.begin(), ids.end()); - auto result = jni::Array::New(env, ids.size()); - result.SetRegion>(env, 0, longIds); - - return result; -} - -jni::Local> NativeMapView::queryShapeAnnotations(JNIEnv& env, const jni::Object& rect) { - using namespace mbgl::style; - using namespace mbgl::style::conversion; - - // Convert input - mbgl::ScreenBox box = { - {RectF::getLeft(env, rect), RectF::getTop(env, rect)}, - {RectF::getRight(env, rect), RectF::getBottom(env, rect)}, - }; - - mbgl::AnnotationIDs ids = rendererFrontend->queryShapeAnnotations(box); - - // Convert result - std::vector longIds(ids.begin(), ids.end()); - auto result = jni::Array::New(env, ids.size()); - result.SetRegion>(env, 0, longIds); - - return result; -} - -jni::Local>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, - const jni::Array& layerIds, - const jni::Array>& jfilter) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - mbgl::optional> layers; - if (layerIds && layerIds.Length(env) > 0) { - layers = android::conversion::toVector(env, layerIds); - } - mapbox::geometry::point point = {x, y}; - - return Feature::convert( - env, - rendererFrontend->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) })); -} - -jni::Local>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, - jni::jfloat right, jni::jfloat bottom, const jni::Array& layerIds, - const jni::Array>& jfilter) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - mbgl::optional> layers; - if (layerIds && layerIds.Length(env) > 0) { - layers = toVector(env, layerIds); - } - mapbox::geometry::box box = { - mapbox::geometry::point{ left, top}, - mapbox::geometry::point{ right, bottom } - }; - - return Feature::convert( - env, - rendererFrontend->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) })); -} - -jni::Local> NativeMapView::getLight(JNIEnv& env) { - mbgl::style::Light* light = map->getStyle().getLight(); - if (light) { - return Light::createJavaLightPeer(env, *map, *light); - } else { - return jni::Local>(); - } -} - -jni::Local>> NativeMapView::getLayers(JNIEnv& env) { - - // Get the core layers - std::vector layers = map->getStyle().getLayers(); - - // Convert - auto jLayers = jni::Array>::New(env, layers.size()); - int index = 0; - for (auto layer : layers) { - jLayers.Set(env, index, LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, *layer)); - index++; - } - - return jLayers; -} - -jni::Local> NativeMapView::getLayer(JNIEnv& env, const jni::String& layerId) { - - // Find the layer - mbgl::style::Layer* coreLayer = map->getStyle().getLayer(jni::Make(env, layerId)); - if (!coreLayer) { - mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); - return jni::Local>(); - } - - // Create and return the layer's native peer - return LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, *coreLayer); -} - -void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, const jni::String& before) { - assert(nativeLayerPtr != 0); - - Layer *layer = reinterpret_cast(nativeLayerPtr); - try { - layer->addToMap(*map, before ? mbgl::optional(jni::Make(env, before)) : mbgl::optional()); - } catch (const std::runtime_error& error) { - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); - } -} - -void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, const jni::String& above) { - assert(nativeLayerPtr != 0); - - Layer *layer = reinterpret_cast(nativeLayerPtr); - - // Find the sibling - auto layers = map->getStyle().getLayers(); - auto siblingId = jni::Make(env, above); - - size_t index = 0; - for (auto l : layers) { - if (l->getID() == siblingId) { - break; - } - index++; - } - - // Check if we found a sibling to place before - mbgl::optional before; - if (index + 1 > layers.size()) { - // Not found - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), - std::string("Could not find layer: ").append(siblingId).c_str()); - return; - } else if (index + 1 < layers.size()) { - // Place before the sibling - before = { layers.at(index + 1)->getID() }; - } - - // Add the layer - try { - layer->addToMap(*map, before); - } catch (const std::runtime_error& error) { - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); - } -} - -void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) { - assert(nativeLayerPtr != 0); - - Layer *layer = reinterpret_cast(nativeLayerPtr); - auto layers = map->getStyle().getLayers(); - - // Check index - int numLayers = layers.size() - 1; - if (index > numLayers || index < 0) { - Log::Error(Event::JNI, "Index out of range: %i", index); - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), - std::string("Invalid index").c_str()); - return; - } - - // Insert it below the current at that index - try { - layer->addToMap(*map, layers.at(index)->getID()); - } catch (const std::runtime_error& error) { - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); - } -} - - -/** - * Remove layer at index. - */ -jni::jboolean NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) { - auto layers = map->getStyle().getLayers(); - - // Check index - int numLayers = layers.size() - 1; - if (index > numLayers || index < 0) { - Log::Warning(Event::JNI, "Index out of range: %i", index); - return jni::jni_false; - } - - std::unique_ptr coreLayer = map->getStyle().removeLayer(layers.at(index)->getID()); - if (coreLayer) { - jni::Local> layerObj = - LayerManagerAndroid::get()->createJavaLayerPeer(env, *map, std::move(coreLayer)); - return jni::jni_true; - } - return jni::jni_false; -} - -/** - * Remove with wrapper object id. Ownership is transferred back to the wrapper - */ -jni::jboolean NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) { - assert(layerPtr != 0); - - mbgl::android::Layer *layer = reinterpret_cast(layerPtr); - std::unique_ptr coreLayer = map->getStyle().removeLayer(layer->get().getID()); - if (coreLayer) { - layer->setLayer(std::move(coreLayer)); - return jni::jni_true; - } - return jni::jni_false; -} - -jni::Local>> NativeMapView::getSources(JNIEnv& env) { - // Get the core sources - std::vector sources = map->getStyle().getSources(); - - // Convert - auto jSources = jni::Array>::New(env, sources.size()); - int index = 0; - for (auto source : sources) { - jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend)); - index++; - } - - return jSources; -} - -jni::Local> NativeMapView::getSource(JNIEnv& env, const jni::String& sourceId) { - // Find the source - mbgl::style::Source* coreSource = map->getStyle().getSource(jni::Make(env, sourceId)); - if (!coreSource) { - mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); - return jni::Local>(); - } - - // Create and return the source's native peer - return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend)); -} - -void NativeMapView::addSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { - assert(sourcePtr != 0); - - Source *source = reinterpret_cast(sourcePtr); - try { - source->addToMap(env, obj, *map, *rendererFrontend); - } catch (const std::runtime_error& error) { - jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); - } -} - -jni::jboolean NativeMapView::removeSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { - assert(sourcePtr != 0); - - mbgl::android::Source *source = reinterpret_cast(sourcePtr); - if (source->removeFromMap(env, obj, *map)) { - source->releaseJavaPeer(); - return jni::jni_true; - } - - return jni::jni_false; -} - -void NativeMapView::addImage(JNIEnv& env, const jni::String& name, const jni::Object& bitmap, jni::jfloat scale, jni::jboolean sdf) { - jni::NullCheck(env, &bitmap); - mbgl::PremultipliedImage premultipliedImage = Bitmap::GetImage(env, bitmap); - - map->getStyle().addImage(std::make_unique( - jni::Make(env, name), - std::move(premultipliedImage), - float(scale), - sdf) - ); -} - -void NativeMapView::addImages(JNIEnv& env, const jni::Array>& jimages) { - jni::NullCheck(env, &jimages); - std::size_t len = jimages.Length(env); - - for (std::size_t i = 0; i < len; i++) { - auto image = mbgl::android::Image::getImage(env, jimages.Get(env, i)); - map->getStyle().addImage(std::make_unique(image)); - } -} - -void NativeMapView::removeImage(JNIEnv& env, const jni::String& name) { - map->getStyle().removeImage(jni::Make(env, name)); -} - -jni::Local> NativeMapView::getImage(JNIEnv& env, const jni::String& name) { - const mbgl::style::Image *image = map->getStyle().getImage(jni::Make(env, name)); - if (image) { - return Bitmap::CreateBitmap(env, image->getImage()); - } else { - return jni::Local>(); - } -} - -void NativeMapView::setPrefetchTiles(JNIEnv&, jni::jboolean enable) { - map->setPrefetchZoomDelta(enable ? util::DEFAULT_PREFETCH_ZOOM_DELTA : uint8_t(0)); -} - -jni::jboolean NativeMapView::getPrefetchTiles(JNIEnv&) { - return jni::jboolean(map->getPrefetchZoomDelta() > 0); -} - -void NativeMapView::setPrefetchZoomDelta(JNIEnv&, jni::jint delta) { - map->setPrefetchZoomDelta(uint8_t(delta)); -} - -jni::jint NativeMapView::getPrefetchZoomDelta(JNIEnv&) { - return jni::jint(map->getPrefetchZoomDelta()); -} - -mbgl::Map& NativeMapView::getMap() { - return *map; -} - -// Static methods // - -void NativeMapView::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, - javaClass, - "nativePtr", - jni::MakePeer&, - const jni::Object&, - const jni::Object&, - jni::jfloat, - jni::jboolean>, - "nativeInitialize", - "nativeDestroy", - METHOD(&NativeMapView::resizeView, "nativeResizeView"), - METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), - METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), - METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), - METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), - METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), - METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), - METHOD(&NativeMapView::moveBy, "nativeMoveBy"), - METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), - METHOD(&NativeMapView::easeTo, "nativeEaseTo"), - METHOD(&NativeMapView::flyTo, "nativeFlyTo"), - METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), - METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), - METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), - METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), - METHOD(&NativeMapView::setReachability, "nativeSetReachability"), - METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), - METHOD(&NativeMapView::getPitch, "nativeGetPitch"), - METHOD(&NativeMapView::setPitch, "nativeSetPitch"), - METHOD(&NativeMapView::getZoom, "nativeGetZoom"), - METHOD(&NativeMapView::setZoom, "nativeSetZoom"), - METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), - METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), - METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), - METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), - METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), - METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), - METHOD(&NativeMapView::setBearing, "nativeSetBearing"), - METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), - METHOD(&NativeMapView::getBearing, "nativeGetBearing"), - METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), - METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), - METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), - METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), - METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), - METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), - METHOD(&NativeMapView::setDebug, "nativeSetDebug"), - METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), - METHOD(&NativeMapView::getDebug, "nativeGetDebug"), - METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), - METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), - METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), - METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), - METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), - METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), - METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), - METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), - METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), - METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), - METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), - METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), - METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), - METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), - METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), - METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), - METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), - METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), - METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), - METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), - METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), - METHOD(&NativeMapView::getLight, "nativeGetLight"), - METHOD(&NativeMapView::getLayers, "nativeGetLayers"), - METHOD(&NativeMapView::getLayer, "nativeGetLayer"), - METHOD(&NativeMapView::addLayer, "nativeAddLayer"), - METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), - METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), - METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), - METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), - METHOD(&NativeMapView::getSources, "nativeGetSources"), - METHOD(&NativeMapView::getSource, "nativeGetSource"), - METHOD(&NativeMapView::addSource, "nativeAddSource"), - METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), - METHOD(&NativeMapView::addImage, "nativeAddImage"), - METHOD(&NativeMapView::addImages, "nativeAddImages"), - METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), - METHOD(&NativeMapView::getImage, "nativeGetImage"), - METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), - METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), - METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles"), - METHOD(&NativeMapView::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), - METHOD(&NativeMapView::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta")); -} - -} // namespace android -} // namespace mbgl diff --git a/src/native_map_view.hpp b/src/native_map_view.hpp deleted file mode 100755 index 5a340d128..000000000 --- a/src/native_map_view.hpp +++ /dev/null @@ -1,265 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "annotation/marker.hpp" -#include "annotation/polygon.hpp" -#include "annotation/polyline.hpp" -#include "graphics/pointf.hpp" -#include "graphics/rectf.hpp" -#include "geojson/feature.hpp" -#include "geojson/geometry.hpp" -#include "geometry/lat_lng.hpp" -#include "geometry/projected_meters.hpp" -#include "style/layers/layer_manager.hpp" -#include "style/sources/source.hpp" -#include "geometry/lat_lng_bounds.hpp" -#include "map/camera_position.hpp" -#include "map/image.hpp" -#include "style/light.hpp" -#include "bitmap.hpp" - -#include -#include -#include -#include -#include -#include - -namespace mbgl { -namespace android { - -class AndroidRendererFrontend; -class FileSource; -class MapRenderer; - -class NativeMapView : public MapObserver { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; }; - - static void registerNative(jni::JNIEnv&); - - NativeMapView(jni::JNIEnv&, - const jni::Object&, - const jni::Object&, - const jni::Object&, - jni::jfloat, - jni::jboolean); - - virtual ~NativeMapView(); - - // mbgl::RendererBackend (mbgl::MapObserver) // - void onCameraWillChange(MapObserver::CameraChangeMode) override; - void onCameraIsChanging() override; - void onCameraDidChange(MapObserver::CameraChangeMode) override; - void onWillStartLoadingMap() override; - void onDidFinishLoadingMap() override; - void onDidFailLoadingMap(MapLoadError, const std::string&) override; - void onWillStartRenderingFrame() override; - void onDidFinishRenderingFrame(MapObserver::RenderFrameStatus) override; - void onWillStartRenderingMap() override; - void onDidFinishRenderingMap(MapObserver::RenderMode) override; - void onDidBecomeIdle() override; - void onDidFinishLoadingStyle() override; - void onSourceChanged(mbgl::style::Source&) override; - void onStyleImageMissing(const std::string&) override; - bool onCanRemoveUnusedStyleImage(const std::string&) override; - - // JNI // - - void resizeView(jni::JNIEnv&, int, int); - - jni::Local getStyleUrl(jni::JNIEnv&); - - void setStyleUrl(jni::JNIEnv&, const jni::String&); - - jni::Local getStyleJson(jni::JNIEnv&); - - void setStyleJson(jni::JNIEnv&, const jni::String&); - - void setLatLngBounds(jni::JNIEnv&, const jni::Object&); - - void cancelTransitions(jni::JNIEnv&); - - void setGestureInProgress(jni::JNIEnv&, jni::jboolean); - - void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong); - - void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, const jni::Array&); - - void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&, jni::jboolean); - - void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&); - - jni::Local> getLatLng(JNIEnv&); - - void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, const jni::Array&, jni::jlong); - - jni::Local> getCameraForLatLngBounds(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); - - jni::Local> getCameraForGeometry(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); - - void setReachability(jni::JNIEnv&, jni::jboolean); - - void resetPosition(jni::JNIEnv&); - - jni::jdouble getPitch(jni::JNIEnv&); - - void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong); - - void setZoom(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); - - jni::jdouble getZoom(jni::JNIEnv&); - - void resetZoom(jni::JNIEnv&); - - void setMinZoom(jni::JNIEnv&, jni::jdouble); - - jni::jdouble getMinZoom(jni::JNIEnv&); - - void setMaxZoom(jni::JNIEnv&, jni::jdouble); - - jni::jdouble getMaxZoom(jni::JNIEnv&); - - void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); - - void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong); - - void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); - - jni::jdouble getBearing(jni::JNIEnv&); - - void resetNorth(jni::JNIEnv&); - - void setVisibleCoordinateBounds(JNIEnv&, const jni::Array>&, const jni::Object&, jni::jdouble, jni::jlong); - - void scheduleSnapshot(jni::JNIEnv&); - - jni::Local> getCameraPosition(jni::JNIEnv&); - - void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, const jni::String&); - - jni::Local> addMarkers(jni::JNIEnv&, const jni::Array>&); - - void onLowMemory(JNIEnv& env); - - void setDebug(JNIEnv&, jni::jboolean); - - void cycleDebugOptions(JNIEnv&); - - jni::jboolean getDebug(JNIEnv&); - - jni::jboolean isFullyLoaded(JNIEnv&); - - jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble); - - jni::Local> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble); - - jni::Local> pixelForLatLng(JNIEnv&, jdouble, jdouble); - - jni::Local> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble); - - jni::Local> latLngForPixel(JNIEnv&, jfloat, jfloat); - - jni::Local> addPolylines(JNIEnv&, const jni::Array>&); - - jni::Local> addPolygons(JNIEnv&, const jni::Array>&); - - void updatePolyline(JNIEnv&, jlong, const jni::Object&); - - void updatePolygon(JNIEnv&, jlong, const jni::Object&); - - void removeAnnotations(JNIEnv&, const jni::Array&); - - void addAnnotationIcon(JNIEnv&, const jni::String&, jint, jint, jfloat, const jni::Array&); - - void removeAnnotationIcon(JNIEnv&, const jni::String&); - - jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, const jni::String&); - - jni::Local> getTransitionOptions(JNIEnv&); - - void setTransitionOptions(JNIEnv&, const jni::Object&); - - jni::Local> queryPointAnnotations(JNIEnv&, const jni::Object&); - - jni::Local> queryShapeAnnotations(JNIEnv&, const jni::Object&); - - jni::Local>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, - const jni::Array&, - const jni::Array>& jfilter); - - jni::Local>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, - jni::jfloat, const jni::Array&, - const jni::Array>& jfilter); - - jni::Local> getLight(JNIEnv&); - - jni::Local>> getLayers(JNIEnv&); - - jni::Local> getLayer(JNIEnv&, const jni::String&); - - void addLayer(JNIEnv&, jlong, const jni::String&); - - void addLayerAbove(JNIEnv&, jlong, const jni::String&); - - void addLayerAt(JNIEnv&, jni::jlong, jni::jint); - - jni::jboolean removeLayerAt(JNIEnv&, jni::jint); - - jni::jboolean removeLayer(JNIEnv&, jlong); - - jni::Local>> getSources(JNIEnv&); - - jni::Local> getSource(JNIEnv&, const jni::String&); - - void addSource(JNIEnv&, const jni::Object&, jlong nativePtr); - - jni::jboolean removeSource(JNIEnv&, const jni::Object&, jlong nativePtr); - - void addImage(JNIEnv&, const jni::String&, const jni::Object& bitmap, jni::jfloat, jni::jboolean); - - void addImages(JNIEnv&, const jni::Array>&); - - void removeImage(JNIEnv&, const jni::String&); - - jni::Local> getImage(JNIEnv&, const jni::String&); - - void setPrefetchTiles(JNIEnv&, jni::jboolean); - - jni::jboolean getPrefetchTiles(JNIEnv&); - - void setPrefetchZoomDelta(JNIEnv&, jni::jint); - - jni::jint getPrefetchZoomDelta(JNIEnv&); - - mbgl::Map& getMap(); - -private: - std::unique_ptr rendererFrontend; - - JavaVM *vm = nullptr; - jni::WeakReference> javaPeer; - - MapRenderer& mapRenderer; - - std::string styleUrl; - - float pixelRatio; - - // Minimum texture size according to OpenGL ES 2.0 specification. - int width = 64; - int height = 64; - - // Ensure these are initialised last - std::unique_ptr map; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_manager.cpp b/src/offline/offline_manager.cpp deleted file mode 100644 index 029252f78..000000000 --- a/src/offline/offline_manager.cpp +++ /dev/null @@ -1,330 +0,0 @@ -#include "offline_manager.hpp" - -#include - -#include "../attach_env.hpp" - -namespace mbgl { -namespace android { - -// OfflineManager // - -OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object& jFileSource) - : fileSource(std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} - -OfflineManager::~OfflineManager() {} - -void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { - fileSource->setOfflineMapboxTileCountLimit(limit); -} - -void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - auto globalFilesource = jni::NewGlobal(env_, jFileSource_); - - fileSource->listOfflineRegions([ - //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)), - jFileSource = std::make_shared(std::move(globalFilesource)) - ](mbgl::expected regions) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (regions) { - OfflineManager::ListOfflineRegionsCallback::onList( - *env, *jFileSource, *callback, *regions); - } else { - OfflineManager::ListOfflineRegionsCallback::onError( - *env, *callback, regions.error()); - } - }); -} - -void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, - const jni::Object& jFileSource_, - const jni::Object& definition_, - const jni::Array& metadata_, - const jni::Object& callback_) { - // Convert - auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); - - mbgl::OfflineRegionMetadata metadata; - if (metadata_) { - metadata = OfflineRegion::metadata(env_, metadata_); - } - - auto globalCallback = jni::NewGlobal(env_, callback_); - auto globalFilesource = jni::NewGlobal(env_, jFileSource_); - - // Create region - fileSource->createOfflineRegion(definition, metadata, [ - //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)), - jFileSource = std::make_shared(std::move(globalFilesource)) - ](mbgl::expected region) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (region) { - OfflineManager::CreateOfflineRegionCallback::onCreate( - *env, *jFileSource, *callback, *region - ); - } else { - OfflineManager::CreateOfflineRegionCallback::onError( - *env, *callback, region.error()); - } - }); -} - -void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, - const jni::String& jString_, - const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - auto globalFilesource = jni::NewGlobal(env_, jFileSource_); - - auto path = jni::Make(env_, jString_); - fileSource->mergeOfflineRegions(path, [ - //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)), - jFileSource = std::make_shared(std::move(globalFilesource)) - ](mbgl::expected regions) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (regions) { - OfflineManager::MergeOfflineRegionsCallback::onMerge( - *env, *jFileSource, *callback, *regions); - } else { - OfflineManager::MergeOfflineRegionsCallback::onError( - *env, *callback, regions.error()); - } - }); -} - -void OfflineManager::resetDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->resetDatabase([ - //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr exception) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (exception) { - OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); - } else { - OfflineManager::FileSourceCallback::onSuccess(*env, *callback); - } - }); -} - -void OfflineManager::invalidateAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->invalidateAmbientCache([ - //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr exception) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (exception) { - OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); - } else { - OfflineManager::FileSourceCallback::onSuccess(*env, *callback); - } - }); -} - -void OfflineManager::clearAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->clearAmbientCache([ - //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr exception) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (exception) { - OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); - } else { - OfflineManager::FileSourceCallback::onSuccess(*env, *callback); - } - }); -} - -void OfflineManager::setMaximumAmbientCacheSize(jni::JNIEnv& env_, const jni::jlong size_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->setMaximumAmbientCacheSize(size_, [ - //Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr exception) mutable { - - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (exception) { - OfflineManager::FileSourceCallback::onError(*env, *callback, jni::Make(*env, mbgl::util::toString(exception))); - } else { - OfflineManager::FileSourceCallback::onSuccess(*env, *callback); - } - }); -} - -// FileSource::FileSourceCallback // - -void OfflineManager::FileSourceCallback::onSuccess(jni::JNIEnv& env, - const jni::Object& callback) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onSuccess"); - callback.Call(env, method); -} - -void OfflineManager::FileSourceCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - const jni::String& message) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - callback.Call(env, method, message); -} - -void OfflineManager::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - jni::RegisterNativePeer( env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"), - METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"), - METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"), - METHOD(&OfflineManager::mergeOfflineRegions, "mergeOfflineRegions"), - METHOD(&OfflineManager::resetDatabase, "nativeResetDatabase"), - METHOD(&OfflineManager::invalidateAmbientCache, "nativeInvalidateAmbientCache"), - METHOD(&OfflineManager::clearAmbientCache, "nativeClearAmbientCache"), - METHOD(&OfflineManager::setMaximumAmbientCacheSize, "nativeSetMaximumAmbientCacheSize"), - METHOD(&OfflineManager::putResourceWithUrl, "putResourceWithUrl")); -} - -// OfflineManager::ListOfflineRegionsCallback // - -void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, - const jni::Object& jFileSource, - const jni::Object& callback, - mbgl::OfflineRegions& regions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod>)>(env, "onList"); - - std::size_t index = 0; - auto jregions = jni::Array>::New(env, regions.size()); - for (auto& region : regions) { - jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); - index++; - } - - callback.Call(env, method, jregions); -} - -// OfflineManager::CreateOfflineRegionCallback // - -void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, - const jni::Object& jFileSource, - const jni::Object& callback, - mbgl::OfflineRegion& region) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod)>(env, "onCreate"); - - callback.Call(env, method, OfflineRegion::New(env, jFileSource, std::move(region))); -} - -// OfflineManager::MergeOfflineRegionsCallback // - -void OfflineManager::MergeOfflineRegionsCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineManager::MergeOfflineRegionsCallback::onMerge(jni::JNIEnv& env, - const jni::Object& jFileSource, - const jni::Object& callback, - mbgl::OfflineRegions& regions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod>)>(env, "onMerge"); - - std::size_t index = 0; - auto jregions = jni::Array>::New(env, regions.size()); - for (auto& region : regions) { - jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); - index++; - } - - callback.Call(env, method, jregions); -} - -void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, - const jni::String& url_, - const jni::Array& arr, - jlong modified, - jlong expires, - const jni::String& eTag_, - jboolean mustRevalidate) { - auto url = jni::Make(env, url_); - auto data = std::make_shared(arr.Length(env), char()); - jni::GetArrayRegion(env, *arr, 0, data->size(), reinterpret_cast(&(*data)[0])); - mbgl::Resource resource(mbgl::Resource::Kind::Unknown, url); - mbgl::Response response; - response.data = data; - response.mustRevalidate = mustRevalidate; - if (eTag_) { - response.etag = jni::Make(env, eTag_); - } - if (modified > 0) { - response.modified = Timestamp(mbgl::Seconds(modified)); - } - if (expires > 0) { - response.expires = Timestamp(mbgl::Seconds(expires)); - } - - fileSource->put(resource, response); -} - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_manager.hpp b/src/offline/offline_manager.hpp deleted file mode 100644 index 058cfb5b4..000000000 --- a/src/offline/offline_manager.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include -#include - -#include "../file_source.hpp" -#include "offline_region.hpp" -#include "offline_region_definition.hpp" -#include "../java_types.hpp" - -#include - -namespace mbgl { - -class DefaultFileSource; - -namespace android { - -class OfflineManager { -public: - - class ListOfflineRegionsCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";} - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onList(jni::JNIEnv&, - const jni::Object&, - const jni::Object&, - mbgl::OfflineRegions&); - }; - - class CreateOfflineRegionCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; } - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onCreate(jni::JNIEnv&, - const jni::Object&, - const jni::Object&, - mbgl::OfflineRegion&); - }; - - class MergeOfflineRegionsCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$MergeOfflineRegionsCallback";} - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onMerge(jni::JNIEnv&, - const jni::Object&, - const jni::Object&, - mbgl::OfflineRegions&); - }; - - struct FileSourceCallback { - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$FileSourceCallback";} - - static void onSuccess(jni::JNIEnv&, const jni::Object&); - - static void onError(jni::JNIEnv&, const jni::Object&, const jni::String&); - }; - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }; - - static void registerNative(jni::JNIEnv&); - - OfflineManager(jni::JNIEnv&, const jni::Object&); - ~OfflineManager(); - - void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit); - - void listOfflineRegions(jni::JNIEnv&, const jni::Object&, const jni::Object& callback); - - void createOfflineRegion(jni::JNIEnv&, - const jni::Object& jFileSource_, - const jni::Object& definition, - const jni::Array& metadata, - const jni::Object& callback); - - void mergeOfflineRegions(jni::JNIEnv&, - const jni::Object&, - const jni::String&, - const jni::Object&); - - void putResourceWithUrl(jni::JNIEnv&, - const jni::String& url, - const jni::Array& data, - jlong modified, - jlong expires, - const jni::String& eTag, - jboolean mustRevalidate); - - void resetDatabase(jni::JNIEnv&, const jni::Object& callback_); - - void invalidateAmbientCache(jni::JNIEnv&, const jni::Object& callback_); - - void clearAmbientCache(jni::JNIEnv&, const jni::Object& callback_); - - void setMaximumAmbientCacheSize(jni::JNIEnv&, const jni::jlong size, const jni::Object& callback_); - -private: - std::shared_ptr fileSource; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region.cpp b/src/offline/offline_region.cpp deleted file mode 100644 index ac9f491ab..000000000 --- a/src/offline/offline_region.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "offline_region.hpp" - -#include -#include - -#include "offline_region_definition.hpp" -#include "offline_region_error.hpp" -#include "offline_region_status.hpp" -#include "../attach_env.hpp" - -namespace mbgl { -namespace android { - -// OfflineRegion // - -OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object& jFileSource) - : region(reinterpret_cast(offlineRegionPtr)) - , fileSource(std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} - -OfflineRegion::~OfflineRegion() {} - -void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Object& callback) { - - // Define the observer - class Observer : public mbgl::OfflineRegionObserver { - public: - Observer(jni::Global, jni::EnvAttachingDeleter> callback_) - : callback(std::move(callback_)) { - } - - void statusChanged(mbgl::OfflineRegionStatus status) override { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*env); - static auto method = javaClass.GetMethod)>(*env, "onStatusChanged"); - - callback.Call(*env, method, OfflineRegionStatus::New(*env, status)); - } - - void responseError(mbgl::Response::Error error) override { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*env); - static auto method = javaClass.GetMethod)>(*env, "onError"); - - callback.Call(*env, method, OfflineRegionError::New(*env, error)); - } - - void mapboxTileCountLimitExceeded(uint64_t limit) override { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*env); - static auto method = javaClass.GetMethod(*env, "mapboxTileCountLimitExceeded"); - - callback.Call(*env, method, jlong(limit)); - } - - jni::Global, jni::EnvAttachingDeleter> callback; - }; - - // Set the observer - fileSource->setOfflineRegionObserver(*region, std::make_unique(jni::NewGlobal(env_, callback))); -} - -void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) { - // State - mbgl::OfflineRegionDownloadState state; - switch (jState) { - case 0: - state = mbgl::OfflineRegionDownloadState::Inactive; - break; - case 1: - state = mbgl::OfflineRegionDownloadState::Active; - break; - default: - mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active)."); - return; - } - - fileSource->setOfflineRegionDownloadState(*region, state); -} - -void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->getOfflineRegionStatus(*region, [ - //Ensure the object is not gc'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](mbgl::expected status) mutable { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (status) { - OfflineRegionStatusCallback::onStatus(*env, *callback, std::move(*status)); - } else { - OfflineRegionStatusCallback::onError(*env, *callback, status.error()); - } - }); -} - -void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->deleteOfflineRegion(std::move(*region), [ - //Ensure the object is not gc'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr error) mutable { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (error) { - OfflineRegionDeleteCallback::onError(*env, *callback, error); - } else { - OfflineRegionDeleteCallback::onDelete(*env, *callback); - } - }); -} - -void OfflineRegion::invalidateOfflineRegion(jni::JNIEnv& env_, const jni::Object& callback_) { - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->invalidateOfflineRegion(*region, [ - //Ensure the object is not gc'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](std::exception_ptr error) mutable { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (error) { - OfflineRegionInvalidateCallback::onError(*env, *callback, error); - } else { - OfflineRegionInvalidateCallback::onInvalidate(*env, *callback); - } - }); -} - -void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Array& jMetadata, const jni::Object& callback_) { - auto metadata = OfflineRegion::metadata(env_, jMetadata); - auto globalCallback = jni::NewGlobal(env_, callback_); - - fileSource->updateOfflineMetadata(region->getID(), metadata, [ - //Ensure the object is not gc'd in the meanwhile - callback = std::make_shared(std::move(globalCallback)) - ](mbgl::expected data) mutable { - // Reattach, the callback comes from a different thread - android::UniqueEnv env = android::AttachEnv(); - - if (data) { - OfflineRegionUpdateMetadataCallback::onUpdate(*env, *callback, std::move(*data)); - } else { - OfflineRegionUpdateMetadataCallback::onError(*env, *callback, data.error()); - } - }); -} - -jni::Local> OfflineRegion::New(jni::JNIEnv& env, const jni::Object& jFileSource, mbgl::OfflineRegion region) { - - // Definition - auto definition = region.getDefinition().match( - [&](const mbgl::OfflineTilePyramidRegionDefinition def) { - return OfflineTilePyramidRegionDefinition::New(env, def); - }, [&](const mbgl::OfflineGeometryRegionDefinition def) { - return OfflineGeometryRegionDefinition::New(env, def); - }); - - // Create region java object - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor, jni::jlong, jni::Object, jni::Array>(env); - - return javaClass.New(env, constructor, - reinterpret_cast(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap - jFileSource, - jni::jlong(region.getID()), - definition, - OfflineRegion::metadata(env, region.getMetadata())); -} - -jni::Local> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) { - std::vector convertedMetadata(metadata_.begin(), metadata_.end()); - std::size_t length = static_cast(convertedMetadata.size()); - auto metadata = jni::Array::New(env, length); - metadata.SetRegion>(env, 0, convertedMetadata); - return metadata; -} - -mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, const jni::Array& metadata_) { - std::size_t length = metadata_.Length(env); - auto metadata_tmp = std::vector(); - metadata_tmp.resize(length); - metadata_.GetRegion>(env, 0, metadata_tmp); - auto metadata = std::vector(metadata_tmp.begin(), metadata_tmp.end()); - return metadata; -} - -void OfflineRegion::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - jni::Class::Singleton(env); - - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - jni::RegisterNativePeer( env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"), - METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"), - METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"), - METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"), - METHOD(&OfflineRegion::invalidateOfflineRegion, "invalidateOfflineRegion"), - METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata") - ); -} - -// OfflineRegionObserver // - -// OfflineRegionStatusCallback // - -void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env, - const jni::Object& callback, - mbgl::optional status) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod)>(env, "onStatus"); - - callback.Call(env, method, OfflineRegionStatus::New(env, std::move(*status))); -} - -// OfflineRegionDeleteCallback // - -void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, const jni::Object& callback) { - // Trigger callback - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onDelete"); - - callback.Call(env, method); -} - -// OfflineRegionUpdateMetadataCallback // - -void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env, - const jni::Object& callback, - mbgl::optional metadata) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod)>(env, "onUpdate"); - - callback.Call(env, method, OfflineRegion::metadata(env, std::move(*metadata))); -} - -// OfflineRegionInvalidateCallback // - -void OfflineRegion::OfflineRegionInvalidateCallback::onError(jni::JNIEnv& env, - const jni::Object& callback, - std::exception_ptr error) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onError"); - callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); -} - -void OfflineRegion::OfflineRegionInvalidateCallback::onInvalidate(jni::JNIEnv& env, const jni::Object& callback) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "onInvalidate"); - callback.Call(env, method); -} - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region.hpp b/src/offline/offline_region.hpp deleted file mode 100644 index dda253469..000000000 --- a/src/offline/offline_region.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include -#include - -#include "../file_source.hpp" - -#include - -namespace mbgl { -namespace android { - -class OfflineRegion { -public: - class OfflineRegionObserver { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; }; - }; - - class OfflineRegionStatusCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; }; - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onStatus(jni::JNIEnv&, - const jni::Object&, - mbgl::optional); - }; - - class OfflineRegionDeleteCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; }; - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onDelete(jni::JNIEnv&, const jni::Object&); - }; - - class OfflineRegionInvalidateCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionInvalidateCallback"; }; - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onInvalidate(jni::JNIEnv&, const jni::Object&); - }; - - class OfflineRegionUpdateMetadataCallback { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; }; - - static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); - - static void onUpdate(jni::JNIEnv&, - const jni::Object&, - mbgl::optional); - }; - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }; - - OfflineRegion(jni::JNIEnv&, jni::jlong, const jni::Object&); - - ~OfflineRegion(); - - void setOfflineRegionObserver(jni::JNIEnv&, const jni::Object&); - - void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint); - - void getOfflineRegionStatus(jni::JNIEnv&, const jni::Object&); - - void deleteOfflineRegion(jni::JNIEnv&, const jni::Object&); - - void invalidateOfflineRegion(jni::JNIEnv&, const jni::Object&); - - void updateOfflineRegionMetadata(jni::JNIEnv&, const jni::Array&, const jni::Object&); - - static jni::Local> New(jni::JNIEnv&, const jni::Object&, mbgl::OfflineRegion); - - static jni::Local> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata); - - static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, const jni::Array&); - - static void registerNative(jni::JNIEnv&); - -private: - std::unique_ptr region; - std::shared_ptr fileSource; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_definition.cpp b/src/offline/offline_region_definition.cpp deleted file mode 100644 index bb9dfc8dd..000000000 --- a/src/offline/offline_region_definition.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "offline_region_definition.hpp" - -#include "../geometry/lat_lng_bounds.hpp" -#include "../geojson/geometry.hpp" - -#include - -namespace mbgl { -namespace android { - -// OfflineRegionDefinition // - -void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, - const jni::Object& jDefinition) { - if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { - return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); - } else if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { - return OfflineGeometryRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); - } - - throw std::runtime_error("Unknown offline region definition java class"); -} - -// OfflineTilePyramidRegionDefinition // - -jni::Local> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); - - return javaClass.New(env, constructor, - jni::Make(env, definition.styleURL), - LatLngBounds::New(env, definition.bounds), - definition.minZoom, - definition.maxZoom, - definition.pixelRatio, - jni::jboolean(definition.includeIdeographs)); -} - -mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { - // Field references - static auto& javaClass = jni::Class::Singleton(env); - static auto styleURLF = javaClass.GetField(env, "styleURL"); - static auto boundsF = javaClass.GetField>(env, "bounds"); - static auto minZoomF = javaClass.GetField(env, "minZoom"); - static auto maxZoomF = javaClass.GetField(env, "maxZoom"); - static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); - static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); - - return mbgl::OfflineTilePyramidRegionDefinition( - jni::Make(env, jDefinition.Get(env, styleURLF)), - LatLngBounds::getLatLngBounds(env, jDefinition.Get(env, boundsF)), - jDefinition.Get(env, minZoomF), - jDefinition.Get(env, maxZoomF), - jDefinition.Get(env, pixelRatioF), - jDefinition.Get(env, includeIdeographsF) - ); -} - -void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -// OfflineGeometryRegionDefinition // - -jni::Local> OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); - - return javaClass.New(env, constructor, - jni::Make(env, definition.styleURL), - geojson::Geometry::New(env, definition.geometry), - definition.minZoom, - definition.maxZoom, - definition.pixelRatio, - jni::jboolean(definition.includeIdeographs)); -} - -mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { - // Field references - static auto& javaClass = jni::Class::Singleton(env); - static auto styleURLF = javaClass.GetField(env, "styleURL"); - static auto geometryF = javaClass.GetField>(env, "geometry"); - static auto minZoomF = javaClass.GetField(env, "minZoom"); - static auto maxZoomF = javaClass.GetField(env, "maxZoom"); - static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); - static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); - - return mbgl::OfflineGeometryRegionDefinition( - jni::Make(env, jDefinition.Get(env, styleURLF)), - geojson::Geometry::convert(env, jDefinition.Get(env, geometryF)), - jDefinition.Get(env, minZoomF), - jDefinition.Get(env, maxZoomF), - jDefinition.Get(env, pixelRatioF), - jDefinition.Get(env, includeIdeographsF) - ); -} - -void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_definition.hpp b/src/offline/offline_region_definition.hpp deleted file mode 100644 index 827fac0a8..000000000 --- a/src/offline/offline_region_definition.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -namespace mbgl { -namespace android { - -class OfflineRegionDefinition { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; }; - - static void registerNative(jni::JNIEnv&); - - static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, const jni::Object& jDefinition); -}; - -class OfflineTilePyramidRegionDefinition { -public: - using SuperTag = OfflineRegionDefinition; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); - - static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -class OfflineGeometryRegionDefinition { -public: - using SuperTag = OfflineRegionDefinition; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; - - static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); - - static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_error.cpp b/src/offline/offline_region_error.cpp deleted file mode 100644 index 199bbafa6..000000000 --- a/src/offline/offline_region_error.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "offline_region_error.hpp" - -namespace mbgl { -namespace android { - -jni::Local> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) { - - // Handle the value of reason independently of the underlying int value - std::string reason; - switch(error.reason) { - case mbgl::Response::Error::Reason::Success: - reason = "REASON_SUCCESS"; - break; - case mbgl::Response::Error::Reason::NotFound: - reason = "REASON_NOT_FOUND"; - break; - case mbgl::Response::Error::Reason::Server: - reason = "REASON_SERVER"; - break; - case mbgl::Response::Error::Reason::Connection: - reason = "REASON_CONNECTION"; - break; - case mbgl::Response::Error::Reason::RateLimit: - reason = "REASON_RATE_LIMIT"; - break; - case mbgl::Response::Error::Reason::Other: - reason = "REASON_OTHER"; - break; - } - - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - - return javaClass.New(env, constructor, - jni::Make(env, reason), - jni::Make(env, error.message)); -} - -void OfflineRegionError::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_error.hpp b/src/offline/offline_region_error.hpp deleted file mode 100644 index 151e05ab1..000000000 --- a/src/offline/offline_region_error.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -namespace mbgl { -namespace android { - -class OfflineRegionError { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; }; - - static jni::Local> New(jni::JNIEnv&, mbgl::Response::Error); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_status.cpp b/src/offline/offline_region_status.cpp deleted file mode 100644 index 5dd9f20a7..000000000 --- a/src/offline/offline_region_status.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "offline_region_status.hpp" - -namespace mbgl { -namespace android { - -jni::Local> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) { - - // Convert to jint - jint downloadState; - switch(status.downloadState) { - case mbgl::OfflineRegionDownloadState::Inactive: - downloadState = 0; - break; - case mbgl::OfflineRegionDownloadState::Active: - downloadState = 1; - break; - } - - // Create java object - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, - downloadState, - jlong(status.completedResourceCount), - jlong(status.completedResourceSize), - jlong(status.completedTileCount), - jlong(status.completedTileSize), - jlong(status.requiredResourceCount), - jboolean(status.requiredResourceCountIsPrecise) - ); -} - -void OfflineRegionStatus::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl diff --git a/src/offline/offline_region_status.hpp b/src/offline/offline_region_status.hpp deleted file mode 100644 index 9ef48ec35..000000000 --- a/src/offline/offline_region_status.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -namespace mbgl { -namespace android { - -class OfflineRegionStatus { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; }; - - static jni::Local> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/run_loop.cpp b/src/run_loop.cpp deleted file mode 100644 index a9cbfb57a..000000000 --- a/src/run_loop.cpp +++ /dev/null @@ -1,256 +0,0 @@ -#include "run_loop_impl.hpp" - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define PIPE_OUT 0 -#define PIPE_IN 1 - -namespace { - -using namespace mbgl::util; - -int looperCallbackNew(int fd, int, void* data) { - int buffer[1]; - while (read(fd, buffer, sizeof(buffer)) > 0) {} - - auto runLoopImpl = reinterpret_cast(data); - - runLoopImpl->coalesce.clear(); - ALooper_wake(runLoopImpl->loop); - - return 1; -} - -int looperCallbackDefault(int fd, int, void* data) { - int buffer[1]; - while (read(fd, buffer, sizeof(buffer)) > 0) {} - - auto runLoopImpl = reinterpret_cast(data); - - runLoopImpl->coalesce.clear(); - runLoopImpl->runLoop->runOnce(); - - if (!runLoopImpl->running) { - ALooper_wake(runLoopImpl->loop); - } - - return 1; -} - -} // namespace - -namespace mbgl { -namespace util { - -// This is needed only for the RunLoop living on the main thread because of -// how we implement timers. We sleep on `ALooper_pollAll` until the next -// timeout, but on the main thread `ALooper_pollAll` is called by the activity -// automatically, thus we cannot set the timeout. Instead we wake the loop -// with an external file descriptor event coming from this thread. -// -// Usually an actor should not carry pointers to other threads, but in -// this case the RunLoop itself owns the Alarm and calling wake() is the most -// efficient way of waking up the RunLoop and it is also thread-safe. -class Alarm { -public: - Alarm(ActorRef, RunLoop::Impl* loop_) : loop(loop_) {} - - void set(const Milliseconds& timeout) { - alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); }); - } - -private: - Timer alarm; - RunLoop::Impl* loop; -}; - -RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) { - loop = ALooper_prepare(0); - assert(loop); - - ALooper_acquire(loop); - - if (pipe(fds)) { - throw std::runtime_error("Failed to create pipe."); - } - - if (fcntl(fds[PIPE_OUT], F_SETFL, O_NONBLOCK)) { - throw std::runtime_error("Failed to set pipe read end non-blocking."); - } - - int ret = 0; - - switch (type) { - case Type::New: - ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, - ALOOPER_EVENT_INPUT, looperCallbackNew, this); - break; - case Type::Default: - ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, - ALOOPER_EVENT_INPUT, looperCallbackDefault, this); - alarm = std::make_unique>("Alarm", this); - running = true; - break; - } - - if (ret != 1) { - throw std::runtime_error("Failed to add file descriptor to Looper."); - } -} - -RunLoop::Impl::~Impl() { - alarm.reset(); - - if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) { - Log::Error(mbgl::Event::General, "Failed to remove file descriptor from Looper"); - } - - if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) { - Log::Error(mbgl::Event::General, "Failed to close file descriptor."); - } - - ALooper_release(loop); -} - -void RunLoop::Impl::wake() { - if (coalesce.test_and_set(std::memory_order_acquire)) { - return; - } - - if (write(fds[PIPE_IN], "\n", 1) == -1) { - throw std::runtime_error("Failed to write to file descriptor."); - } -} - -void RunLoop::Impl::addRunnable(Runnable* runnable) { - { - std::lock_guard lock(mutex); - runnables.push_back(runnable); - } - - wake(); -} - -void RunLoop::Impl::removeRunnable(Runnable* runnable) { - std::lock_guard lock(mutex); - runnables.remove(runnable); -} - -Milliseconds RunLoop::Impl::processRunnables() { - auto now = Clock::now(); - auto nextDue = TimePoint::max(); - std::list tmp; - { - std::lock_guard lock(mutex); - - // O(N) but in the render thread where we get tons - // of messages, the size of the list is usually 1~2. - auto it = runnables.begin(); - while (it != runnables.end()) { - Runnable* runnable = *it; - - auto const dueTime = runnable->dueTime(); - if (dueTime <= now) { - tmp.push_back(runnable); - runnables.erase(it++); - } else { - nextDue = std::min(nextDue, dueTime); - ++it; - } - } - } - - for (auto runnable : tmp) { - runnable->runTask(); - } - - if (runnables.empty() || nextDue == TimePoint::max()) { - return Milliseconds(-1); - } - - auto timeout = std::chrono::duration_cast(nextDue - now); - if (alarm) { - alarm->actor().invoke(&Alarm::set, timeout); - } - - return timeout; -} - -RunLoop* RunLoop::Get() { - assert(static_cast(Scheduler::GetCurrent())); - return static_cast(Scheduler::GetCurrent()); -} - -RunLoop::RunLoop(Type type) : impl(std::make_unique(this, type)) { - Scheduler::SetCurrent(this); -} - -RunLoop::~RunLoop() { - Scheduler::SetCurrent(nullptr); -} - -LOOP_HANDLE RunLoop::getLoopHandle() { - return Get()->impl.get(); -} - -void RunLoop::wake() { - impl->wake(); -} - -void RunLoop::run() { - MBGL_VERIFY_THREAD(tid); - - impl->running = true; - - int outFd, outEvents; - char *outData = nullptr; - - while (impl->running) { - process(); - auto timeout = impl->processRunnables().count(); - ALooper_pollAll(timeout, &outFd, &outEvents, reinterpret_cast(&outData)); - } -} - -void RunLoop::runOnce() { - MBGL_VERIFY_THREAD(tid); - - process(); - impl->processRunnables(); -} - -void RunLoop::stop() { - invoke([&] { - impl->running = false; - impl->wake(); - }); -} - -void RunLoop::addWatch(int, Event, std::function&&) { - throw std::runtime_error("Not implemented."); -} - -void RunLoop::removeWatch(int) { - throw std::runtime_error("Not implemented."); -} - -} // namespace util -} // namespace mbgl diff --git a/src/run_loop_impl.hpp b/src/run_loop_impl.hpp deleted file mode 100644 index c6a1b23a7..000000000 --- a/src/run_loop_impl.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "jni.hpp" - -#include -#include - -#include -#include -#include -#include - -struct ALooper; - -namespace mbgl { -namespace util { - -template class Thread; -class Alarm; - -class RunLoop::Impl { -public: - class Runnable { - public: - virtual ~Runnable() = default; - - virtual void runTask() = 0; - virtual TimePoint dueTime() const = 0; - }; - - Impl(RunLoop*, RunLoop::Type); - ~Impl(); - - void wake(); - - void addRunnable(Runnable*); - void removeRunnable(Runnable*); - - Milliseconds processRunnables(); - - ALooper* loop = nullptr; - RunLoop* runLoop = nullptr; - std::atomic running; - std::atomic_flag coalesce = ATOMIC_FLAG_INIT; - -private: - friend RunLoop; - - int fds[2]; - - std::unique_ptr> alarm; - - std::mutex mutex; - std::list runnables; -}; - -} // namespace util -} // namespace mbgl diff --git a/src/snapshotter/map_snapshot.cpp b/src/snapshotter/map_snapshot.cpp deleted file mode 100644 index 1650f72dc..000000000 --- a/src/snapshotter/map_snapshot.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "map_snapshot.hpp" - -#include "../bitmap.hpp" -#include "../conversion/collection.hpp" - -#include - -namespace mbgl { -namespace android { - -MapSnapshot::MapSnapshot(float pixelRatio_, MapSnapshot::PointForFn pointForFn_, MapSnapshot::LatLngForFn latLngForFn_) - : pixelRatio(pixelRatio_) - , pointForFn(std::move(pointForFn_)) - , latLngForFn(std::move(latLngForFn_)) { -} - -MapSnapshot::~MapSnapshot() = default; - -jni::Local> MapSnapshot::pixelForLatLng(jni::JNIEnv& env, jni::Object& jLatLng) { - ScreenCoordinate point = pointForFn(LatLng::getLatLng(env, jLatLng)); - return PointF::New(env, point.x * pixelRatio, point.y * pixelRatio); -} - -jni::Local> MapSnapshot::latLngForPixel(jni::JNIEnv& env, jni::Object& jPoint) { - return LatLng::New(env, latLngForFn(PointF::getScreenCoordinate(env, jPoint))); -} - -// Static methods // - -jni::Local> MapSnapshot::New(JNIEnv& env, - PremultipliedImage&& image, - float pixelRatio, - std::vector attributions, - bool showLogo, - mbgl::MapSnapshotter::PointForFn pointForFn, - mbgl::MapSnapshotter::LatLngForFn latLngForFn) { - // Create the bitmap - auto bitmap = Bitmap::CreateBitmap(env, std::move(image)); - - // Create the Mapsnapshot peers - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor, jni::Array, jni::jboolean>(env); - auto nativePeer = std::make_unique(pixelRatio, pointForFn, latLngForFn); - return javaClass.New(env, constructor, reinterpret_cast(nativePeer.release()), bitmap, conversion::toArray(env, attributions), (jni::jboolean) showLogo); -} - -void MapSnapshot::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - -#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, javaClass, - "nativePtr", - std::make_unique, - "initialize", - "finalize", - METHOD(&MapSnapshot::latLngForPixel, "latLngForPixel"), - METHOD(&MapSnapshot::pixelForLatLng, "pixelForLatLng") - ); -} - -} // namespace android -} // namespace mbgl diff --git a/src/snapshotter/map_snapshot.hpp b/src/snapshotter/map_snapshot.hpp deleted file mode 100644 index 6b82d0283..000000000 --- a/src/snapshotter/map_snapshot.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -#include - -#include "../geometry/lat_lng.hpp" -#include "../graphics/pointf.hpp" - -#include -#include - -namespace mbgl { -namespace android { - -class MapSnapshot { -public: - - using PointForFn = mbgl::MapSnapshotter::PointForFn; - using LatLngForFn = mbgl::MapSnapshotter::LatLngForFn; - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshot"; }; - - static void registerNative(jni::JNIEnv&); - - static jni::Local> New(JNIEnv& env, - PremultipliedImage&& image, - float pixelRatio, - std::vector attributions, - bool showLogo, - PointForFn pointForFn, - LatLngForFn latLngForFn); - - MapSnapshot(jni::JNIEnv&) {}; - MapSnapshot(float pixelRatio, PointForFn, LatLngForFn); - ~MapSnapshot(); - - jni::Local> pixelForLatLng(jni::JNIEnv&, jni::Object&); - jni::Local> latLngForPixel(jni::JNIEnv&, jni::Object&); - -private: - float pixelRatio; - mbgl::MapSnapshotter::PointForFn pointForFn; - mbgl::MapSnapshotter::LatLngForFn latLngForFn; -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/snapshotter/map_snapshotter.cpp b/src/snapshotter/map_snapshotter.cpp deleted file mode 100644 index 0b38269ad..000000000 --- a/src/snapshotter/map_snapshotter.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "map_snapshotter.hpp" - -#include -#include -#include -#include -#include - -#include "../attach_env.hpp" -#include "map_snapshot.hpp" - -namespace mbgl { -namespace android { - -MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, - const jni::Object& _obj, - const jni::Object& _jFileSource, - jni::jfloat _pixelRatio, - jni::jint width, - jni::jint height, - const jni::String& styleURL, - const jni::String& styleJSON, - const jni::Object& region, - const jni::Object& position, - jni::jboolean _showLogo, - const jni::String& _localIdeographFontFamily) - : javaPeer(_env, _obj) - , pixelRatio(_pixelRatio) { - - // Get a reference to the JavaVM for callbacks - if (_env.GetJavaVM(&vm) < 0) { - _env.ExceptionDescribe(); - return; - } - - jFileSource = FileSource::getNativePeer(_env, _jFileSource); - auto size = mbgl::Size { static_cast(width), static_cast(height) }; - - optional cameraOptions; - if (position) { - cameraOptions = CameraPosition::getCameraOptions(_env, position, pixelRatio); - } - - optional bounds; - if (region) { - bounds = LatLngBounds::getLatLngBounds(_env, region); - } - - std::pair style; - if (styleJSON) { - style = std::make_pair(true, jni::Make(_env, styleJSON)); - } else { - style = std::make_pair(false, jni::Make(_env, styleURL)); - } - - showLogo = _showLogo; - // Create the core snapshotter - snapshotter = std::make_unique(style, - size, - pixelRatio, - cameraOptions, - bounds, - _localIdeographFontFamily ? - jni::Make(_env, _localIdeographFontFamily) : - optional{}, - mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource)); -} - -MapSnapshotter::~MapSnapshotter() = default; - -void MapSnapshotter::start(JNIEnv& env) { - MBGL_VERIFY_THREAD(tid); - activateFilesource(env); - - snapshotCallback = std::make_unique>( - *Scheduler::GetCurrent(), - [this](std::exception_ptr err, PremultipliedImage image, std::vector attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn) { - MBGL_VERIFY_THREAD(tid); - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - - if (err) { - // error handler callback - static auto onSnapshotFailed = javaClass.GetMethod(*_env, "onSnapshotFailed"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onSnapshotFailed, jni::Make(*_env, util::toString(err))); - } - } else { - // Create the wrapper - auto mapSnapshot = android::MapSnapshot::New(*_env, std::move(image), pixelRatio, attributions, showLogo, pointForFn, latLngForFn); - - // invoke callback - static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - weakReference.Call(*_env, onSnapshotReady, mapSnapshot); - } - } - - deactivateFilesource(*_env); - }); - - snapshotter->snapshot(snapshotCallback->self()); -} - -void MapSnapshotter::cancel(JNIEnv& env) { - MBGL_VERIFY_THREAD(tid); - snapshotCallback.reset(); - deactivateFilesource(env); -} - -void MapSnapshotter::setStyleUrl(JNIEnv& env, const jni::String& styleURL) { - snapshotter->setStyleURL(jni::Make(env, styleURL)); -} - -void MapSnapshotter::setStyleJson(JNIEnv& env, const jni::String& styleJSON) { - snapshotter->setStyleJSON(jni::Make(env, styleJSON)); -} - -void MapSnapshotter::setSize(JNIEnv&, jni::jint width, jni::jint height) { - auto size = mbgl::Size { static_cast(width), static_cast(height) }; - snapshotter->setSize(size); -} - -void MapSnapshotter::setCameraPosition(JNIEnv& env, const jni::Object& position) { - auto options = CameraPosition::getCameraOptions(env, position, pixelRatio); - snapshotter->setCameraOptions(options); -} - -void MapSnapshotter::setRegion(JNIEnv& env, const jni::Object& region) { - snapshotter->setRegion(LatLngBounds::getLatLngBounds(env, region)); -} - - -// Private methods // - -void MapSnapshotter::activateFilesource(JNIEnv& env) { - if (!activatedFilesource) { - activatedFilesource = true; - jFileSource->resume(env); - } -} - -void MapSnapshotter::deactivateFilesource(JNIEnv& env) { - if (activatedFilesource) { - activatedFilesource = false; - jFileSource->pause(env); - } -} - -// Static methods // - -void MapSnapshotter::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - -#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - jni::MakePeer&, const jni::Object&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object&, const jni::Object&, jni::jboolean, const jni::String&>, - "nativeInitialize", - "finalize", - METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"), - METHOD(&MapSnapshotter::setStyleJson, "setStyleJson"), - METHOD(&MapSnapshotter::setSize, "setSize"), - METHOD(&MapSnapshotter::setCameraPosition, "setCameraPosition"), - METHOD(&MapSnapshotter::setRegion, "setRegion"), - METHOD(&MapSnapshotter::start, "nativeStart"), - METHOD(&MapSnapshotter::cancel, "nativeCancel") - ); -} - -} // namespace android -} // namespace mbgl diff --git a/src/snapshotter/map_snapshotter.hpp b/src/snapshotter/map_snapshotter.hpp deleted file mode 100644 index 608a4c855..000000000 --- a/src/snapshotter/map_snapshotter.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include - -#include "../file_source.hpp" -#include "../geometry/lat_lng_bounds.hpp" -#include "../map/camera_position.hpp" - -#include - -#include - -namespace mbgl { -namespace android { - -class SnapshotterRendererFrontend; - -class MapSnapshotter { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshotter"; }; - - static void registerNative(jni::JNIEnv&); - - MapSnapshotter(jni::JNIEnv&, - const jni::Object&, - const jni::Object&, - jni::jfloat pixelRatio, - jni::jint width, - jni::jint height, - const jni::String& styleURL, - const jni::String& styleJSON, - const jni::Object& region, - const jni::Object& position, - jni::jboolean showLogo, - const jni::String& localIdeographFontFamily); - - ~MapSnapshotter(); - - void setStyleUrl(JNIEnv&, const jni::String& styleURL); - - void setStyleJson(JNIEnv&, const jni::String& styleJSON); - - void setSize(JNIEnv&, jni::jint width, jni::jint height); - - void setCameraPosition(JNIEnv&, const jni::Object& position); - - void setRegion(JNIEnv&, const jni::Object& region); - - void start(JNIEnv&); - - void cancel(JNIEnv&); - -private: - MBGL_STORE_THREAD(tid); - - JavaVM *vm = nullptr; - jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; - - float pixelRatio; - bool showLogo; - - std::unique_ptr> snapshotCallback; - std::unique_ptr snapshotter; - - FileSource *jFileSource; - void activateFilesource(JNIEnv&); - void deactivateFilesource(JNIEnv&); - bool activatedFilesource = false; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/string_util.cpp b/src/string_util.cpp deleted file mode 100644 index f02155caf..000000000 --- a/src/string_util.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "attach_env.hpp" -#include - -namespace mbgl { -namespace platform { - -std::string uppercase(const std::string& str) { - auto env{ android::AttachEnv() }; - jni::Local value = jni::Make(*env, str.c_str()); - static auto toUpperCase = jni::Class::Singleton(*env).GetMethod(*env, "toUpperCase"); - auto result = value.Call(*env, toUpperCase); - return jni::Make(*env, result); -} - -std::string lowercase(const std::string& str) { - auto env{ android::AttachEnv() }; - jni::Local value = jni::Make(*env, str.c_str()); - static auto toLowerCase = jni::Class::Singleton(*env).GetMethod(*env, "toLowerCase"); - auto result = value.Call(*env, toLowerCase); - return jni::Make(*env, result); -} - -} // namespace platform -} // namespace mbgl diff --git a/src/style/android_conversion.hpp b/src/style/android_conversion.hpp deleted file mode 100644 index dc0a0acb3..000000000 --- a/src/style/android_conversion.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include "value.hpp" - -#include -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -class ConversionTraits { -public: - static bool isUndefined(const mbgl::android::Value& value) { - return value.isNull(); - } - - static bool isArray(const mbgl::android::Value& value) { - return value.isArray(); - } - - static bool isObject(const mbgl::android::Value& value) { - return value.isObject(); - } - - static std::size_t arrayLength(const mbgl::android::Value& value) { - return value.getLength();; - } - - static mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { - return value.get(i); - } - - static optional objectMember(const mbgl::android::Value& value, const char* key) { - mbgl::android::Value member = value.get(key); - if (!member.isNull()) { - return member; - } else { - return {}; - } - } - - template - static optional eachMember(const mbgl::android::Value& value, Fn&& fn) { - assert(value.isObject()); - mbgl::android::Value keys = value.keyArray(); - std::size_t length = arrayLength(keys); - for(std::size_t i = 0; i < length; ++i){ - const auto k = keys.get(i).toString(); - auto v = value.get(k.c_str()); - optional result = fn(k, std::move(v)); - if (result) { - return result; - } - } - return {}; - } - - static optional toBool(const mbgl::android::Value& value) { - if (value.isBool()) { - return value.toBool(); - } else { - return {}; - } - } - - static optional toNumber(const mbgl::android::Value& value) { - if (value.isNumber()) { - auto num = value.toFloat(); - return num; - } else { - return {}; - } - } - - static optional toDouble(const mbgl::android::Value& value) { - if (value.isNumber()) { - return value.toDouble(); - } else { - return {}; - } - } - - static optional toString(const mbgl::android::Value& value) { - if (value.isString()) { - return value.toString(); - } else { - return {}; - } - } - - static optional toValue(const mbgl::android::Value& value) { - if (value.isNull()) { - return {}; - } else if (value.isBool()) { - return { value.toBool() }; - } else if (value.isString()) { - return { value.toString() }; - } else if (value.isNumber()) { - return { value.toDouble() }; - } else { - return {}; - } - } - - static optional toGeoJSON(const mbgl::android::Value &value, Error &error) { - if (value.isNull() || !value.isString()) { - error = { "no json data found" }; - return {}; - } - return parseGeoJSON(value.toString(), error); - } -}; - -template -optional convert(mbgl::android::Value&& value, Error& error, Args&&...args) { - return convert(Convertible(std::move(value)), error, std::forward(args)...); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/style/conversion/filter.cpp b/src/style/conversion/filter.cpp deleted file mode 100644 index d15e2747a..000000000 --- a/src/style/conversion/filter.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "filter.hpp" -#include "../android_conversion.hpp" - -#include -#include - -namespace mbgl { -namespace android { -namespace conversion { - -optional toFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { - mbgl::optional filter; - if (jfilter) { - mbgl::style::conversion::Error error; - auto converted = mbgl::style::conversion::convert(Value(env, jfilter), error); - if (!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); - } - filter = std::move(*converted); - } - return filter; -} - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/src/style/conversion/filter.hpp b/src/style/conversion/filter.hpp deleted file mode 100644 index 920d336a1..000000000 --- a/src/style/conversion/filter.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -optional toFilter(jni::JNIEnv&, const jni::Array>&); - -} // namespace conversion -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/conversion/position.cpp b/src/style/conversion/position.cpp deleted file mode 100644 index e3c334afd..000000000 --- a/src/style/conversion/position.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "position.hpp" - -namespace mbgl { -namespace android { -namespace conversion { - -Result>> Converter>, mbgl::style::Position>::operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { - std::array cartPosition = value.getSpherical(); - return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); -} - -Result Converter>::operator()(jni::JNIEnv &env, const jni::Object &value) const { - float radialCoordinate = Position::getRadialCoordinate(env, value); - float azimuthalAngle = Position::getAzimuthalAngle(env, value); - float polarAngle = Position::getPolarAngle(env, value); - std::array cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; - mbgl::style::Position position{}; - position.set(cartPosition); - return position; -} - -} -} -} diff --git a/src/style/conversion/position.hpp b/src/style/conversion/position.hpp deleted file mode 100644 index 90409d527..000000000 --- a/src/style/conversion/position.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../../conversion/conversion.hpp" -#include "../position.hpp" - -#include -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter>, mbgl::style::Position> { - Result>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const; -}; - -template <> -struct Converter> { - Result operator()(jni::JNIEnv &env, const jni::Object &value) const; -}; - -} -} -} diff --git a/src/style/conversion/property_expression.hpp b/src/style/conversion/property_expression.hpp deleted file mode 100644 index 4e26b11f9..000000000 --- a/src/style/conversion/property_expression.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "../../conversion/conversion.hpp" -#include "../../gson/json_element.hpp" - -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template -struct Converter>, mbgl::style::PropertyExpression> { - Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyExpression& value) const { - return gson::JsonElement::New(env, value.getExpression().serialize()); - } -}; - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/src/style/conversion/property_value.hpp b/src/style/conversion/property_value.hpp deleted file mode 100644 index 317705a28..000000000 --- a/src/style/conversion/property_value.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include - -#include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" -#include "property_expression.hpp" - -namespace mbgl { -namespace android { -namespace conversion { - -/** - * Conversion from core property value types to Java property value types - */ -template -class PropertyValueEvaluator { -public: - PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {} - - jni::Local> operator()(const mbgl::style::Undefined) const { - return jni::Local>(env, nullptr); - } - - jni::Local> operator()(const T& value) const { - return std::move(*convert>>(env, value)); - } - - jni::Local> operator()(const mbgl::style::PropertyExpression& value) const { - return std::move(*convert>>(env, value)); - } - -private: - jni::JNIEnv& env; -}; - -/** - * Convert core property values to java - */ -template -struct Converter>, mbgl::style::PropertyValue> { - Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue& value) const { - PropertyValueEvaluator evaluator(env); - return value.evaluate(evaluator); - } -}; - -/** - * Convert core heat map color property value to java - */ -template <> -struct Converter>, mbgl::style::ColorRampPropertyValue> { - Result>> operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue& value) const { - PropertyValueEvaluator evaluator(env); - return std::move(*convert>>(env, value.evaluate(evaluator))); - } -}; - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/src/style/conversion/transition_options.cpp b/src/style/conversion/transition_options.cpp deleted file mode 100644 index 75d9b4cc0..000000000 --- a/src/style/conversion/transition_options.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "transition_options.hpp" - -namespace mbgl { -namespace android { -namespace conversion { - -Result>> Converter>, mbgl::style::TransitionOptions>::operator()(jni::JNIEnv& env, const mbgl::style::TransitionOptions& value) const { - return TransitionOptions::fromTransitionOptions(env, - std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())).count(), - std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())).count(), - (jboolean) value.enablePlacementTransitions - ); -} - -} -} -} diff --git a/src/style/conversion/transition_options.hpp b/src/style/conversion/transition_options.hpp deleted file mode 100644 index 06c042922..000000000 --- a/src/style/conversion/transition_options.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "../../conversion/conversion.hpp" -#include "../transition_options.hpp" - -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template<> -struct Converter>, mbgl::style::TransitionOptions> { - Result>> operator()(jni::JNIEnv&, const mbgl::style::TransitionOptions&) const; -}; - -} -} -} diff --git a/src/style/conversion/url_or_tileset.cpp b/src/style/conversion/url_or_tileset.cpp deleted file mode 100644 index 2ec585675..000000000 --- a/src/style/conversion/url_or_tileset.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "url_or_tileset.hpp" -#include "../android_conversion.hpp" - -#include -#include - -namespace mbgl { -namespace android { - -// This conversion is expected not to fail because it's used only in contexts where -// the value was originally a String or TileSet object on the Java side. If it fails -// to convert, it's a bug in our serialization or Java-side static typing. -variant convertURLOrTileset(mbgl::android::Value&& value) { - using namespace mbgl::style::conversion; - - const Convertible convertible(std::move(value)); - if (isObject(convertible)) { - Error error; - optional tileset = convert(convertible, error); - if (!tileset) { - throw std::logic_error(error.message); - } - return { *tileset }; - } else { - return { *toString(convertible) }; - } -} - -} -} diff --git a/src/style/conversion/url_or_tileset.hpp b/src/style/conversion/url_or_tileset.hpp deleted file mode 100644 index f42a9b9a2..000000000 --- a/src/style/conversion/url_or_tileset.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "../value.hpp" - -namespace mbgl { -namespace android { - -variant convertURLOrTileset(mbgl::android::Value&& value); - -} -} diff --git a/src/style/formatted.cpp b/src/style/formatted.cpp deleted file mode 100644 index 69c3454e2..000000000 --- a/src/style/formatted.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "formatted.hpp" -#include "formatted_section.hpp" -#include "../conversion/conversion.hpp" -#include "../conversion/constant.hpp" - -namespace mbgl { -namespace android { - -void Formatted::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> Formatted::New(jni::JNIEnv& env, const style::expression::Formatted& value) { - static auto& formatted = jni::Class::Singleton(env); - static auto formattedConstructor = formatted.GetConstructor>>(env); - static auto& formattedSectionClass = jni::Class::Singleton(env); - - auto sections = jni::Array>::New(env, value.sections.size()); - for (std::size_t i = 0; i < value.sections.size(); i++) { - auto section = value.sections.at(i); - auto text = jni::Make(env, section.text); - static auto formattedSectionConstructor = formattedSectionClass.GetConstructor(env); - auto formattedSection = formattedSectionClass.New(env, formattedSectionConstructor, text); - - if (section.fontScale) { - double fontScale = section.fontScale.value(); - static auto method = formattedSectionClass.GetMethod(env, "setFontScale"); - formattedSection.Call(env, method, jni::Box(env, fontScale)); - } - - if (section.fontStack) { - auto fontStack = jni::Array::New(env, section.fontStack.value().size()); - for (std::size_t j = 0; j < section.fontStack.value().size(); j++) { - fontStack.Set(env, j, jni::Make(env, section.fontStack.value().at(j))); - } - static auto method = formattedSectionClass.GetMethod)>(env, "setFontStack"); - formattedSection.Call(env, method, fontStack); - } - - if (section.textColor) { - using namespace mbgl::android::conversion; - auto textColor = std::move(*convert>>(env, *section.textColor)); - static auto method = formattedSectionClass.GetMethod)>(env, "setTextColor"); - formattedSection.Call(env, method, textColor); - } - - sections.Set(env, i, formattedSection); - } - - return formatted.New(env, formattedConstructor, sections); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted.hpp b/src/style/formatted.hpp deleted file mode 100644 index ca91f6562..000000000 --- a/src/style/formatted.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace mbgl { - namespace android { - - using SuperTag = jni::ObjectTag; - class Formatted : private mbgl::util::noncopyable { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/Formatted"; }; - - static jni::Local> - New(jni::JNIEnv&, const style::expression::Formatted &value); - - static void registerNative(jni::JNIEnv &); - }; - - } // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted_section.cpp b/src/style/formatted_section.cpp deleted file mode 100644 index ddcf76f81..000000000 --- a/src/style/formatted_section.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "formatted_section.hpp" - -namespace mbgl { -namespace android { - -void FormattedSection::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/formatted_section.hpp b/src/style/formatted_section.hpp deleted file mode 100644 index f759a94e8..000000000 --- a/src/style/formatted_section.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class FormattedSection : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/FormattedSection"; }; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/layers/background_layer.cpp b/src/style/layers/background_layer.cpp deleted file mode 100644 index e28fd0798..000000000 --- a/src/style/layers/background_layer.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "background_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::BackgroundLayer& toBackgroundLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String& layerId) - : Layer(std::make_unique(jni::Make(env, layerId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - BackgroundLayer::BackgroundLayer(mbgl::Map& map, mbgl::style::BackgroundLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - BackgroundLayer::BackgroundLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - BackgroundLayer::~BackgroundLayer() = default; - - // Property getters - - jni::Local> BackgroundLayer::getBackgroundColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundColor())); - } - - jni::Local> BackgroundLayer::getBackgroundColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundColorTransition(); - return std::move(*convert>>(env, options)); - } - - void BackgroundLayer::setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toBackgroundLayer(layer).setBackgroundColorTransition(options); - } - - jni::Local> BackgroundLayer::getBackgroundPattern(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundPattern())); - } - - jni::Local> BackgroundLayer::getBackgroundPatternTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundPatternTransition(); - return std::move(*convert>>(env, options)); - } - - void BackgroundLayer::setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toBackgroundLayer(layer).setBackgroundPatternTransition(options); - } - - jni::Local> BackgroundLayer::getBackgroundOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundOpacity())); - } - - jni::Local> BackgroundLayer::getBackgroundOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void BackgroundLayer::setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toBackgroundLayer(layer).setBackgroundOpacityTransition(options); - } - - - // BackgroundJavaLayerPeerFactory - - BackgroundJavaLayerPeerFactory::~BackgroundJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new BackgroundLayer(map, toBackgroundLayer(layer))); - } - - jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new BackgroundLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void BackgroundJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&BackgroundLayer::getBackgroundColorTransition, "nativeGetBackgroundColorTransition"), - METHOD(&BackgroundLayer::setBackgroundColorTransition, "nativeSetBackgroundColorTransition"), - METHOD(&BackgroundLayer::getBackgroundColor, "nativeGetBackgroundColor"), - METHOD(&BackgroundLayer::getBackgroundPatternTransition, "nativeGetBackgroundPatternTransition"), - METHOD(&BackgroundLayer::setBackgroundPatternTransition, "nativeSetBackgroundPatternTransition"), - METHOD(&BackgroundLayer::getBackgroundPattern, "nativeGetBackgroundPattern"), - METHOD(&BackgroundLayer::getBackgroundOpacityTransition, "nativeGetBackgroundOpacityTransition"), - METHOD(&BackgroundLayer::setBackgroundOpacityTransition, "nativeSetBackgroundOpacityTransition"), - METHOD(&BackgroundLayer::getBackgroundOpacity, "nativeGetBackgroundOpacity")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/background_layer.hpp b/src/style/layers/background_layer.hpp deleted file mode 100644 index 654031c6f..000000000 --- a/src/style/layers/background_layer.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class BackgroundLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/BackgroundLayer"; }; - - BackgroundLayer(jni::JNIEnv&, jni::String&); - - BackgroundLayer(mbgl::Map&, mbgl::style::BackgroundLayer&); - - BackgroundLayer(mbgl::Map&, std::unique_ptr); - - ~BackgroundLayer(); - - // Properties - - jni::Local> getBackgroundColor(jni::JNIEnv&); - void setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getBackgroundColorTransition(jni::JNIEnv&); - - jni::Local> getBackgroundPattern(jni::JNIEnv&); - void setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getBackgroundPatternTransition(jni::JNIEnv&); - - jni::Local> getBackgroundOpacity(jni::JNIEnv&); - void setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getBackgroundOpacityTransition(jni::JNIEnv&); - -}; // class BackgroundLayer - -class BackgroundJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::BackgroundLayerFactory { -public: - ~BackgroundJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class BackgroundJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/circle_layer.cpp b/src/style/layers/circle_layer.cpp deleted file mode 100644 index f460031dc..000000000 --- a/src/style/layers/circle_layer.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "circle_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::CircleLayer& toCircleLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - CircleLayer::CircleLayer(mbgl::Map& map, mbgl::style::CircleLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - CircleLayer::CircleLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - CircleLayer::~CircleLayer() = default; - - // Property getters - - jni::Local> CircleLayer::getCircleRadius(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleRadius())); - } - - jni::Local> CircleLayer::getCircleRadiusTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleRadiusTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleRadiusTransition(options); - } - - jni::Local> CircleLayer::getCircleColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleColor())); - } - - jni::Local> CircleLayer::getCircleColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleColorTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleColorTransition(options); - } - - jni::Local> CircleLayer::getCircleBlur(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleBlur())); - } - - jni::Local> CircleLayer::getCircleBlurTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleBlurTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleBlurTransition(options); - } - - jni::Local> CircleLayer::getCircleOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleOpacity())); - } - - jni::Local> CircleLayer::getCircleOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleOpacityTransition(options); - } - - jni::Local> CircleLayer::getCircleTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslate())); - } - - jni::Local> CircleLayer::getCircleTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleTranslateTransition(options); - } - - jni::Local> CircleLayer::getCircleTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslateAnchor())); - } - - jni::Local> CircleLayer::getCirclePitchScale(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchScale())); - } - - jni::Local> CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchAlignment())); - } - - jni::Local> CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeWidth())); - } - - jni::Local> CircleLayer::getCircleStrokeWidthTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeWidthTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleStrokeWidthTransition(options); - } - - jni::Local> CircleLayer::getCircleStrokeColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeColor())); - } - - jni::Local> CircleLayer::getCircleStrokeColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeColorTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleStrokeColorTransition(options); - } - - jni::Local> CircleLayer::getCircleStrokeOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeOpacity())); - } - - jni::Local> CircleLayer::getCircleStrokeOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void CircleLayer::setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toCircleLayer(layer).setCircleStrokeOpacityTransition(options); - } - - - // CircleJavaLayerPeerFactory - - CircleJavaLayerPeerFactory::~CircleJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new CircleLayer(map, toCircleLayer(layer))); - } - - jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new CircleLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void CircleJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&CircleLayer::getCircleRadiusTransition, "nativeGetCircleRadiusTransition"), - METHOD(&CircleLayer::setCircleRadiusTransition, "nativeSetCircleRadiusTransition"), - METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"), - METHOD(&CircleLayer::getCircleColorTransition, "nativeGetCircleColorTransition"), - METHOD(&CircleLayer::setCircleColorTransition, "nativeSetCircleColorTransition"), - METHOD(&CircleLayer::getCircleColor, "nativeGetCircleColor"), - METHOD(&CircleLayer::getCircleBlurTransition, "nativeGetCircleBlurTransition"), - METHOD(&CircleLayer::setCircleBlurTransition, "nativeSetCircleBlurTransition"), - METHOD(&CircleLayer::getCircleBlur, "nativeGetCircleBlur"), - METHOD(&CircleLayer::getCircleOpacityTransition, "nativeGetCircleOpacityTransition"), - METHOD(&CircleLayer::setCircleOpacityTransition, "nativeSetCircleOpacityTransition"), - METHOD(&CircleLayer::getCircleOpacity, "nativeGetCircleOpacity"), - METHOD(&CircleLayer::getCircleTranslateTransition, "nativeGetCircleTranslateTransition"), - METHOD(&CircleLayer::setCircleTranslateTransition, "nativeSetCircleTranslateTransition"), - METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"), - METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"), - METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"), - METHOD(&CircleLayer::getCirclePitchAlignment, "nativeGetCirclePitchAlignment"), - METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"), - METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"), - METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"), - METHOD(&CircleLayer::getCircleStrokeColorTransition, "nativeGetCircleStrokeColorTransition"), - METHOD(&CircleLayer::setCircleStrokeColorTransition, "nativeSetCircleStrokeColorTransition"), - METHOD(&CircleLayer::getCircleStrokeColor, "nativeGetCircleStrokeColor"), - METHOD(&CircleLayer::getCircleStrokeOpacityTransition, "nativeGetCircleStrokeOpacityTransition"), - METHOD(&CircleLayer::setCircleStrokeOpacityTransition, "nativeSetCircleStrokeOpacityTransition"), - METHOD(&CircleLayer::getCircleStrokeOpacity, "nativeGetCircleStrokeOpacity")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/circle_layer.hpp b/src/style/layers/circle_layer.hpp deleted file mode 100644 index 191b3924f..000000000 --- a/src/style/layers/circle_layer.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class CircleLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CircleLayer"; }; - - CircleLayer(jni::JNIEnv&, jni::String&, jni::String&); - - CircleLayer(mbgl::Map&, mbgl::style::CircleLayer&); - - CircleLayer(mbgl::Map&, std::unique_ptr); - - ~CircleLayer(); - - // Properties - - jni::Local> getCircleRadius(jni::JNIEnv&); - void setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleRadiusTransition(jni::JNIEnv&); - - jni::Local> getCircleColor(jni::JNIEnv&); - void setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleColorTransition(jni::JNIEnv&); - - jni::Local> getCircleBlur(jni::JNIEnv&); - void setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleBlurTransition(jni::JNIEnv&); - - jni::Local> getCircleOpacity(jni::JNIEnv&); - void setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleOpacityTransition(jni::JNIEnv&); - - jni::Local> getCircleTranslate(jni::JNIEnv&); - void setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleTranslateTransition(jni::JNIEnv&); - - jni::Local> getCircleTranslateAnchor(jni::JNIEnv&); - - jni::Local> getCirclePitchScale(jni::JNIEnv&); - - jni::Local> getCirclePitchAlignment(jni::JNIEnv&); - - jni::Local> getCircleStrokeWidth(jni::JNIEnv&); - void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleStrokeWidthTransition(jni::JNIEnv&); - - jni::Local> getCircleStrokeColor(jni::JNIEnv&); - void setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleStrokeColorTransition(jni::JNIEnv&); - - jni::Local> getCircleStrokeOpacity(jni::JNIEnv&); - void setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getCircleStrokeOpacityTransition(jni::JNIEnv&); - -}; // class CircleLayer - -class CircleJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CircleLayerFactory { -public: - ~CircleJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class CircleJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/custom_layer.cpp b/src/style/layers/custom_layer.cpp deleted file mode 100644 index 3f44aa850..000000000 --- a/src/style/layers/custom_layer.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "custom_layer.hpp" - -#include - -#include - -namespace mbgl { -namespace android { - - CustomLayer::CustomLayer(jni::JNIEnv& env, const jni::String& layerId, jni::jlong host) - : Layer(std::make_unique( - jni::Make(env, layerId), - std::unique_ptr(reinterpret_cast(host))) - ) { - } - - CustomLayer::CustomLayer(mbgl::Map& map, mbgl::style::CustomLayer& coreLayer) - : Layer(map, coreLayer) { - } - - CustomLayer::CustomLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - CustomLayer::~CustomLayer() = default; - - void CustomLayer::update(jni::JNIEnv&) { - Log::Debug(mbgl::Event::JNI, "Updating map"); - if (map) { - map->triggerRepaint(); - } else { - Log::Error(mbgl::Event::JNI, "No map reference, cannot update"); - } - } - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } - - CustomJavaLayerPeerFactory::~CustomJavaLayerPeerFactory() = default; - - jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - return createJavaPeer(env, new CustomLayer(map, static_cast(layer))); - } - - jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - return createJavaPeer(env, new CustomLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void CustomJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&CustomLayer::update, "nativeUpdate")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/custom_layer.hpp b/src/style/layers/custom_layer.hpp deleted file mode 100644 index 0d6f4a408..000000000 --- a/src/style/layers/custom_layer.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "layer.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class CustomLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CustomLayer"; }; - - static void registerNative(jni::JNIEnv&); - - CustomLayer(jni::JNIEnv&, const jni::String&, jni::jlong); - CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&); - CustomLayer(mbgl::Map&, std::unique_ptr); - ~CustomLayer(); - - void update(jni::JNIEnv&); - - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class CustomLayer - -class CustomJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CustomLayerFactory { -public: - ~CustomJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class CustomJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/fill_extrusion_layer.cpp b/src/style/layers/fill_extrusion_layer.cpp deleted file mode 100644 index ddfbd7154..000000000 --- a/src/style/layers/fill_extrusion_layer.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "fill_extrusion_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::FillExtrusionLayer& toFillExtrusionLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - FillExtrusionLayer::FillExtrusionLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, mbgl::style::FillExtrusionLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - FillExtrusionLayer::~FillExtrusionLayer() = default; - - // Property getters - - jni::Local> FillExtrusionLayer::getFillExtrusionOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionOpacity())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionOpacityTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionColor())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionColorTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionColorTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslate())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionTranslateTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslateAnchor())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionPattern(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionPattern())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionPatternTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionPatternTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionPatternTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionHeight(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionHeight())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionHeightTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionHeightTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionHeightTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionBase(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionBase())); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionBaseTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionBaseTransition(); - return std::move(*convert>>(env, options)); - } - - void FillExtrusionLayer::setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillExtrusionLayer(layer).setFillExtrusionBaseTransition(options); - } - - jni::Local> FillExtrusionLayer::getFillExtrusionVerticalGradient(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionVerticalGradient())); - } - - - // FillExtrusionJavaLayerPeerFactory - - FillExtrusionJavaLayerPeerFactory::~FillExtrusionJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new FillExtrusionLayer(map, toFillExtrusionLayer(layer))); - } - - jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new FillExtrusionLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void FillExtrusionJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&FillExtrusionLayer::getFillExtrusionOpacityTransition, "nativeGetFillExtrusionOpacityTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionOpacityTransition, "nativeSetFillExtrusionOpacityTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionOpacity, "nativeGetFillExtrusionOpacity"), - METHOD(&FillExtrusionLayer::getFillExtrusionColorTransition, "nativeGetFillExtrusionColorTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionColorTransition, "nativeSetFillExtrusionColorTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionColor, "nativeGetFillExtrusionColor"), - METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, "nativeGetFillExtrusionTranslateTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, "nativeSetFillExtrusionTranslateTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionTranslate, "nativeGetFillExtrusionTranslate"), - METHOD(&FillExtrusionLayer::getFillExtrusionTranslateAnchor, "nativeGetFillExtrusionTranslateAnchor"), - METHOD(&FillExtrusionLayer::getFillExtrusionPatternTransition, "nativeGetFillExtrusionPatternTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionPatternTransition, "nativeSetFillExtrusionPatternTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionPattern, "nativeGetFillExtrusionPattern"), - METHOD(&FillExtrusionLayer::getFillExtrusionHeightTransition, "nativeGetFillExtrusionHeightTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionHeightTransition, "nativeSetFillExtrusionHeightTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionHeight, "nativeGetFillExtrusionHeight"), - METHOD(&FillExtrusionLayer::getFillExtrusionBaseTransition, "nativeGetFillExtrusionBaseTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionBaseTransition, "nativeSetFillExtrusionBaseTransition"), - METHOD(&FillExtrusionLayer::getFillExtrusionBase, "nativeGetFillExtrusionBase"), - METHOD(&FillExtrusionLayer::getFillExtrusionVerticalGradient, "nativeGetFillExtrusionVerticalGradient")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/fill_extrusion_layer.hpp b/src/style/layers/fill_extrusion_layer.hpp deleted file mode 100644 index 15dad67b0..000000000 --- a/src/style/layers/fill_extrusion_layer.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class FillExtrusionLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer"; }; - - FillExtrusionLayer(jni::JNIEnv&, jni::String&, jni::String&); - - FillExtrusionLayer(mbgl::Map&, mbgl::style::FillExtrusionLayer&); - - FillExtrusionLayer(mbgl::Map&, std::unique_ptr); - - ~FillExtrusionLayer(); - - // Properties - - jni::Local> getFillExtrusionOpacity(jni::JNIEnv&); - void setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionOpacityTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionColor(jni::JNIEnv&); - void setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionColorTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionTranslate(jni::JNIEnv&); - void setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionTranslateTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionTranslateAnchor(jni::JNIEnv&); - - jni::Local> getFillExtrusionPattern(jni::JNIEnv&); - void setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionPatternTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionHeight(jni::JNIEnv&); - void setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionHeightTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionBase(jni::JNIEnv&); - void setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillExtrusionBaseTransition(jni::JNIEnv&); - - jni::Local> getFillExtrusionVerticalGradient(jni::JNIEnv&); - -}; // class FillExtrusionLayer - -class FillExtrusionJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillExtrusionLayerFactory { -public: - ~FillExtrusionJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class FillExtrusionJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/fill_layer.cpp b/src/style/layers/fill_layer.cpp deleted file mode 100644 index c54f4cd39..000000000 --- a/src/style/layers/fill_layer.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "fill_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::FillLayer& toFillLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - FillLayer::FillLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - FillLayer::FillLayer(mbgl::Map& map, mbgl::style::FillLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - FillLayer::FillLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - FillLayer::~FillLayer() = default; - - // Property getters - - jni::Local> FillLayer::getFillAntialias(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillAntialias())); - } - - jni::Local> FillLayer::getFillOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillOpacity())); - } - - jni::Local> FillLayer::getFillOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void FillLayer::setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillLayer(layer).setFillOpacityTransition(options); - } - - jni::Local> FillLayer::getFillColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillColor())); - } - - jni::Local> FillLayer::getFillColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillLayer(layer).getFillColorTransition(); - return std::move(*convert>>(env, options)); - } - - void FillLayer::setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillLayer(layer).setFillColorTransition(options); - } - - jni::Local> FillLayer::getFillOutlineColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillOutlineColor())); - } - - jni::Local> FillLayer::getFillOutlineColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOutlineColorTransition(); - return std::move(*convert>>(env, options)); - } - - void FillLayer::setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillLayer(layer).setFillOutlineColorTransition(options); - } - - jni::Local> FillLayer::getFillTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillTranslate())); - } - - jni::Local> FillLayer::getFillTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillLayer(layer).getFillTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void FillLayer::setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillLayer(layer).setFillTranslateTransition(options); - } - - jni::Local> FillLayer::getFillTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillTranslateAnchor())); - } - - jni::Local> FillLayer::getFillPattern(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toFillLayer(layer).getFillPattern())); - } - - jni::Local> FillLayer::getFillPatternTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toFillLayer(layer).getFillPatternTransition(); - return std::move(*convert>>(env, options)); - } - - void FillLayer::setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toFillLayer(layer).setFillPatternTransition(options); - } - - - // FillJavaLayerPeerFactory - - FillJavaLayerPeerFactory::~FillJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new FillLayer(map, toFillLayer(layer))); - } - - jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new FillLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void FillJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&FillLayer::getFillAntialias, "nativeGetFillAntialias"), - METHOD(&FillLayer::getFillOpacityTransition, "nativeGetFillOpacityTransition"), - METHOD(&FillLayer::setFillOpacityTransition, "nativeSetFillOpacityTransition"), - METHOD(&FillLayer::getFillOpacity, "nativeGetFillOpacity"), - METHOD(&FillLayer::getFillColorTransition, "nativeGetFillColorTransition"), - METHOD(&FillLayer::setFillColorTransition, "nativeSetFillColorTransition"), - METHOD(&FillLayer::getFillColor, "nativeGetFillColor"), - METHOD(&FillLayer::getFillOutlineColorTransition, "nativeGetFillOutlineColorTransition"), - METHOD(&FillLayer::setFillOutlineColorTransition, "nativeSetFillOutlineColorTransition"), - METHOD(&FillLayer::getFillOutlineColor, "nativeGetFillOutlineColor"), - METHOD(&FillLayer::getFillTranslateTransition, "nativeGetFillTranslateTransition"), - METHOD(&FillLayer::setFillTranslateTransition, "nativeSetFillTranslateTransition"), - METHOD(&FillLayer::getFillTranslate, "nativeGetFillTranslate"), - METHOD(&FillLayer::getFillTranslateAnchor, "nativeGetFillTranslateAnchor"), - METHOD(&FillLayer::getFillPatternTransition, "nativeGetFillPatternTransition"), - METHOD(&FillLayer::setFillPatternTransition, "nativeSetFillPatternTransition"), - METHOD(&FillLayer::getFillPattern, "nativeGetFillPattern")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/fill_layer.hpp b/src/style/layers/fill_layer.hpp deleted file mode 100644 index b021ddca1..000000000 --- a/src/style/layers/fill_layer.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class FillLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillLayer"; }; - - FillLayer(jni::JNIEnv&, jni::String&, jni::String&); - - FillLayer(mbgl::Map&, mbgl::style::FillLayer&); - - FillLayer(mbgl::Map&, std::unique_ptr); - - ~FillLayer(); - - // Properties - - jni::Local> getFillAntialias(jni::JNIEnv&); - - jni::Local> getFillOpacity(jni::JNIEnv&); - void setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillOpacityTransition(jni::JNIEnv&); - - jni::Local> getFillColor(jni::JNIEnv&); - void setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillColorTransition(jni::JNIEnv&); - - jni::Local> getFillOutlineColor(jni::JNIEnv&); - void setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillOutlineColorTransition(jni::JNIEnv&); - - jni::Local> getFillTranslate(jni::JNIEnv&); - void setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillTranslateTransition(jni::JNIEnv&); - - jni::Local> getFillTranslateAnchor(jni::JNIEnv&); - - jni::Local> getFillPattern(jni::JNIEnv&); - void setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getFillPatternTransition(jni::JNIEnv&); - -}; // class FillLayer - -class FillJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillLayerFactory { -public: - ~FillJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class FillJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/heatmap_layer.cpp b/src/style/layers/heatmap_layer.cpp deleted file mode 100644 index 509ab5d70..000000000 --- a/src/style/layers/heatmap_layer.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "heatmap_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::HeatmapLayer& toHeatmapLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - HeatmapLayer::HeatmapLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - HeatmapLayer::HeatmapLayer(mbgl::Map& map, mbgl::style::HeatmapLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - HeatmapLayer::HeatmapLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - HeatmapLayer::~HeatmapLayer() = default; - - // Property getters - - jni::Local> HeatmapLayer::getHeatmapRadius(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapRadius())); - } - - jni::Local> HeatmapLayer::getHeatmapRadiusTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapRadiusTransition(); - return std::move(*convert>>(env, options)); - } - - void HeatmapLayer::setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHeatmapLayer(layer).setHeatmapRadiusTransition(options); - } - - jni::Local> HeatmapLayer::getHeatmapWeight(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapWeight())); - } - - jni::Local> HeatmapLayer::getHeatmapIntensity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapIntensity())); - } - - jni::Local> HeatmapLayer::getHeatmapIntensityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapIntensityTransition(); - return std::move(*convert>>(env, options)); - } - - void HeatmapLayer::setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHeatmapLayer(layer).setHeatmapIntensityTransition(options); - } - - jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - auto propertyValue = toHeatmapLayer(layer).getHeatmapColor(); - if (propertyValue.isUndefined()) { - propertyValue = toHeatmapLayer(layer).getDefaultHeatmapColor(); - } - return std::move(*convert>>(env, propertyValue)); - } - - jni::Local> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapOpacity())); - } - - jni::Local> HeatmapLayer::getHeatmapOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void HeatmapLayer::setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHeatmapLayer(layer).setHeatmapOpacityTransition(options); - } - - - // HeatmapJavaLayerPeerFactory - - HeatmapJavaLayerPeerFactory::~HeatmapJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new HeatmapLayer(map, toHeatmapLayer(layer))); - } - - jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new HeatmapLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void HeatmapJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&HeatmapLayer::getHeatmapRadiusTransition, "nativeGetHeatmapRadiusTransition"), - METHOD(&HeatmapLayer::setHeatmapRadiusTransition, "nativeSetHeatmapRadiusTransition"), - METHOD(&HeatmapLayer::getHeatmapRadius, "nativeGetHeatmapRadius"), - METHOD(&HeatmapLayer::getHeatmapWeight, "nativeGetHeatmapWeight"), - METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), - METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), - METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), - METHOD(&HeatmapLayer::getHeatmapColor, "nativeGetHeatmapColor"), - METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), - METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), - METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/heatmap_layer.hpp b/src/style/layers/heatmap_layer.hpp deleted file mode 100644 index 9e3db0c89..000000000 --- a/src/style/layers/heatmap_layer.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class HeatmapLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HeatmapLayer"; }; - - HeatmapLayer(jni::JNIEnv&, jni::String&, jni::String&); - - HeatmapLayer(mbgl::Map&, mbgl::style::HeatmapLayer&); - - HeatmapLayer(mbgl::Map&, std::unique_ptr); - - ~HeatmapLayer(); - - // Properties - - jni::Local> getHeatmapRadius(jni::JNIEnv&); - void setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHeatmapRadiusTransition(jni::JNIEnv&); - - jni::Local> getHeatmapWeight(jni::JNIEnv&); - - jni::Local> getHeatmapIntensity(jni::JNIEnv&); - void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHeatmapIntensityTransition(jni::JNIEnv&); - - jni::Local> getHeatmapColor(jni::JNIEnv&); - - jni::Local> getHeatmapOpacity(jni::JNIEnv&); - void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHeatmapOpacityTransition(jni::JNIEnv&); - -}; // class HeatmapLayer - -class HeatmapJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HeatmapLayerFactory { -public: - ~HeatmapJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class HeatmapJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/hillshade_layer.cpp b/src/style/layers/hillshade_layer.cpp deleted file mode 100644 index bc25f666a..000000000 --- a/src/style/layers/hillshade_layer.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "hillshade_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::HillshadeLayer& toHillshadeLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - HillshadeLayer::HillshadeLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - HillshadeLayer::HillshadeLayer(mbgl::Map& map, mbgl::style::HillshadeLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - HillshadeLayer::HillshadeLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - HillshadeLayer::~HillshadeLayer() = default; - - // Property getters - - jni::Local> HillshadeLayer::getHillshadeIlluminationDirection(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationDirection())); - } - - jni::Local> HillshadeLayer::getHillshadeIlluminationAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationAnchor())); - } - - jni::Local> HillshadeLayer::getHillshadeExaggeration(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeExaggeration())); - } - - jni::Local> HillshadeLayer::getHillshadeExaggerationTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeExaggerationTransition(); - return std::move(*convert>>(env, options)); - } - - void HillshadeLayer::setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHillshadeLayer(layer).setHillshadeExaggerationTransition(options); - } - - jni::Local> HillshadeLayer::getHillshadeShadowColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeShadowColor())); - } - - jni::Local> HillshadeLayer::getHillshadeShadowColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeShadowColorTransition(); - return std::move(*convert>>(env, options)); - } - - void HillshadeLayer::setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHillshadeLayer(layer).setHillshadeShadowColorTransition(options); - } - - jni::Local> HillshadeLayer::getHillshadeHighlightColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeHighlightColor())); - } - - jni::Local> HillshadeLayer::getHillshadeHighlightColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeHighlightColorTransition(); - return std::move(*convert>>(env, options)); - } - - void HillshadeLayer::setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHillshadeLayer(layer).setHillshadeHighlightColorTransition(options); - } - - jni::Local> HillshadeLayer::getHillshadeAccentColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeAccentColor())); - } - - jni::Local> HillshadeLayer::getHillshadeAccentColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeAccentColorTransition(); - return std::move(*convert>>(env, options)); - } - - void HillshadeLayer::setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toHillshadeLayer(layer).setHillshadeAccentColorTransition(options); - } - - - // HillshadeJavaLayerPeerFactory - - HillshadeJavaLayerPeerFactory::~HillshadeJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new HillshadeLayer(map, toHillshadeLayer(layer))); - } - - jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new HillshadeLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void HillshadeJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&HillshadeLayer::getHillshadeIlluminationDirection, "nativeGetHillshadeIlluminationDirection"), - METHOD(&HillshadeLayer::getHillshadeIlluminationAnchor, "nativeGetHillshadeIlluminationAnchor"), - METHOD(&HillshadeLayer::getHillshadeExaggerationTransition, "nativeGetHillshadeExaggerationTransition"), - METHOD(&HillshadeLayer::setHillshadeExaggerationTransition, "nativeSetHillshadeExaggerationTransition"), - METHOD(&HillshadeLayer::getHillshadeExaggeration, "nativeGetHillshadeExaggeration"), - METHOD(&HillshadeLayer::getHillshadeShadowColorTransition, "nativeGetHillshadeShadowColorTransition"), - METHOD(&HillshadeLayer::setHillshadeShadowColorTransition, "nativeSetHillshadeShadowColorTransition"), - METHOD(&HillshadeLayer::getHillshadeShadowColor, "nativeGetHillshadeShadowColor"), - METHOD(&HillshadeLayer::getHillshadeHighlightColorTransition, "nativeGetHillshadeHighlightColorTransition"), - METHOD(&HillshadeLayer::setHillshadeHighlightColorTransition, "nativeSetHillshadeHighlightColorTransition"), - METHOD(&HillshadeLayer::getHillshadeHighlightColor, "nativeGetHillshadeHighlightColor"), - METHOD(&HillshadeLayer::getHillshadeAccentColorTransition, "nativeGetHillshadeAccentColorTransition"), - METHOD(&HillshadeLayer::setHillshadeAccentColorTransition, "nativeSetHillshadeAccentColorTransition"), - METHOD(&HillshadeLayer::getHillshadeAccentColor, "nativeGetHillshadeAccentColor")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/hillshade_layer.hpp b/src/style/layers/hillshade_layer.hpp deleted file mode 100644 index 2f4ea30c2..000000000 --- a/src/style/layers/hillshade_layer.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class HillshadeLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HillshadeLayer"; }; - - HillshadeLayer(jni::JNIEnv&, jni::String&, jni::String&); - - HillshadeLayer(mbgl::Map&, mbgl::style::HillshadeLayer&); - - HillshadeLayer(mbgl::Map&, std::unique_ptr); - - ~HillshadeLayer(); - - // Properties - - jni::Local> getHillshadeIlluminationDirection(jni::JNIEnv&); - - jni::Local> getHillshadeIlluminationAnchor(jni::JNIEnv&); - - jni::Local> getHillshadeExaggeration(jni::JNIEnv&); - void setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHillshadeExaggerationTransition(jni::JNIEnv&); - - jni::Local> getHillshadeShadowColor(jni::JNIEnv&); - void setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHillshadeShadowColorTransition(jni::JNIEnv&); - - jni::Local> getHillshadeHighlightColor(jni::JNIEnv&); - void setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHillshadeHighlightColorTransition(jni::JNIEnv&); - - jni::Local> getHillshadeAccentColor(jni::JNIEnv&); - void setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getHillshadeAccentColorTransition(jni::JNIEnv&); - -}; // class HillshadeLayer - -class HillshadeJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HillshadeLayerFactory { -public: - ~HillshadeJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class HillshadeJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/layer.cpp b/src/style/layers/layer.cpp deleted file mode 100644 index 2f335b6ff..000000000 --- a/src/style/layers/layer.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "layer.hpp" -#include "../android_conversion.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Java -> C++ conversion -#include -#include -#include -#include - -// C++ -> Java conversion -#include "../conversion/property_value.hpp" -#include "custom_layer.hpp" -#include "background_layer.hpp" -#include - -#include - -namespace mbgl { -namespace android { - - /** - * Invoked when the construction is initiated from the jvm through a subclass - */ - Layer::Layer(std::unique_ptr coreLayer) - : ownedLayer(std::move(coreLayer)) - , layer(*ownedLayer) { - } - - /** - * Takes a non-owning reference. For lookup methods - */ - Layer::Layer(mbgl::Map& coreMap, mbgl::style::Layer& coreLayer) : layer(coreLayer) , map(&coreMap) { - } - - /** - * Takes a owning reference. Ownership is transfered to this peer, eg after removing - * from the map - */ - Layer::Layer(mbgl::Map& coreMap, std::unique_ptr coreLayer) - : ownedLayer(std::move(coreLayer)) - , layer(*ownedLayer) - , map(&coreMap) { - } - - Layer::~Layer() { - } - - void Layer::addToMap(mbgl::Map& _map, mbgl::optional before) { - // Check to see if we own the layer first - if (!ownedLayer) { - throw std::runtime_error("Cannot add layer twice"); - } - - // Add layer to map - _map.getStyle().addLayer(releaseCoreLayer(), before); - - // Save pointer to the map - this->map = &_map; - } - - void Layer::setLayer(std::unique_ptr sourceLayer) { - this->ownedLayer = std::move(sourceLayer); - } - - std::unique_ptr Layer::releaseCoreLayer() { - assert(ownedLayer != nullptr); - return std::move(ownedLayer); - } - - jni::Local Layer::getId(jni::JNIEnv& env) { - return jni::Make(env, layer.getID()); - } - - style::Layer& Layer::get() { - return layer; - } - - void Layer::setLayoutProperty(jni::JNIEnv& env, const jni::String& jname, const jni::Object<>& jvalue) { - // Convert and set property - optional error = layer.setLayoutProperty(jni::Make(env, jname), Value(env, jvalue)); - if (error) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); - return; - } - } - - void Layer::setPaintProperty(jni::JNIEnv& env, const jni::String& jname, const jni::Object<>& jvalue) { - // Convert and set property - optional error = layer.setPaintProperty(jni::Make(env, jname), Value(env, jvalue)); - if (error) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); - return; - } - } - - void Layer::setFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { - using namespace mbgl::style; - using namespace mbgl::style::conversion; - - Error error; - optional converted = convert(Value(env, jfilter), error); - if (!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message); - return; - } - - layer.setFilter(std::move(*converted)); - } - - jni::Local> Layer::getFilter(jni::JNIEnv& env) { - using namespace mbgl::style; - using namespace mbgl::style::conversion; - - Filter filter = layer.getFilter(); - if (filter.expression) { - mbgl::Value expressionValue = (*filter.expression)->serialize(); - return gson::JsonElement::New(env, expressionValue); - } else { - return jni::Local>(env, nullptr); - } - } - - void Layer::setSourceLayer(jni::JNIEnv& env, const jni::String& sourceLayer) { - layer.setSourceLayer(jni::Make(env, sourceLayer)); - } - - jni::Local Layer::getSourceLayer(jni::JNIEnv& env) { - return jni::Make(env, layer.getSourceLayer()); - } - - jni::Local Layer::getSourceId(jni::JNIEnv& env) { - return jni::Make(env, layer.getSourceID()); - } - - jni::jfloat Layer::getMinZoom(jni::JNIEnv&){ - return layer.getMinZoom(); - } - - jni::jfloat Layer::getMaxZoom(jni::JNIEnv&) { - return layer.getMaxZoom(); - } - - void Layer::setMinZoom(jni::JNIEnv&, jni::jfloat zoom) { - layer.setMinZoom(zoom); - } - - void Layer::setMaxZoom(jni::JNIEnv&, jni::jfloat zoom) { - layer.setMaxZoom(zoom); - } - - jni::Local> Layer::getVisibility(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, layer.getVisibility())); - } - - void Layer::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - METHOD(&Layer::getId, "nativeGetId"), - METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"), - METHOD(&Layer::setPaintProperty, "nativeSetPaintProperty"), - METHOD(&Layer::setFilter, "nativeSetFilter"), - METHOD(&Layer::getFilter, "nativeGetFilter"), - METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"), - METHOD(&Layer::getSourceLayer, "nativeGetSourceLayer"), - METHOD(&Layer::getSourceId, "nativeGetSourceId"), - METHOD(&Layer::getMinZoom, "nativeGetMinZoom"), - METHOD(&Layer::getMaxZoom, "nativeGetMaxZoom"), - METHOD(&Layer::setMinZoom, "nativeSetMinZoom"), - METHOD(&Layer::setMaxZoom, "nativeSetMaxZoom"), - METHOD(&Layer::getVisibility, "nativeGetVisibility") - ); - - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/layer.cpp.ejs b/src/style/layers/layer.cpp.ejs deleted file mode 100644 index c81fc5ab3..000000000 --- a/src/style/layers/layer.cpp.ejs +++ /dev/null @@ -1,137 +0,0 @@ -<% - const type = locals.type; - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "<%- type.replace('-', '_') %>_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::<%- camelize(type) %>Layer& to<%- camelize(type) %>Layer(mbgl::style::Layer& layer) { - return static_castLayer&>(layer); - } - -<% if (type === 'background') { -%> - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId) - : Layer(std::make_uniqueLayer>(jni::Make(env, layerId))) { -<% } else { -%> - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_uniqueLayer>(jni::Make(env, layerId), jni::Make(env, sourceId))) { -<% } -%> - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, std::unique_ptrLayer> coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - <%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; - - // Property getters - -<% for (const property of properties) { -%> -<% if (property.name != 'heatmap-color') { -%> - jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>())); - } - -<% } else { -%> - jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - auto propertyValue = to<%- camelize(type) %>Layer(layer).getHeatmapColor(); - if (propertyValue.isUndefined()) { - propertyValue = to<%- camelize(type) %>Layer(layer).getDefaultHeatmapColor(); - } - return std::move(*convert>>(env, propertyValue)); - } - -<% } -%> -<% if (property.transition) { -%> - jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>Transition(); - return std::move(*convert>>(env, options)); - } - - void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - to<%- camelize(type) %>Layer(layer).set<%- camelize(property.name) %>Transition(options); - } - -<% } -%> -<% } -%> - - // <%- camelize(type) %>JavaLayerPeerFactory - - <%- camelize(type) %>JavaLayerPeerFactory::~<%- camelize(type) %>JavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new <%- camelize(type) %>Layer(map, to<%- camelize(type) %>Layer(layer))); - } - - jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new <%- camelize(type) %>Layer(map, std::unique_ptrLayer>(static_castLayer*>(layer.release())))); - } - - void <%- camelize(type) %>JavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer<<%- camelize(type) %>Layer>( - env, javaClass, "nativePtr", -<% if (type === 'background') { -%> - jni::MakePeer<<%- camelize(type) %>Layer, jni::String&>, -<% } else { -%> - jni::MakePeer<<%- camelize(type) %>Layer, jni::String&, jni::String&>, -<% } -%> - "initialize", - "finalize",<% for(var i = 0; i < properties.length; i++) {%> -<% if (properties[i].transition) { -%> - METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"), - METHOD(&<%- camelize(type) %>Layer::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"), -<% } -%> - METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/layer.hpp b/src/style/layers/layer.hpp deleted file mode 100644 index 0fb679152..000000000 --- a/src/style/layers/layer.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../../gson/json_array.hpp" -#include "../value.hpp" -#include "../../gson/json_element.hpp" - -#include - -namespace mbgl { - -namespace android { - -class Layer { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/Layer"; }; - - static void registerNative(jni::JNIEnv&); - - virtual ~Layer(); - - /** - * Set core layer (ie return ownership after remove) - */ - void setLayer(std::unique_ptr); - - void addToMap(mbgl::Map&, mbgl::optional); - - jni::Local getId(jni::JNIEnv&); - - jni::Local getSourceId(jni::JNIEnv&); - - style::Layer& get(); - - void setLayoutProperty(jni::JNIEnv&, const jni::String&, const jni::Object<>& value); - - void setPaintProperty(jni::JNIEnv&, const jni::String&, const jni::Object<>& value); - - // Zoom - - jni::jfloat getMinZoom(jni::JNIEnv&); - - jni::jfloat getMaxZoom(jni::JNIEnv&); - - void setMinZoom(jni::JNIEnv&, jni::jfloat zoom); - - void setMaxZoom(jni::JNIEnv&, jni::jfloat zoom); - - /* common properties, but not shared by all */ - - void setFilter(jni::JNIEnv&, const jni::Array>&); - - jni::Local> getFilter(jni::JNIEnv&); - - void setSourceLayer(jni::JNIEnv&, const jni::String&); - - jni::Local getSourceLayer(jni::JNIEnv&); - - // Property getters - - jni::Local> getVisibility(jni::JNIEnv&); - -protected: - /* - * Called when a non-owning peer object is created on the c++ side - */ - Layer(mbgl::Map&, mbgl::style::Layer&); - - /* - * Called when a owning peer object is created on the c++ side - */ - Layer(mbgl::Map&, std::unique_ptr); - - /* - * Called when a Java object was created from the jvm side - */ - Layer(std::unique_ptr); - - // Release the owned view and return it - std::unique_ptr releaseCoreLayer(); - - // Owned layer is set when creating a new layer, before adding it to the map - std::unique_ptr ownedLayer; - - // Raw reference to the layer - mbgl::style::Layer& layer; - - // Map is set when the layer is retrieved or after adding to the map - mbgl::Map* map; -}; - -/** - * @brief A factory class for a layer Java peer objects of a certain type. - */ -class JavaLayerPeerFactory { -public: - virtual ~JavaLayerPeerFactory() = default; - /** - * @brief Create a non-owning peer. - */ - virtual jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) = 0; - - /** - * @brief Create an owning peer. - */ - virtual jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) = 0; - - /** - * @brief Register peer methods. - */ - virtual void registerNative(jni::JNIEnv&) = 0; - - /** - * @brief Get the corresponding layer factory. - * - * @return style::LayerFactory* must not be \c nullptr. - */ - virtual LayerFactory* getLayerFactory() = 0; -}; - - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/layer.hpp.ejs b/src/style/layers/layer.hpp.ejs deleted file mode 100644 index 28e00b273..000000000 --- a/src/style/layers/layer.hpp.ejs +++ /dev/null @@ -1,62 +0,0 @@ -<% - const type = locals.type; - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include _layer_factory.hpp> -#include _layer.hpp> -#include - -namespace mbgl { -namespace android { - -class <%- camelize(type) %>Layer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; }; - -<% if (type === 'background') { -%> - <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&); -<% } else { -%> - <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&, jni::String&); -<% } -%> - - <%- camelize(type) %>Layer(mbgl::Map&, mbgl::style::<%- camelize(type) %>Layer&); - - <%- camelize(type) %>Layer(mbgl::Map&, std::unique_ptrLayer>); - - ~<%- camelize(type) %>Layer(); - - // Properties -<% for (const property of properties) { -%> - - jni::Local> get<%- camelize(property.name) %>(jni::JNIEnv&); -<% if (property.transition) { -%> - void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> get<%- camelize(property.name) %>Transition(jni::JNIEnv&); -<% } -%> -<% } -%> - -}; // class <%- camelize(type) %>Layer - -class <%- camelize(type) %>JavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::<%- camelize(type) %>LayerFactory { -public: - ~<%- camelize(type) %>JavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class <%- camelize(type) %>JavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/layer_manager.cpp b/src/style/layers/layer_manager.cpp deleted file mode 100644 index d0c54ee00..000000000 --- a/src/style/layers/layer_manager.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "layer_manager.hpp" - -#include - -#include -#include -#include - -#include "background_layer.hpp" -#include "circle_layer.hpp" -#include "custom_layer.hpp" -#include "fill_extrusion_layer.hpp" -#include "fill_layer.hpp" -#include "heatmap_layer.hpp" -#include "hillshade_layer.hpp" -#include "line_layer.hpp" -#include "raster_layer.hpp" -#include "symbol_layer.hpp" -#include "fill_extrusion_layer.hpp" - -namespace mbgl { - -namespace android { - -LayerManagerAndroid::LayerManagerAndroid() { -#if defined(MBGL_LAYER_FILL_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_FILL_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_LINE_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_LINE_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_CIRCLE_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_CIRCLE_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_SYMBOL_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_RASTER_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_RASTER_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_BACKGROUND_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_BACKGROUND_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_HILLSHADE_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_HILLSHADE_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_HEATMAP_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_HEATMAP_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -#if defined(MBGL_LAYER_CUSTOM_DISABLE_RUNTIME) - addLayerTypeCoreOnly(std::make_unique()); -#elif !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) - addLayerType(std::make_unique()); -#endif -} - -LayerManagerAndroid::~LayerManagerAndroid() = default; - -jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - if (JavaLayerPeerFactory* factory = getPeerFactory(layer.getTypeInfo())) { - return factory->createJavaLayerPeer(env, map, layer); - } - return jni::Local>(); -} - -jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - if (JavaLayerPeerFactory* factory = getPeerFactory(layer->getTypeInfo())) { - return factory->createJavaLayerPeer(env, map, std::move(layer)); - } - return jni::Local>(); -} - -void LayerManagerAndroid::registerNative(jni::JNIEnv& env) { - if (peerFactories.empty()) { - return; - } - - Layer::registerNative(env); - for (const auto& factory: peerFactories) { - factory->registerNative(env); - } -} - -void LayerManagerAndroid::addLayerType(std::unique_ptr factory) { - assert(getFactory(factory->getLayerFactory()->getTypeInfo()) == nullptr); - registerCoreFactory(factory->getLayerFactory()); - peerFactories.emplace_back(std::move(factory)); -} - -void LayerManagerAndroid::addLayerTypeCoreOnly(std::unique_ptr factory) { - assert(getFactory(factory->getTypeInfo()) == nullptr); - registerCoreFactory(factory.get()); - coreFactories.emplace_back(std::move(factory)); -} - -void LayerManagerAndroid::registerCoreFactory(mbgl::LayerFactory* factory) { - std::string type{factory->getTypeInfo()->type}; - if (!type.empty()) { - assert(typeToFactory.find(type) == typeToFactory.end()); - typeToFactory.emplace(std::make_pair(std::move(type), factory)); - } -} - -JavaLayerPeerFactory* LayerManagerAndroid::getPeerFactory(const mbgl::style::LayerTypeInfo* typeInfo) { - assert(typeInfo); - for (const auto& factory: peerFactories) { - if (factory->getLayerFactory()->getTypeInfo() == typeInfo) { - return factory.get(); - } - } - return nullptr; -} - -LayerFactory* LayerManagerAndroid::getFactory(const std::string& type) noexcept { - auto search = typeToFactory.find(type); - return (search != typeToFactory.end()) ? search->second : nullptr; -} - -LayerFactory* LayerManagerAndroid::getFactory(const mbgl::style::LayerTypeInfo* info) noexcept { - if (JavaLayerPeerFactory* peerFactory = getPeerFactory(info)) { - return peerFactory->getLayerFactory(); - } - - for (const auto& factory: coreFactories) { - if (factory->getTypeInfo() == info) { - return factory.get(); - } - } - - return nullptr; -} - -// static -LayerManagerAndroid* LayerManagerAndroid::get() noexcept { - static LayerManagerAndroid impl; - return &impl; -} - -} // namespace android - -LayerManager* LayerManager::get() noexcept { - return android::LayerManagerAndroid::get(); -} - -#if defined(MBGL_LAYER_LINE_DISABLE_ALL) || defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) || defined(MBGL_LAYER_FILL_DISABLE_ALL) -const bool LayerManager::annotationsEnabled = false; -#else -const bool LayerManager::annotationsEnabled = true; -#endif - -} // namespace mbgl diff --git a/src/style/layers/layer_manager.hpp b/src/style/layers/layer_manager.hpp deleted file mode 100644 index 807ded173..000000000 --- a/src/style/layers/layer_manager.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "layer.hpp" - -#include - -#include -#include - -namespace mbgl { -namespace android { - -/** - * @brief A singleton class forwarding calls to the corresponding \c JavaLayerPeerFactory instance. - */ -class LayerManagerAndroid final : public mbgl::LayerManager { -public: - ~LayerManagerAndroid() final; - static LayerManagerAndroid* get() noexcept; - - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&); - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr); - - void registerNative(jni::JNIEnv&); - -private: - LayerManagerAndroid(); - /** - * @brief Enables a layer type for both JSON style and runtime API. - */ - void addLayerType(std::unique_ptr); - /** - * @brief Enables a layer type for JSON style only. - * - * We might not want to expose runtime API for some layer types - * in order to save binary size - JNI glue code for these layer types - * won't be added to the binary. - */ - void addLayerTypeCoreOnly(std::unique_ptr); - - void registerCoreFactory(mbgl::LayerFactory*); - JavaLayerPeerFactory* getPeerFactory(const mbgl::style::LayerTypeInfo*); - // mbgl::LayerManager overrides. - LayerFactory* getFactory(const std::string& type) noexcept final; - LayerFactory* getFactory(const mbgl::style::LayerTypeInfo* info) noexcept final; - - std::vector> peerFactories; - std::vector> coreFactories; - std::map typeToFactory; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/line_layer.cpp b/src/style/layers/line_layer.cpp deleted file mode 100644 index 73fcd5f99..000000000 --- a/src/style/layers/line_layer.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "line_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::LineLayer& toLineLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - LineLayer::LineLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - LineLayer::LineLayer(mbgl::Map& map, mbgl::style::LineLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - LineLayer::LineLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - LineLayer::~LineLayer() = default; - - // Property getters - - jni::Local> LineLayer::getLineCap(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineCap())); - } - - jni::Local> LineLayer::getLineJoin(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineJoin())); - } - - jni::Local> LineLayer::getLineMiterLimit(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineMiterLimit())); - } - - jni::Local> LineLayer::getLineRoundLimit(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineRoundLimit())); - } - - jni::Local> LineLayer::getLineOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineOpacity())); - } - - jni::Local> LineLayer::getLineOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineOpacityTransition(options); - } - - jni::Local> LineLayer::getLineColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineColor())); - } - - jni::Local> LineLayer::getLineColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineColorTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineColorTransition(options); - } - - jni::Local> LineLayer::getLineTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineTranslate())); - } - - jni::Local> LineLayer::getLineTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineTranslateTransition(options); - } - - jni::Local> LineLayer::getLineTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineTranslateAnchor())); - } - - jni::Local> LineLayer::getLineWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineWidth())); - } - - jni::Local> LineLayer::getLineWidthTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineWidthTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineWidthTransition(options); - } - - jni::Local> LineLayer::getLineGapWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineGapWidth())); - } - - jni::Local> LineLayer::getLineGapWidthTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineGapWidthTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineGapWidthTransition(options); - } - - jni::Local> LineLayer::getLineOffset(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineOffset())); - } - - jni::Local> LineLayer::getLineOffsetTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOffsetTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineOffsetTransition(options); - } - - jni::Local> LineLayer::getLineBlur(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineBlur())); - } - - jni::Local> LineLayer::getLineBlurTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineBlurTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineBlurTransition(options); - } - - jni::Local> LineLayer::getLineDasharray(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineDasharray())); - } - - jni::Local> LineLayer::getLineDasharrayTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLineDasharrayTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLineDasharrayTransition(options); - } - - jni::Local> LineLayer::getLinePattern(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLinePattern())); - } - - jni::Local> LineLayer::getLinePatternTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toLineLayer(layer).getLinePatternTransition(); - return std::move(*convert>>(env, options)); - } - - void LineLayer::setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toLineLayer(layer).setLinePatternTransition(options); - } - - jni::Local> LineLayer::getLineGradient(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toLineLayer(layer).getLineGradient())); - } - - - // LineJavaLayerPeerFactory - - LineJavaLayerPeerFactory::~LineJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new LineLayer(map, toLineLayer(layer))); - } - - jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new LineLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void LineJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&LineLayer::getLineCap, "nativeGetLineCap"), - METHOD(&LineLayer::getLineJoin, "nativeGetLineJoin"), - METHOD(&LineLayer::getLineMiterLimit, "nativeGetLineMiterLimit"), - METHOD(&LineLayer::getLineRoundLimit, "nativeGetLineRoundLimit"), - METHOD(&LineLayer::getLineOpacityTransition, "nativeGetLineOpacityTransition"), - METHOD(&LineLayer::setLineOpacityTransition, "nativeSetLineOpacityTransition"), - METHOD(&LineLayer::getLineOpacity, "nativeGetLineOpacity"), - METHOD(&LineLayer::getLineColorTransition, "nativeGetLineColorTransition"), - METHOD(&LineLayer::setLineColorTransition, "nativeSetLineColorTransition"), - METHOD(&LineLayer::getLineColor, "nativeGetLineColor"), - METHOD(&LineLayer::getLineTranslateTransition, "nativeGetLineTranslateTransition"), - METHOD(&LineLayer::setLineTranslateTransition, "nativeSetLineTranslateTransition"), - METHOD(&LineLayer::getLineTranslate, "nativeGetLineTranslate"), - METHOD(&LineLayer::getLineTranslateAnchor, "nativeGetLineTranslateAnchor"), - METHOD(&LineLayer::getLineWidthTransition, "nativeGetLineWidthTransition"), - METHOD(&LineLayer::setLineWidthTransition, "nativeSetLineWidthTransition"), - METHOD(&LineLayer::getLineWidth, "nativeGetLineWidth"), - METHOD(&LineLayer::getLineGapWidthTransition, "nativeGetLineGapWidthTransition"), - METHOD(&LineLayer::setLineGapWidthTransition, "nativeSetLineGapWidthTransition"), - METHOD(&LineLayer::getLineGapWidth, "nativeGetLineGapWidth"), - METHOD(&LineLayer::getLineOffsetTransition, "nativeGetLineOffsetTransition"), - METHOD(&LineLayer::setLineOffsetTransition, "nativeSetLineOffsetTransition"), - METHOD(&LineLayer::getLineOffset, "nativeGetLineOffset"), - METHOD(&LineLayer::getLineBlurTransition, "nativeGetLineBlurTransition"), - METHOD(&LineLayer::setLineBlurTransition, "nativeSetLineBlurTransition"), - METHOD(&LineLayer::getLineBlur, "nativeGetLineBlur"), - METHOD(&LineLayer::getLineDasharrayTransition, "nativeGetLineDasharrayTransition"), - METHOD(&LineLayer::setLineDasharrayTransition, "nativeSetLineDasharrayTransition"), - METHOD(&LineLayer::getLineDasharray, "nativeGetLineDasharray"), - METHOD(&LineLayer::getLinePatternTransition, "nativeGetLinePatternTransition"), - METHOD(&LineLayer::setLinePatternTransition, "nativeSetLinePatternTransition"), - METHOD(&LineLayer::getLinePattern, "nativeGetLinePattern"), - METHOD(&LineLayer::getLineGradient, "nativeGetLineGradient")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/line_layer.hpp b/src/style/layers/line_layer.hpp deleted file mode 100644 index 75a367ab7..000000000 --- a/src/style/layers/line_layer.hpp +++ /dev/null @@ -1,94 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class LineLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LineLayer"; }; - - LineLayer(jni::JNIEnv&, jni::String&, jni::String&); - - LineLayer(mbgl::Map&, mbgl::style::LineLayer&); - - LineLayer(mbgl::Map&, std::unique_ptr); - - ~LineLayer(); - - // Properties - - jni::Local> getLineCap(jni::JNIEnv&); - - jni::Local> getLineJoin(jni::JNIEnv&); - - jni::Local> getLineMiterLimit(jni::JNIEnv&); - - jni::Local> getLineRoundLimit(jni::JNIEnv&); - - jni::Local> getLineOpacity(jni::JNIEnv&); - void setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineOpacityTransition(jni::JNIEnv&); - - jni::Local> getLineColor(jni::JNIEnv&); - void setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineColorTransition(jni::JNIEnv&); - - jni::Local> getLineTranslate(jni::JNIEnv&); - void setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineTranslateTransition(jni::JNIEnv&); - - jni::Local> getLineTranslateAnchor(jni::JNIEnv&); - - jni::Local> getLineWidth(jni::JNIEnv&); - void setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineWidthTransition(jni::JNIEnv&); - - jni::Local> getLineGapWidth(jni::JNIEnv&); - void setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineGapWidthTransition(jni::JNIEnv&); - - jni::Local> getLineOffset(jni::JNIEnv&); - void setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineOffsetTransition(jni::JNIEnv&); - - jni::Local> getLineBlur(jni::JNIEnv&); - void setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineBlurTransition(jni::JNIEnv&); - - jni::Local> getLineDasharray(jni::JNIEnv&); - void setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLineDasharrayTransition(jni::JNIEnv&); - - jni::Local> getLinePattern(jni::JNIEnv&); - void setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getLinePatternTransition(jni::JNIEnv&); - - jni::Local> getLineGradient(jni::JNIEnv&); - -}; // class LineLayer - -class LineJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::LineLayerFactory { -public: - ~LineJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class LineJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/raster_layer.cpp b/src/style/layers/raster_layer.cpp deleted file mode 100644 index b12267525..000000000 --- a/src/style/layers/raster_layer.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "raster_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::RasterLayer& toRasterLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - RasterLayer::RasterLayer(mbgl::Map& map, mbgl::style::RasterLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - RasterLayer::RasterLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - RasterLayer::~RasterLayer() = default; - - // Property getters - - jni::Local> RasterLayer::getRasterOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterOpacity())); - } - - jni::Local> RasterLayer::getRasterOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterOpacityTransition(options); - } - - jni::Local> RasterLayer::getRasterHueRotate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterHueRotate())); - } - - jni::Local> RasterLayer::getRasterHueRotateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterHueRotateTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterHueRotateTransition(options); - } - - jni::Local> RasterLayer::getRasterBrightnessMin(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMin())); - } - - jni::Local> RasterLayer::getRasterBrightnessMinTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMinTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterBrightnessMinTransition(options); - } - - jni::Local> RasterLayer::getRasterBrightnessMax(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMax())); - } - - jni::Local> RasterLayer::getRasterBrightnessMaxTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMaxTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterBrightnessMaxTransition(options); - } - - jni::Local> RasterLayer::getRasterSaturation(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterSaturation())); - } - - jni::Local> RasterLayer::getRasterSaturationTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterSaturationTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterSaturationTransition(options); - } - - jni::Local> RasterLayer::getRasterContrast(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterContrast())); - } - - jni::Local> RasterLayer::getRasterContrastTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterContrastTransition(); - return std::move(*convert>>(env, options)); - } - - void RasterLayer::setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toRasterLayer(layer).setRasterContrastTransition(options); - } - - jni::Local> RasterLayer::getRasterResampling(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterResampling())); - } - - jni::Local> RasterLayer::getRasterFadeDuration(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toRasterLayer(layer).getRasterFadeDuration())); - } - - - // RasterJavaLayerPeerFactory - - RasterJavaLayerPeerFactory::~RasterJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new RasterLayer(map, toRasterLayer(layer))); - } - - jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new RasterLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void RasterJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&RasterLayer::getRasterOpacityTransition, "nativeGetRasterOpacityTransition"), - METHOD(&RasterLayer::setRasterOpacityTransition, "nativeSetRasterOpacityTransition"), - METHOD(&RasterLayer::getRasterOpacity, "nativeGetRasterOpacity"), - METHOD(&RasterLayer::getRasterHueRotateTransition, "nativeGetRasterHueRotateTransition"), - METHOD(&RasterLayer::setRasterHueRotateTransition, "nativeSetRasterHueRotateTransition"), - METHOD(&RasterLayer::getRasterHueRotate, "nativeGetRasterHueRotate"), - METHOD(&RasterLayer::getRasterBrightnessMinTransition, "nativeGetRasterBrightnessMinTransition"), - METHOD(&RasterLayer::setRasterBrightnessMinTransition, "nativeSetRasterBrightnessMinTransition"), - METHOD(&RasterLayer::getRasterBrightnessMin, "nativeGetRasterBrightnessMin"), - METHOD(&RasterLayer::getRasterBrightnessMaxTransition, "nativeGetRasterBrightnessMaxTransition"), - METHOD(&RasterLayer::setRasterBrightnessMaxTransition, "nativeSetRasterBrightnessMaxTransition"), - METHOD(&RasterLayer::getRasterBrightnessMax, "nativeGetRasterBrightnessMax"), - METHOD(&RasterLayer::getRasterSaturationTransition, "nativeGetRasterSaturationTransition"), - METHOD(&RasterLayer::setRasterSaturationTransition, "nativeSetRasterSaturationTransition"), - METHOD(&RasterLayer::getRasterSaturation, "nativeGetRasterSaturation"), - METHOD(&RasterLayer::getRasterContrastTransition, "nativeGetRasterContrastTransition"), - METHOD(&RasterLayer::setRasterContrastTransition, "nativeSetRasterContrastTransition"), - METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"), - METHOD(&RasterLayer::getRasterResampling, "nativeGetRasterResampling"), - METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/raster_layer.hpp b/src/style/layers/raster_layer.hpp deleted file mode 100644 index 53bee85e2..000000000 --- a/src/style/layers/raster_layer.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class RasterLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/RasterLayer"; }; - - RasterLayer(jni::JNIEnv&, jni::String&, jni::String&); - - RasterLayer(mbgl::Map&, mbgl::style::RasterLayer&); - - RasterLayer(mbgl::Map&, std::unique_ptr); - - ~RasterLayer(); - - // Properties - - jni::Local> getRasterOpacity(jni::JNIEnv&); - void setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterOpacityTransition(jni::JNIEnv&); - - jni::Local> getRasterHueRotate(jni::JNIEnv&); - void setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterHueRotateTransition(jni::JNIEnv&); - - jni::Local> getRasterBrightnessMin(jni::JNIEnv&); - void setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterBrightnessMinTransition(jni::JNIEnv&); - - jni::Local> getRasterBrightnessMax(jni::JNIEnv&); - void setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterBrightnessMaxTransition(jni::JNIEnv&); - - jni::Local> getRasterSaturation(jni::JNIEnv&); - void setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterSaturationTransition(jni::JNIEnv&); - - jni::Local> getRasterContrast(jni::JNIEnv&); - void setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getRasterContrastTransition(jni::JNIEnv&); - - jni::Local> getRasterResampling(jni::JNIEnv&); - - jni::Local> getRasterFadeDuration(jni::JNIEnv&); - -}; // class RasterLayer - -class RasterJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::RasterLayerFactory { -public: - ~RasterJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class RasterJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/symbol_layer.cpp b/src/style/layers/symbol_layer.cpp deleted file mode 100644 index 53b35a9a1..000000000 --- a/src/style/layers/symbol_layer.cpp +++ /dev/null @@ -1,592 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#include "symbol_layer.hpp" - -#include - -#include "../conversion/property_value.hpp" -#include "../conversion/transition_options.hpp" - -#include - -namespace mbgl { -namespace android { - - inline mbgl::style::SymbolLayer& toSymbolLayer(mbgl::style::Layer& layer) { - return static_cast(layer); - } - - /** - * Creates an owning peer object (for layers not attached to the map) from the JVM side - */ - SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) - : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { - } - - /** - * Creates a non-owning peer object (for layers currently attached to the map) - */ - SymbolLayer::SymbolLayer(mbgl::Map& map, mbgl::style::SymbolLayer& coreLayer) - : Layer(map, coreLayer) { - } - - /** - * Creates an owning peer object (for layers not attached to the map) - */ - SymbolLayer::SymbolLayer(mbgl::Map& map, std::unique_ptr coreLayer) - : Layer(map, std::move(coreLayer)) { - } - - SymbolLayer::~SymbolLayer() = default; - - // Property getters - - jni::Local> SymbolLayer::getSymbolPlacement(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolPlacement())); - } - - jni::Local> SymbolLayer::getSymbolSpacing(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSpacing())); - } - - jni::Local> SymbolLayer::getSymbolAvoidEdges(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolAvoidEdges())); - } - - jni::Local> SymbolLayer::getSymbolSortKey(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSortKey())); - } - - jni::Local> SymbolLayer::getSymbolZOrder(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolZOrder())); - } - - jni::Local> SymbolLayer::getIconAllowOverlap(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconAllowOverlap())); - } - - jni::Local> SymbolLayer::getIconIgnorePlacement(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconIgnorePlacement())); - } - - jni::Local> SymbolLayer::getIconOptional(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconOptional())); - } - - jni::Local> SymbolLayer::getIconRotationAlignment(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotationAlignment())); - } - - jni::Local> SymbolLayer::getIconSize(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconSize())); - } - - jni::Local> SymbolLayer::getIconTextFit(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFit())); - } - - jni::Local> SymbolLayer::getIconTextFitPadding(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFitPadding())); - } - - jni::Local> SymbolLayer::getIconImage(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconImage())); - } - - jni::Local> SymbolLayer::getIconRotate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotate())); - } - - jni::Local> SymbolLayer::getIconPadding(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconPadding())); - } - - jni::Local> SymbolLayer::getIconKeepUpright(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconKeepUpright())); - } - - jni::Local> SymbolLayer::getIconOffset(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconOffset())); - } - - jni::Local> SymbolLayer::getIconAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconAnchor())); - } - - jni::Local> SymbolLayer::getIconPitchAlignment(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconPitchAlignment())); - } - - jni::Local> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextPitchAlignment())); - } - - jni::Local> SymbolLayer::getTextRotationAlignment(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotationAlignment())); - } - - jni::Local> SymbolLayer::getTextField(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextField())); - } - - jni::Local> SymbolLayer::getTextFont(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextFont())); - } - - jni::Local> SymbolLayer::getTextSize(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextSize())); - } - - jni::Local> SymbolLayer::getTextMaxWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxWidth())); - } - - jni::Local> SymbolLayer::getTextLineHeight(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextLineHeight())); - } - - jni::Local> SymbolLayer::getTextLetterSpacing(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextLetterSpacing())); - } - - jni::Local> SymbolLayer::getTextJustify(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextJustify())); - } - - jni::Local> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextRadialOffset())); - } - - jni::Local> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextVariableAnchor())); - } - - jni::Local> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextAnchor())); - } - - jni::Local> SymbolLayer::getTextMaxAngle(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxAngle())); - } - - jni::Local> SymbolLayer::getTextWritingMode(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextWritingMode())); - } - - jni::Local> SymbolLayer::getTextRotate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotate())); - } - - jni::Local> SymbolLayer::getTextPadding(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextPadding())); - } - - jni::Local> SymbolLayer::getTextKeepUpright(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextKeepUpright())); - } - - jni::Local> SymbolLayer::getTextTransform(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextTransform())); - } - - jni::Local> SymbolLayer::getTextOffset(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextOffset())); - } - - jni::Local> SymbolLayer::getTextAllowOverlap(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextAllowOverlap())); - } - - jni::Local> SymbolLayer::getTextIgnorePlacement(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextIgnorePlacement())); - } - - jni::Local> SymbolLayer::getTextOptional(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextOptional())); - } - - jni::Local> SymbolLayer::getIconOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconOpacity())); - } - - jni::Local> SymbolLayer::getIconOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconOpacityTransition(options); - } - - jni::Local> SymbolLayer::getIconColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconColor())); - } - - jni::Local> SymbolLayer::getIconColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconColorTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconColorTransition(options); - } - - jni::Local> SymbolLayer::getIconHaloColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloColor())); - } - - jni::Local> SymbolLayer::getIconHaloColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloColorTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconHaloColorTransition(options); - } - - jni::Local> SymbolLayer::getIconHaloWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloWidth())); - } - - jni::Local> SymbolLayer::getIconHaloWidthTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloWidthTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconHaloWidthTransition(options); - } - - jni::Local> SymbolLayer::getIconHaloBlur(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloBlur())); - } - - jni::Local> SymbolLayer::getIconHaloBlurTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloBlurTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconHaloBlurTransition(options); - } - - jni::Local> SymbolLayer::getIconTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslate())); - } - - jni::Local> SymbolLayer::getIconTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setIconTranslateTransition(options); - } - - jni::Local> SymbolLayer::getIconTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslateAnchor())); - } - - jni::Local> SymbolLayer::getTextOpacity(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextOpacity())); - } - - jni::Local> SymbolLayer::getTextOpacityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextOpacityTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextOpacityTransition(options); - } - - jni::Local> SymbolLayer::getTextColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextColor())); - } - - jni::Local> SymbolLayer::getTextColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextColorTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextColorTransition(options); - } - - jni::Local> SymbolLayer::getTextHaloColor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloColor())); - } - - jni::Local> SymbolLayer::getTextHaloColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloColorTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextHaloColorTransition(options); - } - - jni::Local> SymbolLayer::getTextHaloWidth(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloWidth())); - } - - jni::Local> SymbolLayer::getTextHaloWidthTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloWidthTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextHaloWidthTransition(options); - } - - jni::Local> SymbolLayer::getTextHaloBlur(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloBlur())); - } - - jni::Local> SymbolLayer::getTextHaloBlurTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloBlurTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextHaloBlurTransition(options); - } - - jni::Local> SymbolLayer::getTextTranslate(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslate())); - } - - jni::Local> SymbolLayer::getTextTranslateTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextTranslateTransition(); - return std::move(*convert>>(env, options)); - } - - void SymbolLayer::setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - toSymbolLayer(layer).setTextTranslateTransition(options); - } - - jni::Local> SymbolLayer::getTextTranslateAnchor(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslateAnchor())); - } - - - // SymbolJavaLayerPeerFactory - - SymbolJavaLayerPeerFactory::~SymbolJavaLayerPeerFactory() = default; - - namespace { - jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(layer)); - } - } // namespace - - jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& layer) { - assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new SymbolLayer(map, toSymbolLayer(layer))); - } - - jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr layer) { - assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, new SymbolLayer(map, std::unique_ptr(static_cast(layer.release())))); - } - - void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer, - "initialize", - "finalize", - METHOD(&SymbolLayer::getSymbolPlacement, "nativeGetSymbolPlacement"), - METHOD(&SymbolLayer::getSymbolSpacing, "nativeGetSymbolSpacing"), - METHOD(&SymbolLayer::getSymbolAvoidEdges, "nativeGetSymbolAvoidEdges"), - METHOD(&SymbolLayer::getSymbolSortKey, "nativeGetSymbolSortKey"), - METHOD(&SymbolLayer::getSymbolZOrder, "nativeGetSymbolZOrder"), - METHOD(&SymbolLayer::getIconAllowOverlap, "nativeGetIconAllowOverlap"), - METHOD(&SymbolLayer::getIconIgnorePlacement, "nativeGetIconIgnorePlacement"), - METHOD(&SymbolLayer::getIconOptional, "nativeGetIconOptional"), - METHOD(&SymbolLayer::getIconRotationAlignment, "nativeGetIconRotationAlignment"), - METHOD(&SymbolLayer::getIconSize, "nativeGetIconSize"), - METHOD(&SymbolLayer::getIconTextFit, "nativeGetIconTextFit"), - METHOD(&SymbolLayer::getIconTextFitPadding, "nativeGetIconTextFitPadding"), - METHOD(&SymbolLayer::getIconImage, "nativeGetIconImage"), - METHOD(&SymbolLayer::getIconRotate, "nativeGetIconRotate"), - METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"), - METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"), - METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"), - METHOD(&SymbolLayer::getIconAnchor, "nativeGetIconAnchor"), - METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"), - METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"), - METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"), - METHOD(&SymbolLayer::getTextField, "nativeGetTextField"), - METHOD(&SymbolLayer::getTextFont, "nativeGetTextFont"), - METHOD(&SymbolLayer::getTextSize, "nativeGetTextSize"), - METHOD(&SymbolLayer::getTextMaxWidth, "nativeGetTextMaxWidth"), - METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"), - METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"), - METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), - METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), - METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), - METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), - METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), - METHOD(&SymbolLayer::getTextWritingMode, "nativeGetTextWritingMode"), - METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"), - METHOD(&SymbolLayer::getTextPadding, "nativeGetTextPadding"), - METHOD(&SymbolLayer::getTextKeepUpright, "nativeGetTextKeepUpright"), - METHOD(&SymbolLayer::getTextTransform, "nativeGetTextTransform"), - METHOD(&SymbolLayer::getTextOffset, "nativeGetTextOffset"), - METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"), - METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"), - METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"), - METHOD(&SymbolLayer::getIconOpacityTransition, "nativeGetIconOpacityTransition"), - METHOD(&SymbolLayer::setIconOpacityTransition, "nativeSetIconOpacityTransition"), - METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"), - METHOD(&SymbolLayer::getIconColorTransition, "nativeGetIconColorTransition"), - METHOD(&SymbolLayer::setIconColorTransition, "nativeSetIconColorTransition"), - METHOD(&SymbolLayer::getIconColor, "nativeGetIconColor"), - METHOD(&SymbolLayer::getIconHaloColorTransition, "nativeGetIconHaloColorTransition"), - METHOD(&SymbolLayer::setIconHaloColorTransition, "nativeSetIconHaloColorTransition"), - METHOD(&SymbolLayer::getIconHaloColor, "nativeGetIconHaloColor"), - METHOD(&SymbolLayer::getIconHaloWidthTransition, "nativeGetIconHaloWidthTransition"), - METHOD(&SymbolLayer::setIconHaloWidthTransition, "nativeSetIconHaloWidthTransition"), - METHOD(&SymbolLayer::getIconHaloWidth, "nativeGetIconHaloWidth"), - METHOD(&SymbolLayer::getIconHaloBlurTransition, "nativeGetIconHaloBlurTransition"), - METHOD(&SymbolLayer::setIconHaloBlurTransition, "nativeSetIconHaloBlurTransition"), - METHOD(&SymbolLayer::getIconHaloBlur, "nativeGetIconHaloBlur"), - METHOD(&SymbolLayer::getIconTranslateTransition, "nativeGetIconTranslateTransition"), - METHOD(&SymbolLayer::setIconTranslateTransition, "nativeSetIconTranslateTransition"), - METHOD(&SymbolLayer::getIconTranslate, "nativeGetIconTranslate"), - METHOD(&SymbolLayer::getIconTranslateAnchor, "nativeGetIconTranslateAnchor"), - METHOD(&SymbolLayer::getTextOpacityTransition, "nativeGetTextOpacityTransition"), - METHOD(&SymbolLayer::setTextOpacityTransition, "nativeSetTextOpacityTransition"), - METHOD(&SymbolLayer::getTextOpacity, "nativeGetTextOpacity"), - METHOD(&SymbolLayer::getTextColorTransition, "nativeGetTextColorTransition"), - METHOD(&SymbolLayer::setTextColorTransition, "nativeSetTextColorTransition"), - METHOD(&SymbolLayer::getTextColor, "nativeGetTextColor"), - METHOD(&SymbolLayer::getTextHaloColorTransition, "nativeGetTextHaloColorTransition"), - METHOD(&SymbolLayer::setTextHaloColorTransition, "nativeSetTextHaloColorTransition"), - METHOD(&SymbolLayer::getTextHaloColor, "nativeGetTextHaloColor"), - METHOD(&SymbolLayer::getTextHaloWidthTransition, "nativeGetTextHaloWidthTransition"), - METHOD(&SymbolLayer::setTextHaloWidthTransition, "nativeSetTextHaloWidthTransition"), - METHOD(&SymbolLayer::getTextHaloWidth, "nativeGetTextHaloWidth"), - METHOD(&SymbolLayer::getTextHaloBlurTransition, "nativeGetTextHaloBlurTransition"), - METHOD(&SymbolLayer::setTextHaloBlurTransition, "nativeSetTextHaloBlurTransition"), - METHOD(&SymbolLayer::getTextHaloBlur, "nativeGetTextHaloBlur"), - METHOD(&SymbolLayer::getTextTranslateTransition, "nativeGetTextTranslateTransition"), - METHOD(&SymbolLayer::setTextTranslateTransition, "nativeSetTextTranslateTransition"), - METHOD(&SymbolLayer::getTextTranslate, "nativeGetTextTranslate"), - METHOD(&SymbolLayer::getTextTranslateAnchor, "nativeGetTextTranslateAnchor")); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/layers/symbol_layer.hpp b/src/style/layers/symbol_layer.hpp deleted file mode 100644 index 9e494e678..000000000 --- a/src/style/layers/symbol_layer.hpp +++ /dev/null @@ -1,180 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. - -#pragma once - -#include "layer.hpp" -#include "../transition_options.hpp" -#include -#include -#include - -namespace mbgl { -namespace android { - -class SymbolLayer : public Layer { -public: - using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/SymbolLayer"; }; - - SymbolLayer(jni::JNIEnv&, jni::String&, jni::String&); - - SymbolLayer(mbgl::Map&, mbgl::style::SymbolLayer&); - - SymbolLayer(mbgl::Map&, std::unique_ptr); - - ~SymbolLayer(); - - // Properties - - jni::Local> getSymbolPlacement(jni::JNIEnv&); - - jni::Local> getSymbolSpacing(jni::JNIEnv&); - - jni::Local> getSymbolAvoidEdges(jni::JNIEnv&); - - jni::Local> getSymbolSortKey(jni::JNIEnv&); - - jni::Local> getSymbolZOrder(jni::JNIEnv&); - - jni::Local> getIconAllowOverlap(jni::JNIEnv&); - - jni::Local> getIconIgnorePlacement(jni::JNIEnv&); - - jni::Local> getIconOptional(jni::JNIEnv&); - - jni::Local> getIconRotationAlignment(jni::JNIEnv&); - - jni::Local> getIconSize(jni::JNIEnv&); - - jni::Local> getIconTextFit(jni::JNIEnv&); - - jni::Local> getIconTextFitPadding(jni::JNIEnv&); - - jni::Local> getIconImage(jni::JNIEnv&); - - jni::Local> getIconRotate(jni::JNIEnv&); - - jni::Local> getIconPadding(jni::JNIEnv&); - - jni::Local> getIconKeepUpright(jni::JNIEnv&); - - jni::Local> getIconOffset(jni::JNIEnv&); - - jni::Local> getIconAnchor(jni::JNIEnv&); - - jni::Local> getIconPitchAlignment(jni::JNIEnv&); - - jni::Local> getTextPitchAlignment(jni::JNIEnv&); - - jni::Local> getTextRotationAlignment(jni::JNIEnv&); - - jni::Local> getTextField(jni::JNIEnv&); - - jni::Local> getTextFont(jni::JNIEnv&); - - jni::Local> getTextSize(jni::JNIEnv&); - - jni::Local> getTextMaxWidth(jni::JNIEnv&); - - jni::Local> getTextLineHeight(jni::JNIEnv&); - - jni::Local> getTextLetterSpacing(jni::JNIEnv&); - - jni::Local> getTextJustify(jni::JNIEnv&); - - jni::Local> getTextRadialOffset(jni::JNIEnv&); - - jni::Local> getTextVariableAnchor(jni::JNIEnv&); - - jni::Local> getTextAnchor(jni::JNIEnv&); - - jni::Local> getTextMaxAngle(jni::JNIEnv&); - - jni::Local> getTextWritingMode(jni::JNIEnv&); - - jni::Local> getTextRotate(jni::JNIEnv&); - - jni::Local> getTextPadding(jni::JNIEnv&); - - jni::Local> getTextKeepUpright(jni::JNIEnv&); - - jni::Local> getTextTransform(jni::JNIEnv&); - - jni::Local> getTextOffset(jni::JNIEnv&); - - jni::Local> getTextAllowOverlap(jni::JNIEnv&); - - jni::Local> getTextIgnorePlacement(jni::JNIEnv&); - - jni::Local> getTextOptional(jni::JNIEnv&); - - jni::Local> getIconOpacity(jni::JNIEnv&); - void setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconOpacityTransition(jni::JNIEnv&); - - jni::Local> getIconColor(jni::JNIEnv&); - void setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconColorTransition(jni::JNIEnv&); - - jni::Local> getIconHaloColor(jni::JNIEnv&); - void setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconHaloColorTransition(jni::JNIEnv&); - - jni::Local> getIconHaloWidth(jni::JNIEnv&); - void setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconHaloWidthTransition(jni::JNIEnv&); - - jni::Local> getIconHaloBlur(jni::JNIEnv&); - void setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconHaloBlurTransition(jni::JNIEnv&); - - jni::Local> getIconTranslate(jni::JNIEnv&); - void setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIconTranslateTransition(jni::JNIEnv&); - - jni::Local> getIconTranslateAnchor(jni::JNIEnv&); - - jni::Local> getTextOpacity(jni::JNIEnv&); - void setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextOpacityTransition(jni::JNIEnv&); - - jni::Local> getTextColor(jni::JNIEnv&); - void setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextColorTransition(jni::JNIEnv&); - - jni::Local> getTextHaloColor(jni::JNIEnv&); - void setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextHaloColorTransition(jni::JNIEnv&); - - jni::Local> getTextHaloWidth(jni::JNIEnv&); - void setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextHaloWidthTransition(jni::JNIEnv&); - - jni::Local> getTextHaloBlur(jni::JNIEnv&); - void setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextHaloBlurTransition(jni::JNIEnv&); - - jni::Local> getTextTranslate(jni::JNIEnv&); - void setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getTextTranslateTransition(jni::JNIEnv&); - - jni::Local> getTextTranslateAnchor(jni::JNIEnv&); - -}; // class SymbolLayer - -class SymbolJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::SymbolLayerFactory { -public: - ~SymbolJavaLayerPeerFactory() override; - - // JavaLayerPeerFactory overrides. - jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&) final; - jni::Local> createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr) final; - - void registerNative(jni::JNIEnv&) final; - - LayerFactory* getLayerFactory() final { return this; } - -}; // class SymbolJavaLayerPeerFactory - -} // namespace android -} // namespace mbgl diff --git a/src/style/light.cpp b/src/style/light.cpp deleted file mode 100644 index d8ed4d9d9..000000000 --- a/src/style/light.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include "light.hpp" -#include "conversion/transition_options.hpp" -#include "conversion/position.hpp" - -namespace mbgl { -namespace android { - -Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight) - : light(coreLight) , map(&coreMap) { -} - -static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) { - return new Light(map, coreLight); -} - -jni::Local> Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) { - std::unique_ptr peerLight = std::unique_ptr(initializeLightPeer(map, coreLight)); - auto result = peerLight->createJavaPeer(env); - peerLight.release(); - return result; -} - -jni::Local> Light::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); -} - -void Light::setAnchor(jni::JNIEnv& env, const jni::String& property) { - std::string anchorStr = jni::Make(env, property); - if (anchorStr.compare("map") == 0) { - light.setAnchor(LightAnchorType::Map); - } else if (anchorStr.compare("viewport") == 0) { - light.setAnchor(LightAnchorType::Viewport); - } -} - -jni::Local Light::getAnchor(jni::JNIEnv& env) { - auto anchorType = light.getAnchor(); - if (anchorType == LightAnchorType::Map) { - return jni::Make(env, "map"); - } else { - return jni::Make(env, "viewport"); - } -} - -void Light::setPosition(jni::JNIEnv& env, const jni::Object& jposition) { - using namespace mbgl::android::conversion; - auto position = *convert(env, jposition); - light.setPosition(position); -} - -jni::Local> Light::getPosition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::Position position = light.getPosition().asConstant(); - return std::move(*convert>>(env, position)); -} - -jni::Local> Light::getPositionTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = light.getPositionTransition(); - return std::move(*convert>>(env, options)); -} - -void Light::setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - light.setPositionTransition(options); -} - -void Light::setColor(jni::JNIEnv& env, const jni::String& property) { - auto color = Color::parse(jni::Make(env, property)); - if (color) { - light.setColor(color.value()); - } -} - -jni::Local Light::getColor(jni::JNIEnv &env) { - auto color = light.getColor().asConstant(); - return jni::Make(env, color.stringify()); -} - -jni::Local> Light::getColorTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = light.getColorTransition(); - return std::move(*convert>>(env, options)); -} - -void Light::setColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - light.setColorTransition(options); -} - -void Light::setIntensity(jni::JNIEnv&, jni::jfloat property) { - light.setIntensity(property); -} - -jni::jfloat Light::getIntensity(jni::JNIEnv&) { - return light.getIntensity().asConstant(); -} - -jni::Local> Light::getIntensityTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = light.getIntensityTransition(); - return std::move(*convert>>(env, options)); -} - -void Light::setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - light.setIntensityTransition(options); -} - -void Light::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - -#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - METHOD(&Light::getAnchor, "nativeGetAnchor"), - METHOD(&Light::setAnchor, "nativeSetAnchor"), - METHOD(&Light::getPositionTransition, "nativeGetPositionTransition"), - METHOD(&Light::setPositionTransition, "nativeSetPositionTransition"), - METHOD(&Light::getPosition, "nativeGetPosition"), - METHOD(&Light::setPosition, "nativeSetPosition"), - METHOD(&Light::getColorTransition, "nativeGetColorTransition"), - METHOD(&Light::setColorTransition, "nativeSetColorTransition"), - METHOD(&Light::getColor, "nativeGetColor"), - METHOD(&Light::setColor, "nativeSetColor"), - METHOD(&Light::getIntensityTransition, "nativeGetIntensityTransition"), - METHOD(&Light::setIntensityTransition, "nativeSetIntensityTransition"), - METHOD(&Light::getIntensity, "nativeGetIntensity"), - METHOD(&Light::setIntensity, "nativeSetIntensity")); -} - -} // namespace android -} // namespace mb diff --git a/src/style/light.hpp b/src/style/light.hpp deleted file mode 100644 index 97767c4f7..000000000 --- a/src/style/light.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -#include -#include -#include "transition_options.hpp" -#include "position.hpp" -#include -#include - -namespace mbgl { -namespace android { - -using namespace style; - -class Light : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; }; - - static void registerNative(jni::JNIEnv&); - - static jni::Local> createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&); - - Light(mbgl::Map&, mbgl::style::Light&); - - void setAnchor(jni::JNIEnv&, const jni::String&); - jni::Local getAnchor(jni::JNIEnv&); - void setPosition(jni::JNIEnv&, const jni::Object&); - jni::Local> getPosition(jni::JNIEnv&); - void setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getPositionTransition(jni::JNIEnv&); - void setColor(jni::JNIEnv&, const jni::String&); - jni::Local getColor(jni::JNIEnv&); - void setColorTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getColorTransition(jni::JNIEnv&); - void setIntensity(jni::JNIEnv&, jni::jfloat); - jni::jfloat getIntensity(jni::JNIEnv&); - void setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Local> getIntensityTransition(jni::JNIEnv&); - jni::Local> createJavaPeer(jni::JNIEnv&); - -protected: - - // Raw reference to the light - mbgl::style::Light& light; - - // Map is set when the light is retrieved - mbgl::Map* map; -}; -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/position.cpp b/src/style/position.cpp deleted file mode 100644 index 326310be0..000000000 --- a/src/style/position.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "position.hpp" - -namespace mbgl { -namespace android { - -jni::Local> Position::fromPosition(jni::JNIEnv& env, jfloat radialCoordinate, jfloat azimuthalAngle, jfloat polarAngle) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jfloat, jfloat, jfloat)>(env, "fromPosition"); - return javaClass.Call(env, method, radialCoordinate, azimuthalAngle, polarAngle); -} - -void Position::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -float Position::getRadialCoordinate(jni::JNIEnv& env, const jni::Object& position) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "radialCoordinate"); - return position.Get(env, field); -} - -float Position::getAzimuthalAngle(jni::JNIEnv& env, const jni::Object& position) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "azimuthalAngle"); - return position.Get(env, field); -} - -float Position::getPolarAngle(jni::JNIEnv& env, const jni::Object& position) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "polarAngle"); - return position.Get(env, field); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/position.hpp b/src/style/position.hpp deleted file mode 100644 index eb4f5ac67..000000000 --- a/src/style/position.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class Position : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Position"; }; - - static jni::Local> fromPosition(jni::JNIEnv&, jfloat, jfloat, jfloat); - - static void registerNative(jni::JNIEnv&); - - static float getRadialCoordinate(jni::JNIEnv&, const jni::Object&); - static float getAzimuthalAngle(jni::JNIEnv&, const jni::Object&); - static float getPolarAngle(jni::JNIEnv&, const jni::Object&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/sources/custom_geometry_source.cpp b/src/style/sources/custom_geometry_source.cpp deleted file mode 100644 index dccca4cf4..000000000 --- a/src/style/sources/custom_geometry_source.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "custom_geometry_source.hpp" -#include "../../attach_env.hpp" - -#include - -// Java -> C++ conversion -#include "../android_conversion.hpp" -#include "../conversion/filter.hpp" - -// C++ -> Java conversion -#include "../../conversion/conversion.hpp" -#include "../../conversion/collection.hpp" -#include "../../geojson/feature.hpp" -#include - -#include - -namespace mbgl { -namespace android { - - // This conversion is expected not to fail because it's used only in contexts where - // the value was originally a CustomGeometrySourceOptions object on the Java side. If it fails - // to convert, it's a bug in our serialization or Java-side static typing. - static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env, - const jni::Object<>& options, - style::TileFunction fetchFn, - style::TileFunction cancelFn) { - using namespace mbgl::style::conversion; - if (!options) { - return style::CustomGeometrySource::Options(); - } - Error error; - optional result = convert(Value(env, options), error); - if (!result) { - throw std::logic_error(error.message); - } - result->fetchTileFunction = fetchFn; - result->cancelTileFunction = cancelFn; - return *result; - } - - CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, - const jni::String& sourceId, - const jni::Object<>& options) - : Source(env, std::make_unique( - jni::Make(env, sourceId), - convertCustomGeometrySourceOptions(env, options, - std::bind(&CustomGeometrySource::fetchTile, this, std::placeholders::_1), - std::bind(&CustomGeometrySource::cancelTile, this, std::placeholders::_1)))) { - } - - CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - CustomGeometrySource::~CustomGeometrySource() { - releaseThreads(); - } - - void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { - android::UniqueEnv _env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*_env); - static auto fetchTile = javaClass.GetMethod(*_env, "fetchTile"); - - // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. - // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. - // See https://github.com/mapbox/mapbox-gl-native/issues/12551. - if(!javaPeer) { - return; - } - - auto peer = jni::Cast(*_env, javaClass, javaPeer); - peer.Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); - }; - - void CustomGeometrySource::cancelTile(const mbgl::CanonicalTileID& tileID) { - android::UniqueEnv _env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*_env); - static auto cancelTile = javaClass.GetMethod(*_env, "cancelTile"); - - // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. - // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. - // See https://github.com/mapbox/mapbox-gl-native/issues/12551. - if(!javaPeer) { - return; - } - - auto peer = jni::Cast(*_env, javaClass, javaPeer); - peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); - }; - - void CustomGeometrySource::startThreads() { - android::UniqueEnv _env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*_env); - static auto startThreads = javaClass.GetMethod(*_env, "startThreads"); - - assert(javaPeer); - - auto peer = jni::Cast(*_env, javaClass, javaPeer); - peer.Call(*_env, startThreads); - } - - void CustomGeometrySource::releaseThreads() { - android::UniqueEnv _env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*_env); - static auto releaseThreads = javaClass.GetMethod(*_env, "releaseThreads"); - - assert(javaPeer); - - auto peer = jni::Cast(*_env, javaClass, javaPeer); - peer.Call(*_env, releaseThreads); - }; - - bool CustomGeometrySource::isCancelled(jni::jint z, - jni::jint x, - jni::jint y) { - android::UniqueEnv _env = android::AttachEnv(); - - static auto& javaClass = jni::Class::Singleton(*_env); - static auto isCancelled = javaClass.GetMethod(*_env, "isCancelled"); - - assert(javaPeer); - - auto peer = jni::Cast(*_env, javaClass, javaPeer); - return peer.Call(*_env, isCancelled, z, x, y); - }; - - void CustomGeometrySource::setTileData(jni::JNIEnv& env, - jni::jint z, - jni::jint x, - jni::jint y, - const jni::Object& jFeatures) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto geometry = geojson::FeatureCollection::convert(env, jFeatures); - - // Update the core source if not cancelled - if (!isCancelled(z, x ,y)) { - source.as()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); - } - } - - void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) { - source.as()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); - } - - void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, const jni::Object& jBounds) { - auto bounds = LatLngBounds::getLatLngBounds(env, jBounds); - source.as()->CustomGeometrySource::invalidateRegion(bounds); - } - - jni::Local>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env, - const jni::Array>& jfilter) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - std::vector features; - if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) }); - } - return Feature::convert(env, features); - } - - jni::Local> CustomGeometrySource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void CustomGeometrySource::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { - Source::addToMap(env, obj, map, frontend); - startThreads(); - } - - bool CustomGeometrySource::removeFromMap(JNIEnv& env, const jni::Object& source, mbgl::Map& map) { - bool successfullyRemoved = Source::removeFromMap(env, source, map); - if (successfullyRemoved) { - releaseThreads(); - } - return successfullyRemoved; - } - - void CustomGeometrySource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&CustomGeometrySource::querySourceFeatures, "querySourceFeatures"), - METHOD(&CustomGeometrySource::setTileData, "nativeSetTileData"), - METHOD(&CustomGeometrySource::invalidateTile, "nativeInvalidateTile"), - METHOD(&CustomGeometrySource::invalidateBounds, "nativeInvalidateBounds") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/custom_geometry_source.hpp b/src/style/sources/custom_geometry_source.hpp deleted file mode 100644 index 52e4027dd..000000000 --- a/src/style/sources/custom_geometry_source.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include -#include -#include "../../geojson/geometry.hpp" -#include "../../geojson/feature.hpp" -#include "../../geojson/feature_collection.hpp" -#include "../../geometry/lat_lng_bounds.hpp" -#include - -namespace mbgl { -namespace android { - -class CustomGeometrySource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/CustomGeometrySource"; }; - - static void registerNative(jni::JNIEnv&); - - CustomGeometrySource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); - CustomGeometrySource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - ~CustomGeometrySource(); - - bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&) override; - void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&) override; - - void fetchTile(const mbgl::CanonicalTileID& tileID); - void cancelTile(const mbgl::CanonicalTileID& tileID); - bool isCancelled(jni::jint z, jni::jint x, jni::jint y); - void startThreads(); - void releaseThreads(); - -private: - void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, const jni::Object& jf); - - void invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y); - void invalidateBounds(jni::JNIEnv& env, const jni::Object& bounds); - - jni::Local>> querySourceFeatures(jni::JNIEnv&, - const jni::Array>& ); - - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class CustomGeometrySource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/geojson_source.cpp b/src/style/sources/geojson_source.cpp deleted file mode 100644 index 5ff486427..000000000 --- a/src/style/sources/geojson_source.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include "geojson_source.hpp" -#include "../../attach_env.hpp" - -#include - -// Java -> C++ conversion -#include "../android_conversion.hpp" -#include "../conversion/filter.hpp" -#include -#include -#include - -// C++ -> Java conversion -#include "../../conversion/conversion.hpp" -#include "../../conversion/collection.hpp" -#include "../../geojson/feature.hpp" -#include "../conversion/url_or_tileset.hpp" - -#include - -// GeoJSONSource uses a "coalescing" model for high frequency asynchronous data update calls, -// which in practice means, that any update that started processing is going to finish -// and the last scheduled update is going to finish as well. Any updates scheduled during processing can be canceled. -// Conversion from Java features to core ones is done on a worker thread and once finished, -// the ownership of the converted features is returned to the calling thread. -namespace mbgl { -namespace android { - - // This conversion is expected not to fail because it's used only in contexts where - // the value was originally a GeoJsonOptions object on the Java side. If it fails - // to convert, it's a bug in our serialization or Java-side static typing. - static style::GeoJSONOptions convertGeoJSONOptions(jni::JNIEnv& env, const jni::Object<>& options) { - using namespace mbgl::style::conversion; - if (!options) { - return style::GeoJSONOptions(); - } - Error error; - optional result = convert( - mbgl::android::Value(env, options), error); - if (!result) { - throw std::logic_error(error.message); - } - return *result; - } - - GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& options) - : Source(env, std::make_unique( - jni::Make(env, sourceId), - convertGeoJSONOptions(env, options))) - , converter(std::make_unique>(Scheduler::GetBackground())) { - } - - GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) - , converter(std::make_unique>(Scheduler::GetBackground())) { - } - - GeoJSONSource::~GeoJSONSource() = default; - - void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, const jni::String& jString) { - - std::shared_ptr json = std::make_shared(jni::Make(env, jString)); - - Update::Converter converterFn = [this, json](ActorRef _callback) { - converter->self().invoke(&FeatureConverter::convertJson, json, _callback); - }; - - setAsync(converterFn); - } - - void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, const jni::Object& jFeatures) { - setCollectionAsync(env, jFeatures); - } - - void GeoJSONSource::setFeature(jni::JNIEnv& env, const jni::Object& jFeature) { - setCollectionAsync(env, jFeature); - } - - void GeoJSONSource::setGeometry(jni::JNIEnv& env, const jni::Object& jGeometry) { - setCollectionAsync(env, jGeometry); - } - - void GeoJSONSource::setURL(jni::JNIEnv& env, const jni::String& url) { - // Update the core source - source.as()->GeoJSONSource::setURL(jni::Make(env, url)); - } - - jni::Local GeoJSONSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->GeoJSONSource::getURL(); - return url ? jni::Make(env, *url) : jni::Local(); - } - - jni::Local>> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env, - const jni::Array>& jfilter) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - std::vector features; - if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source.getID(), - { {}, toFilter(env, jfilter) }); - } - return Feature::convert(env, features); - } - - jni::Local>> GeoJSONSource::getClusterChildren(jni::JNIEnv& env, const jni::Object& feature) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - if (rendererFrontend) { - mbgl::Feature _feature = Feature::convert(env, feature); - _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); - const auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "children", {}); - if (featureExtension.is()) { - return Feature::convert(env, featureExtension.get()); - } - } - return jni::Array>::New(env, 0); - } - - jni::Local>> GeoJSONSource::getClusterLeaves(jni::JNIEnv& env, const jni::Object& feature, jni::jlong limit, jni::jlong offset) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - if (rendererFrontend) { - mbgl::Feature _feature = Feature::convert(env, feature); - _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); - const std::map options = { {"limit", static_cast(limit)}, - {"offset", static_cast(offset)} }; - auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "leaves", options); - if (featureExtension.is()) { - return Feature::convert(env, featureExtension.get()); - } - } - return jni::Array>::New(env, 0);; - } - - jint GeoJSONSource::getClusterExpansionZoom(jni::JNIEnv& env, const jni::Object& feature) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - if (rendererFrontend) { - mbgl::Feature _feature = Feature::convert(env, feature); - _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); - auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "expansion-zoom", {}); - if (featureExtension.is()) { - auto value = featureExtension.get(); - if (value.is()) { - return value.get(); - } - } - } - return 0; - } - - jni::Local> GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - template - void GeoJSONSource::setCollectionAsync(jni::JNIEnv& env, const jni::Object& jObject) { - auto global = jni::NewGlobal(env, jObject); - auto object = std::make_shared(std::move(global)); - - Update::Converter converterFn = [this, object](ActorRef _callback) { - converter->self().invoke(&FeatureConverter::convertObject, object, _callback); - }; - - setAsync(converterFn); - } - - void GeoJSONSource::setAsync(Update::Converter converterFn) { - awaitingUpdate = std::make_unique( - std::move(converterFn), - std::make_unique>( - *Scheduler::GetCurrent(), - [this](GeoJSON geoJSON) { - // conversion from Java features to core ones finished - android::UniqueEnv _env = android::AttachEnv(); - - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(geoJSON); - - // if there is an awaiting update, execute it, otherwise, release resources - if (awaitingUpdate) { - update = std::move(awaitingUpdate); - update->converterFn(update->callback->self()); - } else { - update.reset(); - } - }) - ); - - // If another update is running, wait - if (update) { - return; - } - - // no updates are being processed, execute this one - update = std::move(awaitingUpdate); - update->converterFn(update->callback->self()); - } - - void GeoJSONSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&GeoJSONSource::setGeoJSONString, "nativeSetGeoJsonString"), - METHOD(&GeoJSONSource::setFeatureCollection, "nativeSetFeatureCollection"), - METHOD(&GeoJSONSource::setFeature, "nativeSetFeature"), - METHOD(&GeoJSONSource::setGeometry, "nativeSetGeometry"), - METHOD(&GeoJSONSource::setURL, "nativeSetUrl"), - METHOD(&GeoJSONSource::getURL, "nativeGetUrl"), - METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures"), - METHOD(&GeoJSONSource::getClusterChildren, "nativeGetClusterChildren"), - METHOD(&GeoJSONSource::getClusterLeaves, "nativeGetClusterLeaves"), - METHOD(&GeoJSONSource::getClusterExpansionZoom, "nativeGetClusterExpansionZoom") - ); - } - - void FeatureConverter::convertJson(std::shared_ptr json, - ActorRef callback) { - using namespace mbgl::style::conversion; - - android::UniqueEnv _env = android::AttachEnv(); - - // Convert the jni object - Error error; - optional converted = parseGeoJSON(*json, error); - if(!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); - return; - } - - callback.invoke(&Callback::operator(), *converted); - } - - template - void FeatureConverter::convertObject(std::shared_ptr, jni::EnvAttachingDeleter>> jObject, ActorRef callback) { - using namespace mbgl::android::geojson; - - android::UniqueEnv _env = android::AttachEnv(); - // Convert the jni object - auto geometry = JNIType::convert(*_env, *jObject); - callback.invoke(&Callback::operator(), GeoJSON(geometry)); - } - - Update::Update(Converter _converterFn, std::unique_ptr> _callback) - : converterFn(std::move(_converterFn)) - , callback(std::move(_callback)) {} - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/geojson_source.hpp b/src/style/sources/geojson_source.hpp deleted file mode 100644 index e737e4192..000000000 --- a/src/style/sources/geojson_source.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include "../../geojson/geometry.hpp" -#include "../../geojson/feature.hpp" -#include "../../geojson/feature_collection.hpp" -#include "../../android_renderer_frontend.hpp" -#include - -namespace mbgl { -namespace android { - -using Callback = std::function; - -struct FeatureConverter { - void convertJson(std::shared_ptr, ActorRef); - - template - void convertObject(std::shared_ptr, jni::EnvAttachingDeleter>>, ActorRef); -}; - -struct Update { - using Converter = std::function)>; - Converter converterFn; - - std::unique_ptr> callback; - - Update(Converter, std::unique_ptr>); -}; - -class GeoJSONSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/GeoJsonSource"; }; - - static void registerNative(jni::JNIEnv&); - - GeoJSONSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); - GeoJSONSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - ~GeoJSONSource(); - -private: - void setGeoJSONString(jni::JNIEnv&, const jni::String&); - void setFeatureCollection(jni::JNIEnv&, const jni::Object&); - void setFeature(jni::JNIEnv&, const jni::Object&); - void setGeometry(jni::JNIEnv&, const jni::Object&); - void setURL(jni::JNIEnv&, const jni::String&); - - jni::Local>> querySourceFeatures(jni::JNIEnv&, - const jni::Array>&); - - jni::Local>> getClusterChildren(jni::JNIEnv&, const jni::Object&); - jni::Local>> getClusterLeaves(jni::JNIEnv&, const jni::Object&, jni::jlong, jni::jlong); - jint getClusterExpansionZoom(jni::JNIEnv&, const jni::Object&); - - jni::Local getURL(jni::JNIEnv&); - - jni::Local> createJavaPeer(jni::JNIEnv&); - std::unique_ptr awaitingUpdate; - std::unique_ptr update; - std::shared_ptr threadPool; - std::unique_ptr> converter; - - template - void setCollectionAsync(jni::JNIEnv&, const jni::Object&); - - void setAsync(Update::Converter); - -}; // class GeoJSONSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/image_source.cpp b/src/style/sources/image_source.cpp deleted file mode 100644 index b42e0e5a5..000000000 --- a/src/style/sources/image_source.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "image_source.hpp" - -// Java -> C++ conversion -#include "../android_conversion.hpp" - -// C++ -> Java conversion -#include "../../conversion/conversion.hpp" -#include -#include - -#include "../../bitmap.hpp" -#include -#include - -namespace mbgl { -namespace android { - - ImageSource::ImageSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object& coordinatesObject) - : Source(env, std::make_unique( - jni::Make(env, sourceId), - LatLngQuad::getLatLngArray(env, coordinatesObject) - ) - ) { - } - - ImageSource::ImageSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - ImageSource::~ImageSource() = default; - - void ImageSource::setURL(jni::JNIEnv& env, const jni::String& url) { - // Update the core source - source.as()->ImageSource::setURL(jni::Make(env, url)); - } - - jni::Local ImageSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->ImageSource::getURL(); - return url ? jni::Make(env, *url) : jni::Local(); - } - - void ImageSource::setImage(jni::JNIEnv& env, const jni::Object& bitmap) { - source.as()->setImage(Bitmap::GetImage(env, bitmap)); - } - - void ImageSource::setCoordinates(jni::JNIEnv& env, const jni::Object& coordinatesObject) { - source.as()->setCoordinates( - LatLngQuad::getLatLngArray(env, coordinatesObject)); - } - - jni::Local> ImageSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void ImageSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&ImageSource::setURL, "nativeSetUrl"), - METHOD(&ImageSource::getURL, "nativeGetUrl"), - METHOD(&ImageSource::setImage, "nativeSetImage"), - METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/image_source.hpp b/src/style/sources/image_source.hpp deleted file mode 100644 index 6c359bf0e..000000000 --- a/src/style/sources/image_source.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "source.hpp" -#include "../../geometry/lat_lng_quad.hpp" -#include -#include - -namespace mbgl { -namespace android { - -class Bitmap; - -class ImageSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; }; - - static void registerNative(jni::JNIEnv&); - - ImageSource(jni::JNIEnv&, const jni::String&, const jni::Object&); - - ImageSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - - ~ImageSource(); - - void setURL(jni::JNIEnv&, const jni::String&); - jni::Local getURL(jni::JNIEnv&); - - void setImage(jni::JNIEnv&, const jni::Object&); - - void setCoordinates(jni::JNIEnv&, const jni::Object&); - -private: - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class ImageSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/raster_dem_source.cpp b/src/style/sources/raster_dem_source.cpp deleted file mode 100644 index f60526a9b..000000000 --- a/src/style/sources/raster_dem_source.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "raster_dem_source.hpp" - -#include "../android_conversion.hpp" -#include "../value.hpp" -#include "../conversion/url_or_tileset.hpp" -#include "source.hpp" - -#include - -#include - -namespace mbgl { -namespace android { - - RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) - : Source( - env, - std::make_unique( - jni::Make(env, sourceId), - convertURLOrTileset(Value(env, urlOrTileSet)), - tileSize - ) - ) { - } - - RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - RasterDEMSource::~RasterDEMSource() = default; - - jni::Local RasterDEMSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->RasterDEMSource::getURL(); - return url ? jni::Make(env, *url) : jni::Local(); - } - - jni::Local> RasterDEMSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void RasterDEMSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&, jni::jint>, - "initialize", - "finalize", - METHOD(&RasterDEMSource::getURL, "nativeGetUrl") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/raster_dem_source.hpp b/src/style/sources/raster_dem_source.hpp deleted file mode 100644 index 0b31c4ecd..000000000 --- a/src/style/sources/raster_dem_source.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include - -namespace mbgl { -namespace android { - -class RasterDEMSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterDemSource"; }; - - static void registerNative(jni::JNIEnv&); - - RasterDEMSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); - RasterDEMSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - ~RasterDEMSource(); - - jni::Local getURL(jni::JNIEnv&); - -private: - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class RasterDEMSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/raster_source.cpp b/src/style/sources/raster_source.cpp deleted file mode 100644 index 535f899c9..000000000 --- a/src/style/sources/raster_source.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "raster_source.hpp" - -#include "../android_conversion.hpp" -#include "../value.hpp" -#include "../conversion/url_or_tileset.hpp" - -#include - -#include - -namespace mbgl { -namespace android { - - RasterSource::RasterSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) - : Source( - env, - std::make_unique( - jni::Make(env, sourceId), - convertURLOrTileset(Value(env, urlOrTileSet)), - tileSize - ) - ) { - } - - RasterSource::RasterSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - RasterSource::~RasterSource() = default; - - jni::Local RasterSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->RasterSource::getURL(); - return url ? jni::Make(env, *url) : jni::Local(); - } - - jni::Local> RasterSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void RasterSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&, jni::jint>, - "initialize", - "finalize", - METHOD(&RasterSource::getURL, "nativeGetUrl") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/raster_source.hpp b/src/style/sources/raster_source.hpp deleted file mode 100644 index 08648f79a..000000000 --- a/src/style/sources/raster_source.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include - -namespace mbgl { -namespace android { - -class RasterSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterSource"; }; - - static void registerNative(jni::JNIEnv&); - - RasterSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); - RasterSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - ~RasterSource(); - - jni::Local getURL(jni::JNIEnv&); - -private: - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class RasterSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/source.cpp b/src/style/sources/source.cpp deleted file mode 100644 index 786e5cb58..000000000 --- a/src/style/sources/source.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "source.hpp" -#include "../android_conversion.hpp" -#include "../../attach_env.hpp" - -#include - -#include -#include - -// Java -> C++ conversion -#include -#include - -// C++ -> Java conversion -#include "../conversion/property_value.hpp" - -#include - -// Core Sources -#include -#include -#include -#include - -// Android Source peers -#include "geojson_source.hpp" -#include "image_source.hpp" -#include "raster_source.hpp" -#include "unknown_source.hpp" -#include "vector_source.hpp" -#include "custom_geometry_source.hpp" -#include "raster_dem_source.hpp" - -namespace mbgl { -namespace android { - - static std::unique_ptr createSourcePeer(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { - if (coreSource.is()) { - return std::make_unique(env, *coreSource.as(), frontend); - } else if (coreSource.is()) { - return std::make_unique(env, *coreSource.as(), frontend); - } else if (coreSource.is()) { - return std::make_unique(env, *coreSource.as(), frontend); - } else if (coreSource.is()) { - return std::make_unique(env, *coreSource.as(), frontend); - } else { - return std::make_unique(env, coreSource, frontend); - } - } - - const jni::Object& Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { - if (!coreSource.peer.has_value()) { - coreSource.peer = createSourcePeer(env, coreSource, frontend); - } - return coreSource.peer.get>()->javaPeer; - } - - Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, const jni::Object& obj, AndroidRendererFrontend& frontend) - : source(coreSource) - , javaPeer(jni::NewGlobal(env, obj)) - , rendererFrontend(&frontend) { - } - - Source::Source(jni::JNIEnv&, std::unique_ptr coreSource) - : ownedSource(std::move(coreSource)) - , source(*ownedSource) { - } - - Source::~Source() { - // Before being added to a map, the Java peer owns this C++ peer and cleans - // up after itself correctly through the jni native peer bindings. - // After being added to the map, the ownership is flipped and the C++ peer has a strong reference - // to it's Java peer, preventing the Java peer from being GC'ed. - // In this case, the core source initiates the destruction, which requires releasing the Java peer, - // while also resetting it's nativePtr to 0 to prevent the subsequent GC of the Java peer from - // re-entering this dtor. - if (ownedSource.get() == nullptr && javaPeer.get() != nullptr) { - // Manually clear the java peer - android::UniqueEnv env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*env); - static auto nativePtrField = javaClass.GetField(*env, "nativePtr"); - javaPeer.Set(*env, nativePtrField, (jlong) 0); - javaPeer.reset(); - } - } - - jni::Local Source::getId(jni::JNIEnv& env) { - return jni::Make(env, source.getID()); - } - - jni::Local Source::getAttribution(jni::JNIEnv& env) { - auto attribution = source.getAttribution(); - return attribution ? jni::Make(env, attribution.value()) : jni::Make(env,""); - } - - void Source::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { - // Check to see if we own the source first - if (!ownedSource) { - throw std::runtime_error("Cannot add source twice"); - } - - // Add source to map and release ownership - map.getStyle().addSource(std::move(ownedSource)); - - // Add peer to core source - source.peer = std::unique_ptr(this); - - // Add strong reference to java source - javaPeer = jni::NewGlobal(env, obj); - - rendererFrontend = &frontend; - } - - bool Source::removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map& map) { - // Cannot remove if not attached yet - if (ownedSource) { - throw std::runtime_error("Cannot remove detached source"); - } - - // Remove the source from the map and take ownership - ownedSource = map.getStyle().removeSource(source.getID()); - - // The source may not be removed if any layers still reference it - return ownedSource != nullptr; - } - - void Source::releaseJavaPeer() { - // We can't release the peer if the source was not removed from the map - if (!ownedSource) { - return; - } - - // Release the peer relationships. These will be re-established when the source is added to a map - assert(ownedSource->peer.has_value()); - ownedSource->peer.get>().release(); - ownedSource->peer = mapbox::base::TypeWrapper(); - - // Release the strong reference to the java peer - assert(javaPeer); - javaPeer.release(); - - rendererFrontend = nullptr; - } - - void Source::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - METHOD(&Source::getId, "nativeGetId"), - METHOD(&Source::getAttribution, "nativeGetAttribution") - ); - - // Register subclasses - GeoJSONSource::registerNative(env); - ImageSource::registerNative(env); - RasterSource::registerNative(env); - UnknownSource::registerNative(env); - VectorSource::registerNative(env); - CustomGeometrySource::registerNative(env); - RasterDEMSource::registerNative(env); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/source.hpp b/src/style/sources/source.hpp deleted file mode 100644 index 93b706425..000000000 --- a/src/style/sources/source.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "../value.hpp" -#include "../../android_renderer_frontend.hpp" - -#include - -namespace mbgl { -namespace android { - -class Source : private mbgl::util::noncopyable { -public: - - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/Source"; }; - - static void registerNative(jni::JNIEnv&); - - static const jni::Object& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - - /* - * Called when a Java object is created for a core source that belongs to a map. - */ - Source(jni::JNIEnv&, mbgl::style::Source&, const jni::Object&, AndroidRendererFrontend&); - - /* - * Called when a Java object is created for a new core source that does not belong to a map. - */ - Source(jni::JNIEnv&, std::unique_ptr); - - virtual ~Source(); - - virtual void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&); - - virtual bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&); - - void releaseJavaPeer(); - - jni::Local getId(jni::JNIEnv&); - - jni::Local getAttribution(jni::JNIEnv&); - -protected: - // Set on newly created sources until added to the map. - std::unique_ptr ownedSource; - - // Raw pointer that is valid at all times. - mbgl::style::Source& source; - - // Set when the source is added to a map. - jni::Global> javaPeer; - - // RendererFrontend pointer is valid only when added to the map. - AndroidRendererFrontend* rendererFrontend { nullptr }; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/unknown_source.cpp b/src/style/sources/unknown_source.cpp deleted file mode 100644 index b5285a5f9..000000000 --- a/src/style/sources/unknown_source.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "unknown_source.hpp" - -namespace { - - // Dummy initializer (We don't support initializing this from the JVM) - std::unique_ptr init(jni::JNIEnv&) { - throw std::runtime_error("UnknownSource should not be initialized from the JVM"); - } - -} // namespace - -namespace mbgl { -namespace android { - - UnknownSource::UnknownSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - jni::Local> UnknownSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void UnknownSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - init, - "initialize", - "finalize" - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/unknown_source.hpp b/src/style/sources/unknown_source.hpp deleted file mode 100644 index f042e2042..000000000 --- a/src/style/sources/unknown_source.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include - -namespace mbgl { -namespace android { - -class UnknownSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/UnknownSource"; }; - - static void registerNative(jni::JNIEnv&); - - UnknownSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - - ~UnknownSource() = default; - -private: - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class UnknownSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/vector_source.cpp b/src/style/sources/vector_source.cpp deleted file mode 100644 index e46fc1a94..000000000 --- a/src/style/sources/vector_source.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "vector_source.hpp" - -#include - -// Java -> C++ conversion -#include "../android_conversion.hpp" -#include "../conversion/filter.hpp" - -// C++ -> Java conversion -#include "../../conversion/conversion.hpp" -#include "../../conversion/collection.hpp" -#include "../../geojson/feature.hpp" -#include "../conversion/url_or_tileset.hpp" - -#include - -#include -#include - -namespace mbgl { -namespace android { - - VectorSource::VectorSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet) - : Source( - env, - std::make_unique( - jni::Make(env, sourceId), - convertURLOrTileset(Value(env, urlOrTileSet)) - ) - ) { - } - - VectorSource::VectorSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { - } - - VectorSource::~VectorSource() = default; - - jni::Local VectorSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->VectorSource::getURL(); - return url ? jni::Make(env, *url) : jni::Local(); - } - - jni::Local>> VectorSource::querySourceFeatures(jni::JNIEnv& env, - const jni::Array& jSourceLayerIds, - const jni::Array>& jfilter) { - using namespace mbgl::android::conversion; - using namespace mbgl::android::geojson; - - std::vector features; - if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source.getID(), - { toVector(env, jSourceLayerIds), toFilter(env, jfilter) }); - } - return Feature::convert(env, features); - } - - jni::Local> VectorSource::createJavaPeer(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, reinterpret_cast(this)); - } - - void VectorSource::registerNative(jni::JNIEnv& env) { - // Lookup the class - static auto& javaClass = jni::Class::Singleton(env); - - #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) - - // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&VectorSource::querySourceFeatures, "querySourceFeatures"), - METHOD(&VectorSource::getURL, "nativeGetUrl") - ); - } - -} // namespace android -} // namespace mbgl diff --git a/src/style/sources/vector_source.hpp b/src/style/sources/vector_source.hpp deleted file mode 100644 index 4cb46c6c6..000000000 --- a/src/style/sources/vector_source.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "source.hpp" -#include -#include "../../geojson/feature.hpp" -#include - -namespace mbgl { -namespace android { - -class VectorSource : public Source { -public: - using SuperTag = Source; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/VectorSource"; }; - - static void registerNative(jni::JNIEnv&); - - VectorSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); - VectorSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); - ~VectorSource(); - -private: - jni::Local>> querySourceFeatures(jni::JNIEnv&, const jni::Array&, - const jni::Array>& jfilter); - - jni::Local getURL(jni::JNIEnv&); - - jni::Local> createJavaPeer(jni::JNIEnv&); - -}; // class VectorSource - -} // namespace android -} // namespace mbgl diff --git a/src/style/transition_options.cpp b/src/style/transition_options.cpp deleted file mode 100644 index d70a04e0d..000000000 --- a/src/style/transition_options.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "transition_options.hpp" - -namespace mbgl { -namespace android { - -jni::Local> TransitionOptions::fromTransitionOptions(jni::JNIEnv& env, jlong duration, jlong delay, jboolean enablePlacementTransitions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jlong, jlong, jboolean)>(env, "fromTransitionOptions"); - return javaClass.Call(env, method, duration, delay, enablePlacementTransitions); -} - -long TransitionOptions::getDuration(jni::JNIEnv& env, const jni::Object& transitionOptions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "duration"); - return transitionOptions.Get(env, field); -} - -long TransitionOptions::getDelay(jni::JNIEnv& env, const jni::Object& transitionOptions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "delay"); - return transitionOptions.Get(env, field); -} - -bool TransitionOptions::isEnablePlacementTransitions(jni::JNIEnv& env, const jni::Object& transitionOptions) { - static auto& javaClass = jni::Class::Singleton(env); - static auto field = javaClass.GetField(env, "enablePlacementTransitions"); - return transitionOptions.Get(env, field); -} - -void TransitionOptions::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/transition_options.hpp b/src/style/transition_options.hpp deleted file mode 100644 index 58656a946..000000000 --- a/src/style/transition_options.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class TransitionOptions : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TransitionOptions"; }; - - static jni::Local> fromTransitionOptions(jni::JNIEnv&, jlong duration, jlong delay, jboolean enablePlacementTransitions); - - static long getDuration(jni::JNIEnv&, const jni::Object&); - - static long getDelay(jni::JNIEnv&, const jni::Object&); - - static bool isEnablePlacementTransitions(jni::JNIEnv&, const jni::Object&); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/src/style/value.cpp b/src/style/value.cpp deleted file mode 100644 index 2f0484072..000000000 --- a/src/style/value.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "value.hpp" - -#include "../java_types.hpp" - -namespace mbgl { -namespace android { - // Instance - - Value::Value(jni::JNIEnv& _env, jni::Local> _value) - : env(_env), - value(std::move(_value)) {} - - Value::Value(jni::JNIEnv& _env, const jni::Object<>& _value) - : env(_env), - value(jni::NewLocal(_env, _value)) {} - - bool Value::isNull() const { - return !value; - } - - bool Value::isArray() const { - return jni::IsInstanceOf(env, value.get(), *java::ObjectArray::jclass); - } - - bool Value::isObject() const { - return jni::IsInstanceOf(env, value.get(), *java::Map::jclass); - } - - bool Value::isString() const { - return jni::IsInstanceOf(env, value.get(), *java::String::jclass); - } - - bool Value::isBool() const { - return jni::IsInstanceOf(env, value.get(), *java::Boolean::jclass); - } - - bool Value::isNumber() const { - return jni::IsInstanceOf(env, value.get(), *java::Number::jclass); - } - - std::string Value::toString() const { - return jni::Make(env, jni::Cast(env, jni::Class::Singleton(env), value)); - } - - float Value::toFloat() const { - return jni::CallMethod(env, value.get(), *java::Number::floatValueMethodId); - } - - double Value::toDouble() const { - return jni::CallMethod(env, value.get(), *java::Number::doubleValueMethodId); - } - - long Value::toLong() const { - return jni::CallMethod(env, value.get(), *java::Number::longValueMethodId); - } - - bool Value::toBool() const { - return jni::CallMethod(env, value.get(), *java::Boolean::booleanValueMethodId); - } - - Value Value::get(const char* key) const { - jni::jobject* member = jni::CallMethod(env, value.get(), *java::Map::getMethodId, jni::Make(env, std::string(key)).get()); - return Value(env, jni::Local>(env, member)); - } - - Value Value::keyArray() const{ - jni::jobject* set = jni::CallMethod(env, value.get(), *java::Map::keySetMethodId); - jni::jobject* array = jni::CallMethod(env, set, *java::Set::toArrayMethodId); - return Value(env, jni::Local>(env, array)); - } - - int Value::getLength() const { - auto array = (jni::jarray*) value.get(); - return jni::GetArrayLength(env, *array); - } - - Value Value::get(const int index) const { - auto array = (jni::jarray*) value.get(); - return Value(env, jni::Local>(env, jni::GetObjectArrayElement(env, *array, index))); - } -} -} - diff --git a/src/style/value.hpp b/src/style/value.hpp deleted file mode 100644 index b507c5ed1..000000000 --- a/src/style/value.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace android { - -class Value { -public: - Value(jni::JNIEnv&, jni::Local>); - Value(jni::JNIEnv&, const jni::Object<>&); - - Value(Value&&) = default; - Value& operator=(Value&&) = delete; - - Value(const Value&) = delete; - Value& operator=(const Value&) = delete; - - bool isNull() const; - bool isArray() const; - bool isObject() const; - bool isString() const; - bool isBool() const; - bool isNumber() const; - - std::string toString() const; - float toFloat() const; - double toDouble() const; - long toLong() const; - bool toBool() const; - Value get(const char* key) const; - Value keyArray() const; - int getLength() const; - Value get(const int index ) const; - - jni::JNIEnv& env; - jni::Local> value; -}; - -} -} diff --git a/src/test/benchmark_runner.cpp b/src/test/benchmark_runner.cpp deleted file mode 100644 index 321a37a02..000000000 --- a/src/test/benchmark_runner.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "runtime.hpp" -#include - -int main(int argc, char *argv[]) { - if (!mbgl::android::initRuntime(argc, argv)) { - return 1; - } - - return mbgl::runBenchmark(argc, argv); -} diff --git a/src/test/runtime.cpp b/src/test/runtime.cpp deleted file mode 100644 index 1f8f16da3..000000000 --- a/src/test/runtime.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "runtime.hpp" -#include "../jni.hpp" -#include "../jni_native.hpp" - -#include -#include -#include -#include -#include - -// Required for art / libsigchain -extern "C" JNIEXPORT void EnsureFrontOfChain(int, struct sigaction*) { } -extern "C" JNIEXPORT void AddSpecialSignalHandlerFn(int, void*) { } -extern "C" JNIEXPORT void RemoveSpecialSignalHandlerFn(int, bool (*) (int, siginfo_t*, void*)) { } - -namespace { -const std::string kClassPathCommand{"--class_path="}; -const std::string kClassPath{"-Djava.class.path="}; -const std::string kDefaultDex{"/data/local/tmp/core-tests/classes.dex"}; -} // namespace - -namespace mbgl { -namespace android { - -bool initRuntime(int argc, char *argv[]) { - void* vmHandle = dlopen("libart.so", RTLD_NOW); - assert(vmHandle != nullptr); - - using CreateJavaVMFn = jint (*)(JavaVM** vm, JNIEnv** env, void* vmArgs); - CreateJavaVMFn createJavaVMFn = reinterpret_cast(dlsym(vmHandle, "JNI_CreateJavaVM")); - assert(createJavaVMFn != nullptr); - - std::string classPath = kClassPath + kDefaultDex; - for (int i = 0; i < argc; ++i) { - const std::string arg{argv[i]}; - if (arg.compare(0, kClassPathCommand.length(), kClassPathCommand) == 0) { - classPath = kClassPath + arg.substr(kClassPathCommand.length()); - break; - } - } - - JavaVMOption options[1]; - options[0].optionString = classPath.c_str(); - - JavaVMInitArgs args; - args.version = JNI_VERSION_1_6; - args.nOptions = 1; - args.options = options; - args.ignoreUnrecognized = JNI_FALSE; - - JavaVM* vm; - JNIEnv* env; - - if (createJavaVMFn(&vm, &env, &args) != JNI_OK) { - return false; - } - - void* runtimeHandle = dlopen("libandroid_runtime.so", RTLD_NOW); - assert(runtimeHandle != nullptr); - - using RegisterNativesFn = jint (*)(JNIEnv* env); - RegisterNativesFn registerNativesFn = reinterpret_cast(dlsym(runtimeHandle, "registerFrameworkNatives")); - assert(registerNativesFn != nullptr); - - if (registerNativesFn(env) != JNI_OK) { - return false; - } - - mbgl::android::registerNatives(vm); - return true; -} - -} // namespace android -} // namespace mbgl diff --git a/src/test/runtime.hpp b/src/test/runtime.hpp deleted file mode 100644 index c5e69d61c..000000000 --- a/src/test/runtime.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace mbgl { -namespace android { - -bool initRuntime(int argc, char *argv[]); - -} // namespace android -} // namespace mbgl diff --git a/src/test/test_runner.cpp b/src/test/test_runner.cpp deleted file mode 100644 index 008e3c574..000000000 --- a/src/test/test_runner.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "runtime.hpp" -#include - -int main(int argc, char *argv[]) { - if (!mbgl::android::initRuntime(argc, argv)) { - return 1; - } - - mbgl::runTests(argc, argv); -} diff --git a/src/test/version-script b/src/test/version-script deleted file mode 100644 index ebc2c1701..000000000 --- a/src/test/version-script +++ /dev/null @@ -1,8 +0,0 @@ -{ -global: - EnsureFrontOfChain; - AddSpecialSignalHandlerFn; - RemoveSpecialSignalHandlerFn; -local: - *; -}; diff --git a/src/text/collator.cpp b/src/text/collator.cpp deleted file mode 100644 index acb4f36ee..000000000 --- a/src/text/collator.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include -#include - -#include - -#include - -#include "../attach_env.hpp" -#include "collator_jni.hpp" - -namespace mbgl { -namespace android { - -void Collator::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setStrength"); - collator.Call(env, method, strength); -} - -jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "compare"); - return collator.Call(env, method, lhs, rhs); -} - -void StringUtils::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod(env, "unaccent"); - return javaClass.Call(env, method, value); -} - -void Locale::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -/* -We would prefer to use for/toLanguageTag, but they're only available in API level 21+ - -jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { - using Signature = jni::Object(jni::String); - auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); - return javaClass.Call(env, method, languageTag); -} - -jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { - using Signature = jni::String(); - auto static method = javaClass.GetMethod(env, "toLanguageTag"); - return locale.Call(env, method); -} -*/ - -jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getLanguage"); - return locale.Call(env, method); -} - -jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getCountry"); - return locale.Call(env, method); -} - -jni::Local> Locale::getDefault(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); - return javaClass.Call(env, method); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language, region); -} - -} // namespace android - -namespace style { -namespace expression { - -class Collator::Impl { -public: - Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) - : caseSensitive(caseSensitive_) - , diacriticSensitive(diacriticSensitive_) - , env(android::AttachEnv()) - { - LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, - android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); - if (!diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); - } else if (diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); - } else if (caseSensitive) { - // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator - // and a fallback implementation of diacritic-insensitivity. - android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); - } - } - - bool operator==(const Impl& other) const { - return caseSensitive == other.caseSensitive && - diacriticSensitive == other.diacriticSensitive && - resolvedLocale() == other.resolvedLocale(); - } - - int compare(const std::string& lhs, const std::string& rhs) const { - bool useUnaccent = !diacriticSensitive && caseSensitive; - // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation - // order, so we have to compromise here. We use Android's case-sensitive Collator - // against strings that have been "unaccented" using non-locale-aware nunicode logic. - // Because of the difference in locale-awareness, this means turning on case-sensitivity - // can _potentially_ change compare results for strings that don't actually have any case - // differences. - jni::Local jlhs = jni::Make(*env, useUnaccent ? - platform::unaccent(lhs) : - lhs); - jni::Local jrhs = jni::Make(*env, useUnaccent ? - platform::unaccent(rhs) : - rhs); - - jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); - - return result; - } - - std::string resolvedLocale() const { - std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); - std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); - - optional resultLanguage; - if (!language.empty()) resultLanguage = language; - optional resultRegion; - if (!region.empty()) resultRegion = region; - - return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); - } - -private: - bool caseSensitive; - bool diacriticSensitive; - - android::UniqueEnv env; - jni::Global> collator; - jni::Global> locale; -}; - - -Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) - : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) -{} - -bool Collator::operator==(const Collator& other) const { - return *impl == *(other.impl); -} - -int Collator::compare(const std::string& lhs, const std::string& rhs) const { - return impl->compare(lhs, rhs); -} - -std::string Collator::resolvedLocale() const { - return impl->resolvedLocale(); -} - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/src/text/collator_jni.hpp b/src/text/collator_jni.hpp deleted file mode 100644 index dd3f84566..000000000 --- a/src/text/collator_jni.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include - -/* - android::Collator and android::Locale are - the JNI wrappers of - java/text/Collator and java/util/Locale - - mbgl::Collator is the portable interface - Both implementations are in collator.cpp - */ - -namespace mbgl { -namespace android { - -class Locale { -public: - static constexpr auto Name() { return "java/util/Locale"; }; - - /* Requires API level 21+ in order to support script/variant - static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); - static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); - */ - static jni::Local> getDefault(jni::JNIEnv&); - static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); - static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); - - static jni::Local> New(jni::JNIEnv&, const jni::String&); - static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -class Collator { -public: - static constexpr auto Name() { return "java/text/Collator"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - - static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); - - static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - - -class StringUtils { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; - - static jni::Local unaccent(jni::JNIEnv&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/text/format_number.cpp b/src/text/format_number.cpp deleted file mode 100644 index 3a41175ec..000000000 --- a/src/text/format_number.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -#include - -#include "../attach_env.hpp" -#include "format_number_jni.hpp" - -namespace mbgl { -namespace android { - -void NumberFormat::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "format"); - return nf.Call(env, method, number); -} - -void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); - return nf.Call(env, method, value); -} - -void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); - return nf.Call(env, method, value); -} - -} // namespace android - -namespace platform { - -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - auto env{ android::AttachEnv() }; - - jni::Global> locale; - LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - - jni::Global> formatter; - if (currency.empty()) { - formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); - android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); - android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); - } else { - formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); - } - - auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); - return jni::Make(*env, result); -} - -} // namespace platform -} // namespace mbgl diff --git a/src/text/format_number_jni.hpp b/src/text/format_number_jni.hpp deleted file mode 100644 index 172003892..000000000 --- a/src/text/format_number_jni.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "collator_jni.hpp" - -/* - android::NumberFormat is the JNI wrapper - of java/text/NumberFormat. - */ - -namespace mbgl { -namespace android { - -class NumberFormat { -public: - static constexpr auto Name() { return "java/text/NumberFormat"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); - static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/src/text/local_glyph_rasterizer.cpp b/src/text/local_glyph_rasterizer.cpp deleted file mode 100644 index 8892ee3f3..000000000 --- a/src/text/local_glyph_rasterizer.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include - -#include - -#include "../attach_env.hpp" -#include "../bitmap.hpp" - -#include "local_glyph_rasterizer_jni.hpp" - -/* - Android implementation of LocalGlyphRasterizer: - Draws CJK glyphs using locally available fonts. - - Follows pattern of GL JS implementation in that: - - Only CJK glyphs are drawn locally (because we can guess their metrics effectively) - * Render size/metrics determined experimentally using Noto Sans - - Configuration is done at map creation time by setting a "font family" - * JS uses a CSS font-family, this uses android.graphics.Typeface - https://developer.android.com/reference/android/graphics/Typeface.html - - We use heuristics to extract a font-weight based on the incoming font stack - * JS tries to extract multiple weights, this implementation only looks for - "bold" - - mbgl::LocalGlyphRasterizer is the portable interface - mbgl::LocalGlyphRasterizer::Impl stores platform-specific configuration data - mbgl::android::LocalGlyphRasterizer is the JNI wrapper - com.mapbox.mapboxsdk.text.LocalGlyphRasterizer is the Java implementation that - actually does the drawing - */ - -namespace mbgl { -namespace android { - -LocalGlyphRasterizer::LocalGlyphRasterizer() { - UniqueEnv env { AttachEnv() }; - - static auto& javaClass = jni::Class::Singleton(*env); - static auto constructor = javaClass.GetConstructor(*env); - - javaObject = jni::NewGlobal(*env, javaClass.New(*env, constructor)); -} - -PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& fontFamily, const bool bold, const GlyphID glyphID) { - UniqueEnv env { AttachEnv() }; - - static auto& javaClass = jni::Class::Singleton(*env); - static auto drawGlyphBitmap = javaClass.GetMethod (jni::String, jni::jboolean, jni::jchar)>(*env, "drawGlyphBitmap"); - - return Bitmap::GetImage(*env, - javaObject.Call(*env, - drawGlyphBitmap, - jni::Make(*env, fontFamily), - static_cast(bold), - static_cast(glyphID))); -} - -void LocalGlyphRasterizer::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -} // namespace android - -class LocalGlyphRasterizer::Impl { -public: - Impl(const optional fontFamily_) - : fontFamily(fontFamily_) - {} - - bool isConfigured() const { - return bool(fontFamily); - } - - PremultipliedImage drawGlyphBitmap(const FontStack& fontStack, GlyphID glyphID) { - bool bold = false; - for (auto font : fontStack) { - std::string lowercaseFont = platform::lowercase(font); - if (lowercaseFont.find("bold") != std::string::npos) { - bold = true; - break; - } - } - return androidLocalGlyphRasterizer.drawGlyphBitmap(*fontFamily, bold, glyphID); - } - -private: - optional fontFamily; - android::LocalGlyphRasterizer androidLocalGlyphRasterizer; -}; - -LocalGlyphRasterizer::LocalGlyphRasterizer(const optional fontFamily) - : impl(std::make_unique(fontFamily)) -{} - -LocalGlyphRasterizer::~LocalGlyphRasterizer() -{} - -bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) { - return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured(); -} - -Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) { - Glyph fixedMetrics; - if (!impl->isConfigured()) { - return fixedMetrics; - } - - fixedMetrics.id = glyphID; - - Size size(35, 35); - - fixedMetrics.metrics.width = size.width; - fixedMetrics.metrics.height = size.height; - fixedMetrics.metrics.left = 3; - fixedMetrics.metrics.top = -10; - fixedMetrics.metrics.advance = 24; - - PremultipliedImage rgbaBitmap = impl->drawGlyphBitmap(fontStack, glyphID); - - // Copy alpha values from RGBA bitmap into the AlphaImage output - fixedMetrics.bitmap = AlphaImage(size); - for (uint32_t i = 0; i < size.width * size.height; i++) { - fixedMetrics.bitmap.data[i] = rgbaBitmap.data[4 * i + 3]; - } - - return fixedMetrics; -} - -} // namespace mbgl diff --git a/src/text/local_glyph_rasterizer_jni.hpp b/src/text/local_glyph_rasterizer_jni.hpp deleted file mode 100644 index e80e84833..000000000 --- a/src/text/local_glyph_rasterizer_jni.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include - -/* - android::LocalGlyphRasterizer is the JNI wrapper of - com/mapbox/mapboxsdk/text/LocalGlyphRasterizer - - mbgl::LocalGlyphRasterizer is the portable interface - Both implementations are in local_glyph_rasterizer.cpp - */ - -namespace mbgl { -namespace android { - -class LocalGlyphRasterizer { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/text/LocalGlyphRasterizer"; }; - - static void registerNative(jni::JNIEnv&); - - LocalGlyphRasterizer(); - - PremultipliedImage drawGlyphBitmap(const std::string& fontFamily, const bool bold, const char16_t glyphID); - -private: - jni::Global> javaObject; -}; - -} // namespace android -} // namespace mbgl diff --git a/src/thread.cpp b/src/thread.cpp deleted file mode 100644 index cd0a72306..000000000 --- a/src/thread.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include - -#include -#include - -#include -#include "jni.hpp" - -// Implementation based on Chromium's platform_thread_android.cc. - -namespace mbgl { -namespace platform { - -thread_local static JNIEnv* env; -thread_local static bool detach; - -std::string getCurrentThreadName() { - char name[32] = "unknown"; - - if (prctl(PR_GET_NAME, name) == -1) { - Log::Warning(Event::General, "Couldn't get thread name"); - } - - return name; -} - -void setCurrentThreadName(const std::string& name) { - if (prctl(PR_SET_NAME, name.c_str()) == -1) { - Log::Warning(Event::General, "Couldn't set thread name"); - } -} - -void makeThreadLowPriority() { - // ANDROID_PRIORITY_LOWEST = 19 - // - // Supposedly would set the priority for the whole process, but - // on Linux/Android it only sets for the current thread. - setpriority(PRIO_PROCESS, 0, 19); -} - -void attachThread() { - using namespace android; - assert(env == nullptr); - detach = attach_jni_thread(theJVM, &env, platform::getCurrentThreadName()); -} - -void detachThread() { - using namespace android; - assert(env); - detach_jni_thread(theJVM, &env, detach); -} - -} // namespace platform -} // namespace mbgl diff --git a/src/timer.cpp b/src/timer.cpp deleted file mode 100644 index a45c48702..000000000 --- a/src/timer.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "run_loop_impl.hpp" - -#include -#include - -#include - -namespace mbgl { -namespace util { - -class Timer::Impl : public RunLoop::Impl::Runnable { -public: - Impl() = default; - - ~Impl() { - stop(); - } - - void start(Duration timeout, Duration repeat_, std::function&& task_) { - stop(); - - repeat = repeat_; - task = std::move(task_); - // Prevent overflows when timeout is set to Duration::max() - due = (timeout == Duration::max()) ? std::chrono::time_point::max() : Clock::now() + - timeout; - loop->addRunnable(this); - } - - void stop() { - loop->removeRunnable(this); - } - - void reschedule() { - if (repeat != Duration::zero()) { - due = Clock::now() + repeat; - loop->wake(); - } else { - stop(); - } - } - - TimePoint dueTime() const override { - return due; - } - - void runTask() override { - reschedule(); - task(); - } - -private: - TimePoint due; - Duration repeat; - - RunLoop::Impl* loop = reinterpret_cast(RunLoop::getLoopHandle()); - - std::function task; -}; - -Timer::Timer() : impl(std::make_unique()) { -} - -Timer::~Timer() = default; - -void Timer::start(Duration timeout, Duration repeat, std::function&& cb) { - impl->start(timeout, repeat, std::move(cb)); -} - -void Timer::stop() { - impl->stop(); -} - -} // namespace util -} // namespace mbgl diff --git a/src/unaccent.cpp b/src/unaccent.cpp deleted file mode 100644 index 8da0ce493..000000000 --- a/src/unaccent.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include "attach_env.hpp" -#include "text/collator_jni.hpp" -#include - -namespace mbgl { -namespace platform { - -std::string unaccent(const std::string& str) { - android::UniqueEnv env = android::AttachEnv(); - jni::Local input = jni::Make(*env, str); - jni::Local unaccented = android::StringUtils::unaccent(*env, input); - return jni::Make(*env, unaccented); -} - -} // namespace platform -} // namespace mbgl From 8a8d19ddd41dc3e230ab23dddf59789567b5a356 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 29 Oct 2019 19:09:56 +0100 Subject: [PATCH 016/185] [build] add CI job with building with buck (#26) --- .circleci/config.yml | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 54fb39d29..4005726d0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,6 +4,7 @@ workflows: version: 2 mapbox-gl-native-android: jobs: + - android-debug-arm-v7-buck - android-arm-template: name: android-debug-arm-v8 - android-release: @@ -17,6 +18,11 @@ commands: - run: name: npm install command: npm install --ignore-scripts + npm-install-vendor: + steps: + - run: + name: npm install + command: cd vendor/mapbox-gl-native && npm install --ignore-scripts prepare-ccache: steps: - run: @@ -89,6 +95,11 @@ commands: keys: - 'gradle/v1/{{ checksum "gradle/dependencies.gradle" }}/{{ checksum "build.gradle" }}/{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}' - 'gradle/v1' + prepare-environment: + steps: + - run: + name: Prepare environment + command: touch "$BASH_ENV" && ./vendor/mapbox-gl-native/scripts/environment.js | tee -a "$BASH_ENV" install-dependencies: parameters: node_modules: @@ -334,4 +345,30 @@ jobs: else make run-android-upload-to-artifactory fi - fi \ No newline at end of file + fi + + # ------------------------------------------------------------------------------ + android-debug-arm-v7-buck: + docker: + - image: mbgl/android-ndk-r17c-buck:07c5ef2e71 + working_directory: /src + environment: + LIBSYSCONFCPUS: 2 + JOBS: 2 + BUILDTYPE: Debug + ANDROID_NDK: /android/sdk/ndk-bundle + steps: + - checkout + - npm-install + - run: + name: Checkout submodules + command: | + git submodule update --init --recursive + - npm-install-vendor + - prepare-environment + - run: + name: Build Android library + command: | + cd vendor/mapbox-gl-native/misc/buck + buck build mapbox-gl-native:android-core + # ------------------------------------------------------------------------------ \ No newline at end of file From a4b4c57a486f430e82803ed760f3c67c9d89d4a3 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Tue, 29 Oct 2019 13:14:17 -0700 Subject: [PATCH 017/185] Adjusting CircleCI README badge to this repo (#30) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cc83efee5..fd284d06c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # [Mapbox Maps SDK for Android](https://www.mapbox.com/android-sdk/) -[![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) +[![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native-android/tree/master.svg?style=shield)](https://circleci.com/gh/mapbox/mapbox-gl-native-android/tree/master) + [![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://docs.mapbox.com/android/maps/overview/) From 50f9717afc8765d3866e1d0ccc200deb804d95b1 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Tue, 29 Oct 2019 13:14:29 -0700 Subject: [PATCH 018/185] Removed BubbleLayout deprecated tag and added explanation (#29) --- .../mapbox/mapboxsdk/annotations/BubbleLayout.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java index f4a1484f8..3ff3143b2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java @@ -14,9 +14,14 @@ import com.mapbox.mapboxsdk.R; /** * Bubble View for Android with custom stroke width and color, arrow size, position and direction. - * @deprecated As of 7.0.0, - * use - * Mapbox Annotation Plugin instead + * This class has been deprecated as of the 7.0.0 version of the Maps SDK for Android. + * However, even though the Maps SDK for Android team hasn't continued work on this class, + * the class is still completely fine to use. This class can be used to create a custom + * {@link android.view.View}, which is then turned into a {@link android.graphics.Bitmap}. + * After the bitmap is added to the {@link com.mapbox.mapboxsdk.maps.Style} object, a + * {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} or the + * + * Mapbox Annotation Plugin can reference the image ID. */ @Deprecated public class BubbleLayout extends LinearLayout { From 1f262f356b4131b262c9d1047f2d84220a63c30d Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 30 Oct 2019 11:20:06 +0100 Subject: [PATCH 019/185] [gl-native] update submodule to latest from master, update snapshot version for release-tequila (#32) --- MapboxGLAndroidSDK/gradle.properties | 2 +- vendor/mapbox-gl-native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MapboxGLAndroidSDK/gradle.properties b/MapboxGLAndroidSDK/gradle.properties index e3fedcde0..e19588917 100644 --- a/MapboxGLAndroidSDK/gradle.properties +++ b/MapboxGLAndroidSDK/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=8.5.0-SNAPSHOT +VERSION_NAME=8.6.0-SNAPSHOT # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 646d4e399..84f2ff108 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 646d4e3996513ed3e9247e958d39ce9e9b506652 +Subproject commit 84f2ff1084ccaec68c7a26243367ae657f6ebe60 From b381086338dfa5c8873730a88b8df1b02f5c368b Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 4 Nov 2019 13:54:40 +0100 Subject: [PATCH 020/185] [offline] update gl-native submodule to include warning log when creating an offline region (#35) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 84f2ff108..ab7cd57de 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 84f2ff1084ccaec68c7a26243367ae657f6ebe60 +Subproject commit ab7cd57de037bc6e71e327cffeb421e08e3b2480 From dfdbaf5493130a19da9978f40d2ff535fff2c0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 13 Nov 2019 14:14:21 +0100 Subject: [PATCH 021/185] bump gl-native submodule and bring platform changes --- CHANGELOG.md | 11 ++++ .../mapboxsdk/offline/OfflineManager.java | 45 ++++++++++++++++ .../mapboxsdk/offline/OfflineRegion.java | 52 ++++++++++++++++++- .../style/expressions/Expression.java | 50 ++++++++++++++++-- .../mapboxsdk/testapp/offline/CacheTest.kt | 16 ++++++ .../mapboxsdk/testapp/style/layer.junit.ejs | 4 ++ scripts/generate-style-code.js | 8 +++ vendor/mapbox-gl-native | 2 +- 8 files changed, 182 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa1add83..43e35db36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## master +### Features +- Added support for [image expression](https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-image) in core library. Runtime APIs for image expression will be implemented separately. [#15877](https://github.com/mapbox/mapbox-gl-native/pull/15877) +- Introduce `OfflineManager#packDatabase` and `OfflineRegion#deleteAndSkipPackDatabase` API in order to decouple offline storage vacuum and delete region operations and thus to gain performance benefits e.g. when several regions should be deleted in a row [#15899](https://github.com/mapbox/mapbox-gl-native/pull/15899) + +### Bugs +- Fixed Geo JSON source flickering on style transition [#15907](https://github.com/mapbox/mapbox-gl-native/pull/15907) + +### Performance improvements +- Convert GeoJSON features to tiles for the loaded source description in a background thread and thus unblock the UI thread [#15885](https://github.com/mapbox/mapbox-gl-native/pull/15885) + ## 8.5.0-alpha.4 - October 24, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.3...android-v8.5.0-alpha.4) since [Mapbox Maps SDK for Android v8.5.0-alpha.3](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.3): ### Bug fixes diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index faed46662..3975e0134 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -8,6 +8,7 @@ import android.support.annotation.Keep; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; + import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.R; @@ -306,6 +307,47 @@ public class OfflineManager { }); } + /** + * Packs the existing database file into a minimal amount of disk space. + *

    + * When the operation is complete or encounters an error, the given callback will be + * executed on the database thread; it is the responsibility of the SDK bindings + * to re-execute a user-provided callback on the main thread. + *

    + * + * @param callback the callback to be invoked when the database was reset or when the operation erred. + */ + public void packDatabase(@Nullable final FileSourceCallback callback) { + fileSource.activate(); + nativePackDatabase(new FileSourceCallback() { + @Override + public void onSuccess() { + handler.post(new Runnable() { + @Override + public void run() { + fileSource.deactivate(); + if (callback != null) { + callback.onSuccess(); + } + } + }); + } + + @Override + public void onError(@NonNull final String message) { + handler.post(new Runnable() { + @Override + public void run() { + fileSource.deactivate(); + if (callback != null) { + callback.onError(message); + } + } + }); + } + }); + } + /** * Forces re-validation of the ambient cache. *

    @@ -648,6 +690,9 @@ public class OfflineManager { @Keep private native void nativeResetDatabase(@Nullable FileSourceCallback callback); + @Keep + private native void nativePackDatabase(@Nullable FileSourceCallback callback); + @Keep private native void nativeInvalidateAmbientCache(@Nullable FileSourceCallback callback); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java index f13128da6..b188d60a9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java @@ -401,7 +401,55 @@ public class OfflineRegion { if (!isDeleted) { isDeleted = true; fileSource.activate(); - deleteOfflineRegion(new OfflineRegionDeleteCallback() { + deleteOfflineRegion(true /*pack*/, new OfflineRegionDeleteCallback() { + @Override + public void onDelete() { + handler.post(new Runnable() { + @Override + public void run() { + fileSource.deactivate(); + callback.onDelete(); + OfflineRegion.this.finalize(); + } + }); + } + + @Override + public void onError(final String error) { + handler.post(new Runnable() { + @Override + public void run() { + isDeleted = false; + fileSource.deactivate(); + callback.onError(error); + } + }); + } + }); + } + } + + /** + * Same as {@link OfflineRegion#delete} but skipping database file packing for performance reasons. + *

    + * Database file packing can be done later with {@link OfflineManager#packDatabase}. + * This method is a useful optimization e.g. when several regions should be deleted in a row. + *

    + *

    + * When the operation is complete or encounters an error, the given callback will be + * executed on the main thread. + *

    + *

    + * After you call this method, you may not call any additional methods on this object. + *

    + * + * @param callback the callback to be invoked + */ + public void deleteAndSkipPackDatabase(@NonNull final OfflineRegionDeleteCallback callback) { + if (!isDeleted) { + isDeleted = true; + fileSource.activate(); + deleteOfflineRegion(false /*pack*/, new OfflineRegionDeleteCallback() { @Override public void onDelete() { handler.post(new Runnable() { @@ -521,7 +569,7 @@ public class OfflineRegion { private native void getOfflineRegionStatus(OfflineRegionStatusCallback callback); @Keep - private native void deleteOfflineRegion(OfflineRegionDeleteCallback callback); + private native void deleteOfflineRegion(boolean pack, OfflineRegionDeleteCallback callback); @Keep private native void updateOfflineRegionMetadata(byte[] metadata, OfflineRegionUpdateMetadataCallback callback); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 34b330880..0003006b7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -5,6 +5,7 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Size; + import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -3150,7 +3151,7 @@ public class Expression { * If set, the min-fraction-digits and max-fraction-digits arguments specify the minimum and maximum number * of fractional digits to include. * - * @param number number expression + * @param number number expression * @param options number formatting options * @return expression */ @@ -3169,7 +3170,7 @@ public class Expression { * If set, the min-fraction-digits and max-fraction-digits arguments specify the minimum and maximum number * of fractional digits to include. * - * @param number number expression + * @param number number expression * @param options number formatting options * @return expression */ @@ -3409,6 +3410,49 @@ public class Expression { return new FormatEntry(literal(text), null); } + /** + * Returns image expression for use in '*-pattern' and 'icon-image' layer properties. Compared to + * string literals that can be used to represent an image, image expression allows to determine an + * image's availability at runtime, thus, can be used in conditional coalesce operator. + * + *

    + * Example usage: + *

    + *
    +   * {@code
    +   * SymbolLayer symbolLayer = new SymbolLayer("layer-id", "source-id");
    +   * symbolLayer.setProperties(
    +   *     iconImage(image(get("key-to-feature")))
    +   * );
    +   * }
    +   * 
    + * + *

    + * Example usage with coalesce operator: + *

    + *
    +   * {@code
    +   * SymbolLayer symbolLayer = new SymbolLayer("layer-id", "source-id");
    +   * symbolLayer.setProperties(
    +   *     iconImage(
    +   *         coalesce(
    +   *             image(literal("maki-11")),
    +   *             image(literal("bicycle-15")),
    +   *             image(literal("default-icon"))
    +   *         )
    +   *     )
    +   * );
    +   * }
    +   * 
    + * + * @param input expression input + * @return expression + * @see Image expression + */ + public static Expression image(@NonNull Expression input) { + return new Expression("image", input); + } + /** * Asserts that the input value is an object. If it is not, the expression is an error * The asserted input value is returned as result. @@ -4430,7 +4474,7 @@ public class Expression { /** * Create an option option entry that is encapsulated as a json object member for an expression. * - * @param type json object member name + * @param type json object member name * @param value json object member value */ Option(@NonNull String type, @NonNull Expression value) { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt index a3214c9f1..da4cfbaf0 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt @@ -85,4 +85,20 @@ class CacheTest { } countDownLatch.await() } + + @Test + fun testSetPackDatabase() { + rule.activity.runOnUiThread { + OfflineManager.getInstance(context).packDatabase(object : OfflineManager.FileSourceCallback { + override fun onSuccess() { + countDownLatch.countDown() + } + + override fun onError(message: String) { + Assert.assertNull("onError should not be called", message) + } + }) + } + countDownLatch.await() + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index 1104cbed9..141114c1a 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -151,6 +151,8 @@ public class <%- camelize(type) %>LayerTest extends BaseLayerTest { layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>("{token}")); <% if (property.type === 'formatted') { -%> assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), <%- defaultExpressionJava(property) %>(Expression.formatEntry(Expression.toString(Expression.get("token"))))); +<% } else if (property.type === 'resolvedImage') {-%> + assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), <%- defaultExpressionJava(property) %>(Expression.toString(Expression.get("token")))); <% } else {-%> assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), Expression.toString(Expression.get("token"))); <% } -%> @@ -169,6 +171,8 @@ public class <%- camelize(type) %>LayerTest extends BaseLayerTest { // Set and Get <% if (property.type === 'formatted') { -%> Expression expression = <%- defaultExpressionJava(property) %>(Expression.formatEntry(Expression.get("undefined"), FormatOption.formatFontScale(2.0), FormatOption.formatTextFont(new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}))); +<% } else if (property.type === 'resolvedImage') { -%> + Expression expression = <%- defaultExpressionJava(property) %>(string(Expression.get("undefined"))); <% } else { -%> Expression expression = <%- defaultExpressionJava(property) %>(Expression.get("undefined")); <% } -%> diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 652b8a98a..ea68a059d 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -72,6 +72,7 @@ global.propertyType = function propertyType(property) { case 'formatted': return 'Formatted'; case 'string': + case 'resolvedImage': return 'String'; case 'enum': return 'String'; @@ -93,6 +94,7 @@ global.propertyJavaType = function propertyType(property) { case 'formatted': return 'Formatted'; case 'string': + case 'resolvedImage': return 'String'; case 'enum': return 'String'; @@ -141,6 +143,7 @@ global.propertyNativeType = function (property) { return 'float'; case 'formatted': case 'string': + case 'resolvedImage': // TODO: replace once we implement image expressions return 'std::string'; case 'enum': if(property['light-property']){ @@ -176,7 +179,10 @@ global.defaultExpressionJava = function(property) { return 'number'; case 'formatted': return 'format'; + case 'resolvedImage': + return "image"; case 'string': + case 'image': return "string"; case 'enum': return "string"; @@ -203,6 +209,7 @@ global.defaultValueJava = function(property) { case 'formatted': return 'new Formatted(new FormattedSection("default"))' case 'string': + case 'resolvedImage': return '"' + property['default'] + '"'; case 'enum': return snakeCaseUpper(property.name) + "_" + snakeCaseUpper(Object.keys(property.values)[0]); @@ -335,6 +342,7 @@ global.evaluatedType = function (property) { return 'float'; case 'formatted': case 'string': + case 'image': return 'std::string'; case 'enum': return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`; diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index ab7cd57de..4c1d03c25 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit ab7cd57de037bc6e71e327cffeb421e08e3b2480 +Subproject commit 4c1d03c257754ecc1555f3e31b3c6ccf45c4bf7b From c396113785c7e3640af7cf0ec23d8fcac87392d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 13 Nov 2019 14:21:39 +0100 Subject: [PATCH 022/185] skip jni layers generation --- .../mapboxsdk/testapp/style/FillExtrusionLayerTest.java | 2 +- .../com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java | 2 +- .../com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java | 2 +- .../com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java | 4 ++-- scripts/generate-style-code.js | 6 +----- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java index cdfd030f9..4b936a4c9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java @@ -244,7 +244,7 @@ public class FillExtrusionLayerTest extends BaseLayerTest { assertNull(layer.getFillExtrusionPattern().getExpression()); // Set and Get - Expression expression = string(Expression.get("undefined")); + Expression expression = image(string(Expression.get("undefined"))); layer.setProperties(fillExtrusionPattern(expression)); assertEquals(layer.getFillExtrusionPattern().getExpression(), expression); } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java index f6e3cc854..4e9dddc0a 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java @@ -319,7 +319,7 @@ public class FillLayerTest extends BaseLayerTest { assertNull(layer.getFillPattern().getExpression()); // Set and Get - Expression expression = string(Expression.get("undefined")); + Expression expression = image(string(Expression.get("undefined"))); layer.setProperties(fillPattern(expression)); assertEquals(layer.getFillPattern().getExpression(), expression); } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java index 5e00890f7..4c8e70d3d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java @@ -486,7 +486,7 @@ public class LineLayerTest extends BaseLayerTest { assertNull(layer.getLinePattern().getExpression()); // Set and Get - Expression expression = string(Expression.get("undefined")); + Expression expression = image(string(Expression.get("undefined"))); layer.setProperties(linePattern(expression)); assertEquals(layer.getLinePattern().getExpression(), expression); } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java index c65e37019..02205b3c9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java @@ -296,7 +296,7 @@ public class SymbolLayerTest extends BaseLayerTest { assertEquals(layer.getIconImage().getValue(), propertyValue); layer.setProperties(iconImage("{token}")); - assertEquals(layer.getIconImage().getExpression(), Expression.toString(Expression.get("token"))); + assertEquals(layer.getIconImage().getExpression(), image(Expression.toString(Expression.get("token")))); } @Test @@ -307,7 +307,7 @@ public class SymbolLayerTest extends BaseLayerTest { assertNull(layer.getIconImage().getExpression()); // Set and Get - Expression expression = string(Expression.get("undefined")); + Expression expression = image(string(Expression.get("undefined"))); layer.setProperties(iconImage(expression)); assertEquals(layer.getIconImage().getExpression(), expression); } diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index ea68a059d..fd9490445 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -374,15 +374,11 @@ const lightJavaUnitTests = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestAp writeIfModified(`MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties})); writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties})); -// Java + JNI Layers (Peer model) -const layerHpp = ejs.compile(fs.readFileSync('src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); -const layerCpp = ejs.compile(fs.readFileSync('src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); +// Java const layerJava = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs', 'utf8'), {strict: true}); const layerJavaUnitTests = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs', 'utf8'), {strict: true}); for (const layer of layers) { - writeIfModified(`src/style/layers/${layer.type.replace('-', '_')}_layer.hpp`, layerHpp(layer)); - writeIfModified(`src/style/layers/${layer.type.replace('-', '_')}_layer.cpp`, layerCpp(layer)); writeIfModified(`MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer)); writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); } From 97722e755527339f0b16eb5dbd052d8e4f10342a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 13 Nov 2019 14:30:03 +0100 Subject: [PATCH 023/185] add collection and style smooth reload example --- .../src/main/AndroidManifest.xml | 11 ++ .../style/CollectionUpdateOnStyleChange.kt | 135 ++++++++++++++++++ ...vity_collection_update_on_style_change.xml | 24 ++++ .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/titles.xml | 1 + 5 files changed, 172 insertions(+) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CollectionUpdateOnStyleChange.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_collection_update_on_style_change.xml diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 73c9b97f2..e29f6e74c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -484,6 +484,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + (R.id.fabStyles) + fabStyles.setOnClickListener { + currentStyleIndex++ + if (currentStyleIndex == STYLES.size) { + currentStyleIndex = 0 + } + mapboxMap.setStyle(Style.Builder().fromUri(STYLES[currentStyleIndex]), this) + } + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + mapView.onDestroy() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + companion object { + + private val STYLES = arrayOf(Style.MAPBOX_STREETS, Style.OUTDOORS, Style.LIGHT, Style.DARK, Style.SATELLITE, Style.SATELLITE_STREETS, Style.TRAFFIC_DAY, Style.TRAFFIC_NIGHT) + + private val featureCollection: FeatureCollection + + init { + val bounds = LatLngBounds.from(60.0, 100.0, -60.0, -100.0) + val points = ArrayList() + for (i in 0 until 1000) { + val latLng = getLatLngInBounds(bounds) + points.add(Point.fromLngLat(latLng.longitude, latLng.latitude)) + } + featureCollection = FeatureCollection.fromFeature(Feature.fromGeometry(LineString.fromLngLats(points))) + } + + private fun getLatLngInBounds(bounds: LatLngBounds): LatLng { + val generator = Random() + val randomLat = bounds.latSouth + generator.nextDouble() * (bounds.latNorth - bounds.latSouth) + val randomLon = bounds.lonWest + generator.nextDouble() * (bounds.lonEast - bounds.lonWest) + return LatLng(randomLat, randomLon) + } + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_collection_update_on_style_change.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_collection_update_on_style_change.xml new file mode 100644 index 000000000..22f99c1e6 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_collection_update_on_style_change.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 7f018a43f..075949be5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -50,6 +50,7 @@ Use a local file as the style Display a map inside a dialog fragment Show bus stops and route in Singapore + Verify that updating the GeoJsonSource across style changes allows for smooth transitions Transform urls on the fly Control the cache management with FileSource API Limit viewport to Iceland diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 90baaed28..0a0166945 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -34,6 +34,7 @@ Gradient line layer Data Driven Style Circle layer + Collection updates on style changes Local Style file GeoJson Clustering Add live realtime data From fb9b566a32418cfc2696cfb27e87fc0c3d34be43 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Fri, 1 Nov 2019 17:37:19 +0100 Subject: [PATCH 024/185] Update mapbox-gl-native and changelog. (#34) * Update changelog for v8.5.0-beta.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43e35db36..f01c2bb01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Performance improvements - Convert GeoJSON features to tiles for the loaded source description in a background thread and thus unblock the UI thread [#15885](https://github.com/mapbox/mapbox-gl-native/pull/15885) +## 8.5.0-beta.1 - November 1, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.4...android-v8.5.0-beta.1) since [Mapbox Maps SDK for Android v8.5.0-alpha.4](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.4): +### Performance improvements + - Convert GeoJSON features to tiles in a background thread and thus unblock the UI thread on updating the GeoJsonSource [#15871](https://github.com/mapbox/mapbox-gl-native/pull/15871) + ## 8.5.0-alpha.4 - October 24, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.3...android-v8.5.0-alpha.4) since [Mapbox Maps SDK for Android v8.5.0-alpha.3](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.3): ### Bug fixes From d582495b02b893ee361e4fc9a7d144defebe906b Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Fri, 8 Nov 2019 16:58:01 +0100 Subject: [PATCH 025/185] Update dependencies and changelog for version 8.5.0. (#49) --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f01c2bb01..fb66cad40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,14 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Performance improvements - Convert GeoJSON features to tiles for the loaded source description in a background thread and thus unblock the UI thread [#15885](https://github.com/mapbox/mapbox-gl-native/pull/15885) +## 8.5.0 - November 8, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-beta.1...android-v8.5.0) since [Mapbox Maps SDK for Android v8.5.0-alpha.4](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-beta.1): +### Bug fixes + - Fixed the rendering bug caused by redundant pending requests for already requested images [#15864](https://github.com/mapbox/mapbox-gl-native/pull/15864) + - Use individual textures for line dash patterns [#15862](https://github.com/mapbox/mapbox-gl-native/pull/15862) + ## 8.5.0-beta.1 - November 1, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.4...android-v8.5.0-beta.1) since [Mapbox Maps SDK for Android v8.5.0-alpha.4](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.4): -### Performance improvements - - Convert GeoJSON features to tiles in a background thread and thus unblock the UI thread on updating the GeoJsonSource [#15871](https://github.com/mapbox/mapbox-gl-native/pull/15871) ## 8.5.0-alpha.4 - October 24, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-alpha.3...android-v8.5.0-alpha.4) since [Mapbox Maps SDK for Android v8.5.0-alpha.3](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-alpha.3): From 652c69bc26eb41e96f505647db342e8ecd18fbbd Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 14 Nov 2019 19:04:53 +0100 Subject: [PATCH 026/185] [docs] - update changelog for alpha.1 for release-tequila (#54) --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb66cad40..be9bb97ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master +## 8.6.0-alpha.1 - November 14, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0...android-v8.6.0-alpha.1) since [Mapbox Maps SDK for Android v8.5.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0): ### Features - Added support for [image expression](https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-image) in core library. Runtime APIs for image expression will be implemented separately. [#15877](https://github.com/mapbox/mapbox-gl-native/pull/15877) - Introduce `OfflineManager#packDatabase` and `OfflineRegion#deleteAndSkipPackDatabase` API in order to decouple offline storage vacuum and delete region operations and thus to gain performance benefits e.g. when several regions should be deleted in a row [#15899](https://github.com/mapbox/mapbox-gl-native/pull/15899) From 2064871502c8078d513f7aae149c3747339832a7 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 15 Nov 2019 19:56:30 +0100 Subject: [PATCH 027/185] [build] use https for git submodules (#57) --- .gitmodules | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index e59e6f17d..7a8ecb57a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "vendor/mapbox-gl-native"] path = vendor/mapbox-gl-native - url = git@github.com:mapbox/mapbox-gl-native.git + url = https://github.com/mapbox/mapbox-gl-native.git [submodule "vendor/mapbox-events-android"] path = vendor/mapbox-events-android - url = git@github.com:mapbox/mapbox-events-android.git + url = https://github.com/mapbox/mapbox-events-android.git [submodule "vendor/mapbox-java"] path = vendor/mapbox-java - url = git@github.com:mapbox/mapbox-java.git + url = https://github.com/mapbox/mapbox-java.git [submodule "vendor/mapbox-gestures-android"] path = vendor/mapbox-gestures-android - url = git@github.com:mapbox/mapbox-gestures-android.git + url = https://github.com/mapbox/mapbox-gestures-android.git From 6cebb51747bfc8b0359c0a875cf2bf7ded58169f Mon Sep 17 00:00:00 2001 From: Dan Swick Date: Fri, 15 Nov 2019 11:00:15 -0800 Subject: [PATCH 028/185] add check for darwin systems to support local javadoc generation (#55) --- Makefile | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index bf1afa79c..b8369143d 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,19 @@ endif buildtype := $(shell echo "$(BUILDTYPE)" | tr "[A-Z]" "[a-z]") -HOST_PLATFORM = linux -HOST_PLATFORM_VERSION = $(shell uname -m) -export NINJA = platform/linux/ninja -export JOBS ?= $(shell grep --count processor /proc/cpuinfo) +ifeq ($(shell uname -s), Darwin) + HOST_PLATFORM = macos + HOST_PLATFORM_VERSION = $(shell uname -m) + export NINJA = platform/macos/ninja + export JOBS ?= $(shell sysctl -n hw.ncpu) +else ifeq ($(shell uname -s), Linux) + HOST_PLATFORM = linux + HOST_PLATFORM_VERSION = $(shell uname -m) + export NINJA = platform/linux/ninja + export JOBS ?= $(shell grep --count processor /proc/cpuinfo) +else + $(error Cannot determine host platform) +endif #### Android targets ########################################################### From 8b20a9288055da0558b58bb6f5918bcf48ec7df9 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Nov 2019 07:22:50 +0100 Subject: [PATCH 029/185] [libaryloader] synchronise access to the library loader load method (#58) --- CHANGELOG.md | 4 ++++ .../src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java | 4 ++-- .../mapboxsdk/module/loader/LibraryLoaderProviderImpl.java | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be9bb97ea..7ffaeaead 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## Master +### Bugs + - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) + ## 8.6.0-alpha.1 - November 14, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0...android-v8.6.0-alpha.1) since [Mapbox Maps SDK for Android v8.5.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0): ### Features diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java index ee9f4b3b6..96e97a850 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java @@ -5,7 +5,7 @@ import com.mapbox.mapboxsdk.log.Logger; /** * Loads the mapbox-gl shared library *

    - * By default uses the {@link System#loadLibrary(String)}, + * By default uses SoLoader from https://github.com/facebook/SoLoader * use {@link #setLibraryLoader(LibraryLoader)} to provide an alternative library loading hook. *

    */ @@ -36,7 +36,7 @@ public abstract class LibraryLoader { * Catches UnsatisfiedLinkErrors and prints a warning to logcat. *

    */ - public static void load() { + public static synchronized void load() { try { if (!loaded) { loaded = true; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/LibraryLoaderProviderImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/LibraryLoaderProviderImpl.java index 9e5e72d40..b5c03d6b9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/LibraryLoaderProviderImpl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/loader/LibraryLoaderProviderImpl.java @@ -12,7 +12,7 @@ import static com.facebook.soloader.SoLoader.loadLibrary; /** * Concrete implementation of a native library loader. *

    - * Uses ReLinker from https://github.com/KeepSafe/ReLinker. + * Uses SoLoader from https://github.com/facebook/SoLoader. *

    */ public class LibraryLoaderProviderImpl implements LibraryLoaderProvider { @@ -28,7 +28,7 @@ public class LibraryLoaderProviderImpl implements LibraryLoaderProvider { } /** - * Concrete implementation of a LibraryLoader using ReLinker. + * Concrete implementation of a LibraryLoader using SoLoader. */ private static class SoLibraryLoader extends LibraryLoader { @@ -43,6 +43,7 @@ public class LibraryLoaderProviderImpl implements LibraryLoaderProvider { } catch (MapboxConfigurationException exception) { Logger.e(TAG, "Couldn't load so file with relinker, application context missing, " + "call Mapbox.getInstance(Context context, String accessToken) first"); + throw new UnsatisfiedLinkError(exception.getMessage()); } } } From 3cc7e29dd1c01590057d57d828ce692fb6a3e19c Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Mon, 18 Nov 2019 11:28:20 -0800 Subject: [PATCH 030/185] [build] Added automated API javadoc generation scripting (#53) --- .circleci/config.yml | 11 +++++- ...trigger-maps-documentation-deploy-steps.sh | 36 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 scripts/trigger-maps-documentation-deploy-steps.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 4005726d0..97105cd0d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -172,6 +172,15 @@ commands: gcloud auth activate-service-account --key-file secret.json --project mapbox-gl-native-android rm secret.json fi + generate-api-javadoc: + steps: + - run: + name: Generate Maps SDK API javadoc and transfer to `/android-docs` + command: | + export VERSION_TAG=${CIRCLE_TAG} + export GITHUB_TOKEN=${DANGER_GITHUB_API_TOKEN} + export DOCS_REPO="android-docs" + bash scripts/trigger-maps-documentation-deploy-steps.sh jobs: # ------------------------------------------------------------------------------ @@ -346,7 +355,7 @@ jobs: make run-android-upload-to-artifactory fi fi - + - generate-api-javadoc # ------------------------------------------------------------------------------ android-debug-arm-v7-buck: docker: diff --git a/scripts/trigger-maps-documentation-deploy-steps.sh b/scripts/trigger-maps-documentation-deploy-steps.sh new file mode 100644 index 000000000..d3778de21 --- /dev/null +++ b/scripts/trigger-maps-documentation-deploy-steps.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -euo pipefail + +function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; } +function finish { >&2 echo -en "\033[0m"; } +trap finish EXIT + +SDK_FLAVOR=${SDK_FLAVOR:-"maps"} + +step "Triggering automated site and documentation generation for ${SDK_FLAVOR} SDK ${VERSION_TAG}" + +# No branch specified, so default branch will be used +request_body="{ + \"request\": { + \"message\": \"[${SDK_FLAVOR}] ${VERSION_TAG} automated site and documentation generation\", + \"config\": { + \"merge_mode\": \"deep_merge\", + \"env\": { + \"SDK_FLAVOR\": \"${SDK_FLAVOR}\", + \"RELEASE_TAG\": \"${VERSION_TAG}\" + } + } + } +}" + +step "Making request…" + +# Request URL set to docs-sandbox while testing +curl -s -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Travis-API-Version: 3" \ + -H "Authorization: token ${TRAVISCI_API_TOKEN}" \ + -d "${request_body}" \ + https://api.travis-ci.com/repo/mapbox%2F${DOCS_REPO}/requests \ No newline at end of file From 004071ac33b9278176b7190ba3b3c189c14d0007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 20 Nov 2019 17:20:05 +0100 Subject: [PATCH 031/185] changelog for v8.5.1 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ffaeaead..4d4ab893f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Bugs - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) +## 8.5.1 - November 20, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0...android-v8.5.1) since [Mapbox Maps SDK for Android v8.5.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0): +### Bugs +- Fixed Geo JSON source flickering on style transition [#15907](https://github.com/mapbox/mapbox-gl-native/pull/15907) +- Fixed flickering caused by unnecessary removing and re-adding of the render sources when the order of their corresponding style objects was changed in the updated style [#15941](https://github.com/mapbox/mapbox-gl-native/pull/15941) + ## 8.6.0-alpha.1 - November 14, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0...android-v8.6.0-alpha.1) since [Mapbox Maps SDK for Android v8.5.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0): ### Features @@ -19,7 +25,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Convert GeoJSON features to tiles for the loaded source description in a background thread and thus unblock the UI thread [#15885](https://github.com/mapbox/mapbox-gl-native/pull/15885) ## 8.5.0 - November 8, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-beta.1...android-v8.5.0) since [Mapbox Maps SDK for Android v8.5.0-alpha.4](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-beta.1): +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0-beta.1...android-v8.5.0) since [Mapbox Maps SDK for Android v8.5.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0-beta.1): ### Bug fixes - Fixed the rendering bug caused by redundant pending requests for already requested images [#15864](https://github.com/mapbox/mapbox-gl-native/pull/15864) - Use individual textures for line dash patterns [#15862](https://github.com/mapbox/mapbox-gl-native/pull/15862) From 72c28e449546a7e30bf8b682d4aba37563b3027f Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 22 Nov 2019 13:29:44 +0200 Subject: [PATCH 032/185] [gl-native] update gl-native to latest --- .../java/com/mapbox/mapboxsdk/offline/OfflineManager.java | 6 +++--- .../java/com/mapbox/mapboxsdk/offline/OfflineRegion.java | 2 +- vendor/mapbox-gl-native | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index 3975e0134..dec234adf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -604,8 +604,8 @@ public class OfflineManager { @NonNull final CreateOfflineRegionCallback callback) { if (!isValidOfflineRegionDefinition(definition)) { callback.onError( - String.format(context.getString(R.string.mapbox_offline_error_region_definition_invalid), - definition.getBounds()) + String.format(context.getString(R.string.mapbox_offline_error_region_definition_invalid), + definition.getBounds()) ); return; } @@ -724,4 +724,4 @@ public class OfflineManager { @Keep public native void putResourceWithUrl(String url, byte[] data, long modified, long expires, String etag, boolean mustRevalidate); -} +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java index b188d60a9..2ad66f044 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java @@ -577,4 +577,4 @@ public class OfflineRegion { @Keep private native void invalidateOfflineRegion(OfflineRegionInvalidateCallback callback); -} +} \ No newline at end of file diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 4c1d03c25..a02ed76d5 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 4c1d03c257754ecc1555f3e31b3c6ccf45c4bf7b +Subproject commit a02ed76d5bfcb2a4623eb3dd1256252ab2cf9281 From 76d2a4bcfd060eee4ae759f4fd8fce8fccb965ac Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Fri, 22 Nov 2019 13:38:47 -0800 Subject: [PATCH 033/185] [docs] - changelog update for 8.6.0-alpha.2 release (#67) --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d4ab893f..b8e4194d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## Master +## 8.6.0-alpha.2 - November 22, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): + ### Bugs - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) From 561c2ed335e15b4245e567421b214b4b8cb948eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 27 Nov 2019 12:14:16 +0100 Subject: [PATCH 034/185] add SoLoader's proaguard rule --- MapboxGLAndroidSDK/proguard-rules.pro | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/proguard-rules.pro b/MapboxGLAndroidSDK/proguard-rules.pro index f592efa6b..1035bb01d 100644 --- a/MapboxGLAndroidSDK/proguard-rules.pro +++ b/MapboxGLAndroidSDK/proguard-rules.pro @@ -38,4 +38,10 @@ # while we don't include this dependency directly # a large amount of users combine it with our SDK # we aren't able to provide a proguard config in that project (jar vs aar) --dontwarn com.sun.xml.internal.ws.spi.db.* \ No newline at end of file +-dontwarn com.sun.xml.internal.ws.spi.db.* + +# config for SoLoader https://github.com/mapbox/mapbox-gl-native-android/issues/60, +# https://github.com/facebook/SoLoader/blob/master/java/com/facebook/soloader/soloader.pro +-keep class com.facebook.soloader.SysUtil$LollipopSysdeps { + public ; +} \ No newline at end of file From 4de847e9ca053d297ae3d16839ae79e9a4633348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 27 Nov 2019 12:43:27 +0100 Subject: [PATCH 035/185] add gnustl_shared shared build run on a low-end device --- .circleci/config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 97105cd0d..6c46c66de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,6 +7,13 @@ workflows: - android-debug-arm-v7-buck - android-arm-template: name: android-debug-arm-v8 + - android-arm-template: + name: android-gnustl-arm-v7 + stl: gnustl_shared + firebase_device_id: "flo" + firebase_device_os: "21" + image: android-ndk-r17c:1d5db0eb34 + abi: arm-v7 - android-release: filters: tags: From b1fe1433b07182a3cddf827fa8d33fc30ade63a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 27 Nov 2019 13:35:42 +0100 Subject: [PATCH 036/185] bump mapbox-gl-native pin --- CHANGELOG.md | 3 +++ vendor/mapbox-gl-native | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e4194d1..55d53e0fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## master +- Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) + ## 8.6.0-alpha.2 - November 22, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index a02ed76d5..f10097640 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit a02ed76d5bfcb2a4623eb3dd1256252ab2cf9281 +Subproject commit f10097640a8a62f9a139952844a75ac9b0b12543 From 4bde987fb91865ae70be03cbaa78a227b3185b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 3 Dec 2019 11:03:43 +0100 Subject: [PATCH 037/185] invoke location camera transition finish callback when equal mode is set --- .../location/LocationCameraController.java | 3 ++ .../LocationCameraControllerTest.java | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index 79d2e02bf..47d4fe0ae 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -103,6 +103,9 @@ final class LocationCameraController { @Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt, @Nullable OnLocationCameraTransitionListener internalTransitionListener) { if (this.cameraMode == cameraMode) { + if (internalTransitionListener != null) { + internalTransitionListener.onLocationCameraTransitionFinished(cameraMode); + } return; } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java index d1b8642c3..f068c94ce 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java @@ -643,6 +643,36 @@ public class LocationCameraControllerTest { any(MapboxMap.CancelableCallback.class)); } + @Test + public void transition_duplicateMode() { + MapboxMap mapboxMap = mock(MapboxMap.class); + Transform transform = mock(Transform.class); + when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); + LocationCameraController camera = buildCamera(mapboxMap, transform); + camera.initializeOptions(mock(LocationComponentOptions.class)); + final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class); + Location location = mock(Location.class); + + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + listener.onLocationCameraTransitionFinished(TRACKING); + return null; + } + }).when(transform).animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener); + verify(listener, times(1)).onLocationCameraTransitionFinished(TRACKING); + verify(transform, times(1)) + .animateCamera(eq(mapboxMap), any(CameraUpdate.class), any(Integer.class), + any(MapboxMap.CancelableCallback.class)); + } + @Test public void transition_canceled() { MapboxMap mapboxMap = mock(MapboxMap.class); From 9a40605133f7f769a1de876f8136d3a624206071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 3 Dec 2019 12:24:05 +0100 Subject: [PATCH 038/185] invoke cancelable callback when zoom/tilt while tracking is ignored --- .../mapboxsdk/location/LocationComponent.java | 21 ++- .../location/LocationComponentTest.kt | 120 ++++++++++++++++++ 2 files changed, 137 insertions(+), 4 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 952da885f..f8933d4c1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -739,14 +739,15 @@ public final class LocationComponent { @Nullable MapboxMap.CancelableCallback callback) { checkActivationState(); if (!isLayerReady) { + notifyUnsuccessfulCameraOperation(callback, null); return; } else if (getCameraMode() == CameraMode.NONE) { - Logger.e(TAG, String.format("%s%s", + notifyUnsuccessfulCameraOperation(callback, String.format("%s%s", "LocationComponent#zoomWhileTracking method can only be used", " when a camera mode other than CameraMode#NONE is engaged.")); return; } else if (locationCameraController.isTransitioning()) { - Logger.e(TAG, + notifyUnsuccessfulCameraOperation(callback, "LocationComponent#zoomWhileTracking method call is ignored because the camera mode is transitioning"); return; } @@ -817,14 +818,15 @@ public final class LocationComponent { @Nullable MapboxMap.CancelableCallback callback) { checkActivationState(); if (!isLayerReady) { + notifyUnsuccessfulCameraOperation(callback, null); return; } else if (getCameraMode() == CameraMode.NONE) { - Logger.e(TAG, String.format("%s%s", + notifyUnsuccessfulCameraOperation(callback, String.format("%s%s", "LocationComponent#tiltWhileTracking method can only be used", " when a camera mode other than CameraMode#NONE is engaged.")); return; } else if (locationCameraController.isTransitioning()) { - Logger.e(TAG, + notifyUnsuccessfulCameraOperation(callback, "LocationComponent#tiltWhileTracking method call is ignored because the camera mode is transitioning"); return; } @@ -1607,6 +1609,17 @@ public final class LocationComponent { } } + private void notifyUnsuccessfulCameraOperation(@Nullable MapboxMap.CancelableCallback callback, + @Nullable String msg) { + if (msg != null) { + Logger.e(TAG, msg); + } + + if (callback != null) { + callback.onCancel(); + } + } + /** * Returns whether the location component is activated. * diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index 648a1d214..4a2839361 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -467,4 +467,124 @@ class LocationComponentTest { verify(locationAnimatorCoordinator).resetAllLayerAnimations() verify(renderChangeListener).onRenderModeChanged(RenderMode.NORMAL) } + + @Test + fun tiltWhileTracking_notReady() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.tiltWhileTracking(30.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewTilt(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun tiltWhileTracking_notTracking() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.NONE) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.tiltWhileTracking(30.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewTilt(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun tiltWhileTracking_transitioning() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING) + `when`(locationCameraController.isTransitioning).thenReturn(true) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.tiltWhileTracking(30.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewTilt(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun tiltWhileTracking_sucessful() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING) + `when`(locationCameraController.isTransitioning).thenReturn(false) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.tiltWhileTracking(30.0, 500L, callback) + verify(callback, times(0)).onCancel() + verify(locationAnimatorCoordinator).feedNewTilt(30.0, CameraPosition.DEFAULT, 500L, callback) + } + + @Test + fun zoomWhileTracking_notReady() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.zoomWhileTracking(14.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewZoomLevel(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun zoomWhileTracking_notTracking() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.NONE) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.zoomWhileTracking(14.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewZoomLevel(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun zoomWhileTracking_transitioning() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING) + `when`(locationCameraController.isTransitioning).thenReturn(true) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.zoomWhileTracking(14.0, 500L, callback) + verify(callback).onCancel() + verify(locationAnimatorCoordinator, times(0)).feedNewZoomLevel(anyDouble(), any(), anyLong(), any()) + } + + @Test + fun zoomWhileTracking_successful() { + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + `when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING) + `when`(locationCameraController.isTransitioning).thenReturn(false) + locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + + val callback = mock(MapboxMap.CancelableCallback::class.java) + + locationComponent.zoomWhileTracking(14.0, 500L, callback) + verify(callback, times(0)).onCancel() + verify(locationAnimatorCoordinator).feedNewZoomLevel(14.0, CameraPosition.DEFAULT, 500L, callback) + } } \ No newline at end of file From 703edff8f4af4167cc728c5146b424d2d7765960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 3 Dec 2019 12:42:47 +0100 Subject: [PATCH 039/185] add changelog entry for #80 and #83 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d53e0fd..d18f4f863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,13 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. ## master +### Performance improvements - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) +### Bug fixes +- Fixed a bug where location camera mode transition callback would not get notified if the requested mode was already set. [#80](https://github.com/mapbox/mapbox-gl-native-android/pull/80) +- Fixed a bug where location tilt/zoom while tracking callback would not get notified if the request was ignored. [#83](https://github.com/mapbox/mapbox-gl-native-android/pull/83) + ## 8.6.0-alpha.2 - November 22, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): From 8fe32cc8ac8707eb27026e8c319782eb19e266cf Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 3 Dec 2019 14:09:40 +0100 Subject: [PATCH 040/185] [ci] remove core benchmark trigger (#86) --- .circleci/config.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c46c66de..731706010 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -293,14 +293,6 @@ jobs: - run: name: Android nitpick command: make run-android-nitpick - - run: - name: Trigger core benchmark run - command: | - if [ -n "${MOBILE_METRICS_TOKEN}" ]; then - if [[ $CIRCLE_BRANCH == master ]]; then - curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-core-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master - fi - fi - run: name: Trigger android benchmark run command: | From e8678922e4899acd8b10c0d6712a3089051648de Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 3 Dec 2019 16:28:16 +0100 Subject: [PATCH 041/185] Introduce OfflineManager.runPackDatabaseAutomatically(boolean) API (#78) * [offline] Introduce OfflineManager.runPackDatabaseAutomatically(boolean) API * [doc] update changelog * [doc] add note to offline region delete API --- CHANGELOG.md | 6 +++ .../mapboxsdk/offline/OfflineManager.java | 31 +++++++++-- .../mapboxsdk/offline/OfflineRegion.java | 54 ++----------------- vendor/mapbox-gl-native | 2 +- 4 files changed, 38 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d18f4f863..b24c41ef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,18 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. ## master + +### Features +- Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) + ### Performance improvements - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) ### Bug fixes - Fixed a bug where location camera mode transition callback would not get notified if the requested mode was already set. [#80](https://github.com/mapbox/mapbox-gl-native-android/pull/80) - Fixed a bug where location tilt/zoom while tracking callback would not get notified if the request was ignored. [#83](https://github.com/mapbox/mapbox-gl-native-android/pull/83) +- Use -Oz to reduce binary size [#15984](https://github.com/mapbox/mapbox-gl-native/pull/15984) +- Use icf=all compile flag to reduce binary size [#15987](https://github.com/mapbox/mapbox-gl-native/pull/15987) ## 8.6.0-alpha.2 - November 22, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index dec234adf..b5f296a7a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -310,6 +310,10 @@ public class OfflineManager { /** * Packs the existing database file into a minimal amount of disk space. *

    + * This operation has a performance impact as it will vacuum the database, + * forcing it to move pages on the filesystem. + *

    + *

    * When the operation is complete or encounters an error, the given callback will be * executed on the database thread; it is the responsibility of the SDK bindings * to re-execute a user-provided callback on the main thread. @@ -397,9 +401,9 @@ public class OfflineManager { /** * Erase resources from the ambient cache, freeing storage space. *

    - * Erases the ambient cache, freeing resources. This operation can be - * potentially slow because it will trigger a VACUUM on SQLite, - * forcing the database to move pages on the filesystem. + * Erases the ambient cache, freeing resources. + * Note that this operation can be potentially slow if packing the database + * occurs automatically ({@link OfflineManager#runPackDatabaseAutomatically(boolean)}). *

    *

    * Resources overlapping with offline regions will not be affected @@ -662,7 +666,7 @@ public class OfflineManager { *

    * Once this limit is reached, {@link OfflineRegion.OfflineRegionObserver#mapboxTileCountLimitExceeded(long)} * fires every additional attempt to download additional tiles until already downloaded tiles are removed - * by calling {@link OfflineRegion#deleteOfflineRegion(OfflineRegion.OfflineRegionDeleteCallback)}. + * by calling {@link OfflineRegion#delete(OfflineRegion.OfflineRegionDeleteCallback)}. *

    * * @param limit the maximum number of tiles allowed to be downloaded @@ -670,6 +674,25 @@ public class OfflineManager { @Keep public native void setOfflineMapboxTileCountLimit(long limit); + + /** + * Sets whether database file packing occurs automatically. + * By default, the automatic database file packing is enabled. + *

    + * If packing is enabled, database file packing occurs automatically + * after an offline region is deleted by calling + * {@link OfflineRegion#delete(OfflineRegion.OfflineRegionDeleteCallback)} + * or the ambient cache is cleared by calling {@link OfflineManager#clearAmbientCache()}. + * + * If packing is disabled, disk space will not be freed after + * resources are removed unless {@link OfflineManager#packDatabase()} is explicitly called. + *

    + * + * @param autopack flag setting the automatic database file packing. + */ + @Keep + public native void runPackDatabaseAutomatically(boolean autopack); + @Keep private native void initialize(FileSource fileSource); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java index 2ad66f044..79928c649 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java @@ -391,6 +391,8 @@ public class OfflineRegion { * When the operation is complete or encounters an error, the given callback will be * executed on the main thread. *

    + * Note that this operation can be potentially slow if packing the database + * occurs automatically ({@link OfflineManager#runPackDatabaseAutomatically(boolean)}) *

    * After you call this method, you may not call any additional methods on this object. *

    @@ -401,55 +403,7 @@ public class OfflineRegion { if (!isDeleted) { isDeleted = true; fileSource.activate(); - deleteOfflineRegion(true /*pack*/, new OfflineRegionDeleteCallback() { - @Override - public void onDelete() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - callback.onDelete(); - OfflineRegion.this.finalize(); - } - }); - } - - @Override - public void onError(final String error) { - handler.post(new Runnable() { - @Override - public void run() { - isDeleted = false; - fileSource.deactivate(); - callback.onError(error); - } - }); - } - }); - } - } - - /** - * Same as {@link OfflineRegion#delete} but skipping database file packing for performance reasons. - *

    - * Database file packing can be done later with {@link OfflineManager#packDatabase}. - * This method is a useful optimization e.g. when several regions should be deleted in a row. - *

    - *

    - * When the operation is complete or encounters an error, the given callback will be - * executed on the main thread. - *

    - *

    - * After you call this method, you may not call any additional methods on this object. - *

    - * - * @param callback the callback to be invoked - */ - public void deleteAndSkipPackDatabase(@NonNull final OfflineRegionDeleteCallback callback) { - if (!isDeleted) { - isDeleted = true; - fileSource.activate(); - deleteOfflineRegion(false /*pack*/, new OfflineRegionDeleteCallback() { + deleteOfflineRegion(new OfflineRegionDeleteCallback() { @Override public void onDelete() { handler.post(new Runnable() { @@ -569,7 +523,7 @@ public class OfflineRegion { private native void getOfflineRegionStatus(OfflineRegionStatusCallback callback); @Keep - private native void deleteOfflineRegion(boolean pack, OfflineRegionDeleteCallback callback); + private native void deleteOfflineRegion(OfflineRegionDeleteCallback callback); @Keep private native void updateOfflineRegionMetadata(byte[] metadata, OfflineRegionUpdateMetadataCallback callback); diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index f10097640..e373d8a59 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit f10097640a8a62f9a139952844a75ac9b0b12543 +Subproject commit e373d8a5924e4f4cf3904ecacbf1d1cf86a5d60f From c51eab4001a84d773b7842305c6fa9c20ecffbcb Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 3 Dec 2019 21:00:37 +0100 Subject: [PATCH 042/185] [map] expose getter for the view used for rendering OpenGL on (#87) --- CHANGELOG.md | 1 + .../com/mapbox/mapboxsdk/maps/MapView.java | 18 +++++++ .../testapp/maps/RenderViewGetterTest.kt | 51 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index b24c41ef4..d7bc7564c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Features - Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) +- Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87) ### Performance improvements - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 4521d2ae6..558343e8c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -70,6 +70,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private NativeMap nativeMapView; @Nullable private MapboxMap mapboxMap; + private View renderView; + private AttributionClickListener attributionClickListener; private MapboxMapOptions mapboxMapOptions; private MapRenderer mapRenderer; @@ -296,6 +298,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { }; addView(textureView, 0); + renderView = textureView; } else { MapboxGLSurfaceView glSurfaceView = new MapboxGLSurfaceView(getContext()); glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop()); @@ -308,6 +311,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { }; addView(glSurfaceView, 0); + renderView = glSurfaceView; } boolean crossSourceCollisions = mapboxMapOptions.getCrossSourceCollisions(); @@ -465,6 +469,20 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { return destroyed; } + /** + * Returns the View used for rendering OpenGL. + *

    + * The type of the returned view is either a GLSurfaceView or a TextureView. + *

    + * + * @return the view used for rendering OpenGL + */ + @NonNull + @UiThread + public View getRenderView() { + return renderView; + } + @Override public boolean onTouchEvent(MotionEvent event) { if (!isGestureDetectorInitialized()) { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt new file mode 100644 index 000000000..afe6e7c09 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt @@ -0,0 +1,51 @@ +package com.mapbox.mapboxsdk.testapp.maps + +import android.opengl.GLSurfaceView +import android.support.test.annotation.UiThreadTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.view.TextureView +import android.view.ViewGroup +import com.mapbox.mapboxsdk.AppCenter +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.MapboxMapOptions +import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity +import java.util.concurrent.CountDownLatch +import junit.framework.Assert.assertNotNull +import junit.framework.Assert.assertTrue +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class RenderViewGetterTest : AppCenter() { + + @Rule + @JvmField + var rule = ActivityTestRule(FeatureOverviewActivity::class.java) + + private lateinit var rootView: ViewGroup + private lateinit var mapView: MapView + private val latch: CountDownLatch = CountDownLatch(1) + + @Test + @UiThreadTest + fun testGLSurfaceView() { + rootView = rule.activity.findViewById(android.R.id.content) + mapView = MapView(rule.activity) + assertNotNull(mapView.renderView) + assertTrue(mapView.renderView is GLSurfaceView) + } + + @Test + @UiThreadTest + fun testTextureView() { + rootView = rule.activity.findViewById(android.R.id.content) + mapView = MapView(rule.activity, + MapboxMapOptions.createFromAttributes(rule.activity, null) + .textureMode(true) + ) + assertNotNull(mapView.renderView) + assertTrue(mapView.renderView is TextureView) + } +} \ No newline at end of file From c85c99f8e8a58a273e0ba7463d74bb1c762fc61e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 6 Dec 2019 15:30:36 +0100 Subject: [PATCH 043/185] [projection] add bulk conversion of geographic coordinates to screen coordinates with reusable objects (#91) --- CHANGELOG.md | 1 + .../com/mapbox/mapboxsdk/maps/NativeMap.java | 4 + .../mapbox/mapboxsdk/maps/NativeMapView.java | 21 ++++ .../com/mapbox/mapboxsdk/maps/Projection.java | 25 ++++ .../maps/ScreenCoordinateConversion.kt | 112 ++++++++++++++++++ vendor/mapbox-gl-native | 2 +- 6 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bc7564c..dd7ddbd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Features - Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) - Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87) +- Bulk conversion of geographic coordinates to screen coordinate using reusable double arrays. [#91](https://github.com/mapbox/mapbox-gl-native-android/pull/91) ### Performance improvements - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index c805dcddb..2c6a49305 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -193,8 +193,12 @@ interface NativeMap { @NonNull PointF pixelForLatLng(@NonNull LatLng latLng); + void pixelsForLatLngs(@NonNull double[] input, @NonNull double[] output); + LatLng latLngForPixel(@NonNull PointF pixel); + void latLngsForPixels(@NonNull double[] input, @NonNull double[] output); + // // Utils API // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 75ca5edfc..2c69cb322 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -651,6 +651,13 @@ final class NativeMapView implements NativeMap { return pointF; } + @Override + public void pixelsForLatLngs(@NonNull double[] input, @NonNull double[] output) { + if (!checkState("pixelsForLatLngs")) { + nativePixelsForLatLngs(input, output, pixelRatio); + } + } + @Override public LatLng latLngForPixel(@NonNull PointF pixel) { if (checkState("latLngForPixel")) { @@ -659,6 +666,14 @@ final class NativeMapView implements NativeMap { return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio); } + @Override + public void latLngsForPixels(@NonNull double[] input, @NonNull double[] output) { + if (!checkState("latLngsForPixels")) { + nativeLatLngsForPixels(input, output, pixelRatio); + } + } + + @Override public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) { if (checkState("getTopOffsetPixelsForAnnotationSymbol")) { @@ -1275,10 +1290,16 @@ final class NativeMapView implements NativeMap { @Keep private native PointF nativePixelForLatLng(double lat, double lon); + @Keep + private native void nativePixelsForLatLngs(double[] input, double[] output, float pixelRatio); + @NonNull @Keep private native LatLng nativeLatLngForPixel(float x, float y); + @Keep + private native void nativeLatLngsForPixels(double[] input, double[] output, float pixelRatio); + @Keep private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index 76395f956..ae28576fa 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -95,6 +95,19 @@ public class Projection { return nativeMapView.latLngForPixel(point); } + + /** + * Returns the geographic locations that corresponds to screen locations. + * The screen locations are specified in screen pixels (not display pixels) relative to the + * top left of the map (not the top left of the whole screen). + * + * @param input an array of input values representing screen coordinates + * @param output an array of output values representing geographic locations + */ + public void fromScreenLocations(@NonNull double[] input, @NonNull double[] output) { + nativeMapView.latLngsForPixels(input, output); + } + /** * Gets a projection of the viewing frustum for converting between screen coordinates and * geo-latitude/longitude coordinates. @@ -263,6 +276,18 @@ public class Projection { return nativeMapView.pixelForLatLng(location); } + /** + * Returns a screen locations that corresponds to a geographical coordinates. + * The screen locations are in screen pixels (not display pixels) relative to the top left + * of the map (not of the whole screen). + * + * @param input an array of input values representing geographic locations + * @param output an array of output values representing screen coordinates + */ + public void toScreenLocations(@NonNull double[] input, @NonNull double[] output) { + nativeMapView.pixelsForLatLngs(input, output); + } + float getHeight() { return mapView.getHeight(); } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt new file mode 100644 index 000000000..3894bf46f --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt @@ -0,0 +1,112 @@ +package com.mapbox.mapboxsdk.testapp.maps + +import android.graphics.PointF +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.AppCenter +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.testapp.R +import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ScreenCoordinateConversion : AppCenter() { + + @Rule + @JvmField + var rule = ActivityTestRule(DeviceIndependentTestActivity::class.java) + + private lateinit var mapView: MapView + private lateinit var latch: CountDownLatch + + @Before + fun setup() { + latch = CountDownLatch(1) + } + + @Test + fun testToScreenCoordinates() { + rule.runOnUiThread { + mapView = rule.activity.findViewById(R.id.mapView) + val expected = doubleArrayOf(261.6888889445351, 253.15541110551123, 267.37777788907033, 247.4627648056528) + val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapView.getMapAsync { + val projection = it.projection + projection.toScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual) + // check all values + assertTrue(expected.contentEquals(actual)) + // check first coordinate value + val pointFirst = PointF(expected[0].toFloat(), expected[1].toFloat()) + val convertedFirst = projection.toScreenLocation(LatLng(1.0, 2.0)) + assertEquals( + pointFirst.x, convertedFirst.x, DELTA_FLOAT + ) + assertEquals( + pointFirst.y, convertedFirst.y, DELTA_FLOAT + ) + + // check second latlng value + val pointSecond = PointF(expected[2].toFloat(), expected[3].toFloat()) + val convertedSecond = projection.toScreenLocation(LatLng(3.0, 4.0)) + assertEquals( + pointSecond.x, convertedSecond.x, DELTA_FLOAT + ) + assertEquals( + pointSecond.y, convertedSecond.y, DELTA_FLOAT + ) + latch.countDown() + } + } + latch.await(10, TimeUnit.SECONDS) + } + + @Test + fun testFromScreenCoordinates() { + rule.runOnUiThread { + mapView = rule.activity.findViewById(R.id.mapView) + val expected = doubleArrayOf(66.2314571265913, -89.64843662311537, 65.94647142295494, -88.94531162999371) + val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapView.getMapAsync { + val projection = it.projection + projection.fromScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual) + // check all values at once + assertTrue(expected.contentEquals(actual)) + + // check first latlng value + val latLngFirst = LatLng(expected[0], expected[1]) + val convertedFirst = projection.fromScreenLocation(PointF(1.0f, 2.0f)) + assertEquals( + latLngFirst.latitude, convertedFirst.latitude, DELTA_DOUBLE + ) + assertEquals( + latLngFirst.longitude, convertedFirst.longitude, DELTA_DOUBLE + ) + + // check second latlng value + val latLngSecond = LatLng(expected[2], expected[3]) + val convertedSecond = projection.fromScreenLocation(PointF(3.0f, 4.0f)) + assertEquals( + latLngSecond.latitude, convertedSecond.latitude, DELTA_DOUBLE + ) + assertEquals( + latLngSecond.longitude, convertedSecond.longitude, DELTA_DOUBLE + ) + latch.countDown() + } + } + latch.await(10, TimeUnit.SECONDS) + } + + companion object { + const val DELTA_DOUBLE = 0.000001 + const val DELTA_FLOAT = 0.000001f + } +} \ No newline at end of file diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index e373d8a59..1ac3e9e9c 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit e373d8a5924e4f4cf3904ecacbf1d1cf86a5d60f +Subproject commit 1ac3e9e9c2a8bfc731e3bba978a28562c3f083e5 From 7b903283a45d0d1034fd4c7c85a746153de73521 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 6 Dec 2019 16:32:54 +0200 Subject: [PATCH 044/185] Update changelog for alpha.3 for release-tequila. (#89) --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd7ddbd3f..4390636d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master - +## 8.6.0-beta.1 - December 6, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.2...android-v8.6.0-beta.1) since [Mapbox Maps SDK for Android v8.6.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.2): ### Features - Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) - Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87) @@ -13,6 +13,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) ### Bug fixes +- Fixed a runtime crash of Proguard optimized builds on < API 21 devices by including the missing SoLoader flag. [#71](https://github.com/mapbox/mapbox-gl-native-android/pull/71) - Fixed a bug where location camera mode transition callback would not get notified if the requested mode was already set. [#80](https://github.com/mapbox/mapbox-gl-native-android/pull/80) - Fixed a bug where location tilt/zoom while tracking callback would not get notified if the request was ignored. [#83](https://github.com/mapbox/mapbox-gl-native-android/pull/83) - Use -Oz to reduce binary size [#15984](https://github.com/mapbox/mapbox-gl-native/pull/15984) From e274d6e28e36c7c8dfe6d4d8d30db7728ac50498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 16 Dec 2019 19:01:46 +0100 Subject: [PATCH 045/185] keep the whole LocalGlyphRasterizer class to prevent constructor minification --- CHANGELOG.md | 6 +++++- .../com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4390636d3..826785071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## master +### Bug fixes +- Fixed a crash caused by an unintentional minification of the `LocalGlyphRasterizer`. [#102](https://github.com/mapbox/mapbox-gl-native-android/pull/102) + ## 8.6.0-beta.1 - December 6, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.2...android-v8.6.0-beta.1) since [Mapbox Maps SDK for Android v8.6.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.2): ### Features @@ -22,7 +26,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## 8.6.0-alpha.2 - November 22, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): -### Bugs +### Bug fixes - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) ## 8.5.1 - November 20, 2019 diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java index 40e116fbc..32c5e40a4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java @@ -14,6 +14,7 @@ import android.support.annotation.WorkerThread; * LocalGlyphRasterizer is the Android-specific platform implementation used * by the portable local_glyph_rasterizer.hpp */ +@Keep public class LocalGlyphRasterizer { private final Bitmap bitmap; @NonNull @@ -49,7 +50,6 @@ public class LocalGlyphRasterizer { * @return Return a {@link Bitmap} to be displayed in the requested tile. */ @WorkerThread - @Keep protected Bitmap drawGlyphBitmap(String fontFamily, boolean bold, char glyphID) { paint.setTypeface(Typeface.create(fontFamily, bold ? Typeface.BOLD : Typeface.NORMAL)); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); From c4782e7a2db9be6e4528a6bb45bc1e3967e5d78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 16 Dec 2019 19:18:43 +0100 Subject: [PATCH 046/185] deprecate MapboxMap#cycleDebugActive --- CHANGELOG.md | 1 + .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 6 ++++-- .../java/com/mapbox/mapboxsdk/maps/NativeMap.java | 2 -- .../java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 11 ----------- .../testapp/activity/maplayout/DebugModeActivity.java | 2 +- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 826785071..1e5de0b01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master ### Bug fixes - Fixed a crash caused by an unintentional minification of the `LocalGlyphRasterizer`. [#102](https://github.com/mapbox/mapbox-gl-native-android/pull/102) +- Deprecated `MapboxMap#cycleDebugOptions` and fixed an `UnsatisfiedLinkError` when accessed. [#104](https://github.com/mapbox/mapbox-gl-native-android/pull/104) ## 8.6.0-beta.1 - December 6, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.2...android-v8.6.0-beta.1) since [Mapbox Maps SDK for Android v8.6.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.2): diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 8f4cb9438..c6b923865 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -775,10 +775,12 @@ public final class MapboxMap { * any map debug options enabled or disabled. * * @see #isDebugActive() + * @deprecated use {@link #setDebugActive(boolean)} */ + @Deprecated public void cycleDebugOptions() { - nativeMapView.cycleDebugOptions(); - this.debugActive = nativeMapView.getDebug(); + this.debugActive = !nativeMapView.getDebug(); + nativeMapView.setDebug(debugActive); } // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 2c6a49305..4f7db45ff 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -209,8 +209,6 @@ interface NativeMap { boolean getDebug(); - void cycleDebugOptions(); - void setReachability(boolean status); void setApiBaseUrl(String baseUrl); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 2c69cb322..5917a8b42 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -583,14 +583,6 @@ final class NativeMapView implements NativeMap { nativeSetDebug(debug); } - @Override - public void cycleDebugOptions() { - if (checkState("cycleDebugOptions")) { - return; - } - nativeCycleDebugOptions(); - } - @Override public boolean getDebug() { if (checkState("getDebug")) { @@ -1263,9 +1255,6 @@ final class NativeMapView implements NativeMap { @Keep private native void nativeSetDebug(boolean debug); - @Keep - private native void nativeCycleDebugOptions(); - @Keep private native boolean nativeGetDebug(); diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java index 097ef316f..85b31b85f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java @@ -164,8 +164,8 @@ public class DebugModeActivity extends AppCompatActivity implements OnMapReadyCa FloatingActionButton fabDebug = findViewById(R.id.fabDebug); fabDebug.setOnClickListener(view -> { if (mapboxMap != null) { + mapboxMap.setDebugActive(!mapboxMap.isDebugActive()); Timber.d("Debug FAB: isDebug Active? %s", mapboxMap.isDebugActive()); - mapboxMap.cycleDebugOptions(); } }); } From 39d688ab941ccc9c0d51954823451ca52bd825af Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Thu, 19 Dec 2019 00:32:41 -0800 Subject: [PATCH 047/185] cp 8.5.2 changelog (#110) --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e5de0b01..b57a16ac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Bug fixes - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) +## 8.5.2 - December 10, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.1...android-v8.5.2) since [Mapbox Maps SDK for Android v8.5.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.1): + +### Features +- Enabling decoupling vacuum operation from other operations run on the offline database file (delete offline region, clear ambient cache) [#99](https://github.com/mapbox/mapbox-gl-native-android/pull/99) + ## 8.5.1 - November 20, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.5.0...android-v8.5.1) since [Mapbox Maps SDK for Android v8.5.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.5.0): ### Bugs From d8fc70eacdaef8e9ccfcea605028adace9799455 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 20 Dec 2019 09:40:33 +0100 Subject: [PATCH 048/185] [buck] use buck to build library (#112) --- .circleci/config.yml | 2 +- core-files.json | 195 ++++++++++++++++++++ filesource-files.json | 27 +++ misc/buck/.buckconfig | 15 ++ misc/buck/mapbox-gl-native/Android.mk | 4 + misc/buck/mapbox-gl-native/Application.mk | 2 + misc/buck/mapbox-gl-native/BUCK | 140 ++++++++++++++ misc/buck/mapbox-gl-native/include | 1 + misc/buck/mapbox-gl-native/mapbox-gl-native | 1 + misc/buck/mapbox-gl-native/platform | 1 + misc/buck/mapbox-gl-native/sdk | 1 + misc/buck/mapbox-gl-native/src | 1 + misc/buck/mapbox-gl-native/vendor | 1 + misc/buck/mapbox-gl-native/vendor-android | 1 + version-script | 4 + 15 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 core-files.json create mode 100644 filesource-files.json create mode 100644 misc/buck/.buckconfig create mode 100644 misc/buck/mapbox-gl-native/Android.mk create mode 100644 misc/buck/mapbox-gl-native/Application.mk create mode 100644 misc/buck/mapbox-gl-native/BUCK create mode 120000 misc/buck/mapbox-gl-native/include create mode 120000 misc/buck/mapbox-gl-native/mapbox-gl-native create mode 120000 misc/buck/mapbox-gl-native/platform create mode 120000 misc/buck/mapbox-gl-native/sdk create mode 120000 misc/buck/mapbox-gl-native/src create mode 120000 misc/buck/mapbox-gl-native/vendor create mode 120000 misc/buck/mapbox-gl-native/vendor-android create mode 100644 version-script diff --git a/.circleci/config.yml b/.circleci/config.yml index 731706010..068e1dba1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -377,6 +377,6 @@ jobs: - run: name: Build Android library command: | - cd vendor/mapbox-gl-native/misc/buck + cd misc/buck buck build mapbox-gl-native:android-core # ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/core-files.json b/core-files.json new file mode 100644 index 000000000..70b748234 --- /dev/null +++ b/core-files.json @@ -0,0 +1,195 @@ +{ + "//": "This file can be edited manually and is the canonical source.", + "sources": [ + "vendor-android/mapbox-gl-native/platform/android/src/main.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_backend.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_frontend.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/annotation/marker.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/annotation/polygon.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/annotation/polyline.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/async_task.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/attach_env.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/bitmap.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/bitmap_factory.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/conversion/collection.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/conversion/color.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/conversion/constant.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature_collection.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry_collection.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/line_string.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_line_string.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_point.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_polygon.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/point.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geojson/polygon.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_bounds.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_quad.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/geometry/projected_meters.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/graphics/pointf.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/graphics/rectf.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/gson/json_array.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/gson/json_element.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/gson/json_object.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/gson/json_primitive.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/i18n/collator.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/i18n/number_format.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/image.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/java/util.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/java_types.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/jni.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/jni_native.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/logger.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/logging_android.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/mapbox.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/map/camera_position.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/map/image.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/map_renderer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/map_renderer_runnable.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/native_map_view.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/run_loop.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshot.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshotter.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/string_util.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/filter.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/position.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/transition_options.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/url_or_tileset.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/formatted.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/formatted_section.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/background_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/circle_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/custom_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_extrusion_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/heatmap_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/hillshade_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer_manager.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/line_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/raster_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/layers/symbol_layer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/light.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/position.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/custom_geometry_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/geojson_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/image_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_dem_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/unknown_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/sources/vector_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/transition_options.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/style/value.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/text/local_glyph_rasterizer.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/gl_functions.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/thread.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/timer.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gfx/headless_backend.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gfx/headless_frontend.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gl/headless_backend.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/map/map_snapshotter.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/text/bidi.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/compression.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/monotonic_timer.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/png_writer.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/thread_local.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/utf.cpp", + "vendor-android/mapbox-gl-native/platform/linux/src/headless_backend_egl.cpp" + ], + "public_headers": { + "jni/string_conversion.hpp": "vendor-android/mapbox-gl-native/platform/default/include/jni/string_conversion.hpp", + "mbgl/gfx/headless_backend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gfx/headless_backend.hpp", + "mbgl/gfx/headless_frontend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gfx/headless_frontend.hpp", + "mbgl/gl/headless_backend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gl/headless_backend.hpp", + "mbgl/map/map_snapshotter.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/map/map_snapshotter.hpp" + }, + "private_headers": { + "android_renderer_backend.hpp": "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_backend.hpp", + "android_renderer_frontend.hpp": "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_frontend.hpp", + "annotation/marker.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/marker.hpp", + "annotation/multi_point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/multi_point.hpp", + "annotation/polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/polygon.hpp", + "annotation/polyline.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/polyline.hpp", + "attach_env.hpp": "vendor-android/mapbox-gl-native/platform/android/src/attach_env.hpp", + "bitmap.hpp": "vendor-android/mapbox-gl-native/platform/android/src/bitmap.hpp", + "bitmap_factory.hpp": "vendor-android/mapbox-gl-native/platform/android/src/bitmap_factory.hpp", + "conversion/collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/collection.hpp", + "conversion/color.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/color.hpp", + "conversion/constant.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/constant.hpp", + "conversion/conversion.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/conversion.hpp", + "geojson/feature.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature.hpp", + "geojson/feature_collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature_collection.hpp", + "geojson/geometry.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry.hpp", + "geojson/geometry_collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry_collection.hpp", + "geojson/line_string.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/line_string.hpp", + "geojson/multi_line_string.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_line_string.hpp", + "geojson/multi_point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_point.hpp", + "geojson/multi_polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_polygon.hpp", + "geojson/point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/point.hpp", + "geojson/polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/polygon.hpp", + "geojson/util.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/util.hpp", + "geometry/lat_lng.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng.hpp", + "geometry/lat_lng_bounds.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_bounds.hpp", + "geometry/lat_lng_quad.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_quad.hpp", + "geometry/projected_meters.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/projected_meters.hpp", + "graphics/pointf.hpp": "vendor-android/mapbox-gl-native/platform/android/src/graphics/pointf.hpp", + "graphics/rectf.hpp": "vendor-android/mapbox-gl-native/platform/android/src/graphics/rectf.hpp", + "gson/json_array.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_array.hpp", + "gson/json_element.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_element.hpp", + "gson/json_object.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_object.hpp", + "gson/json_primitive.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_primitive.hpp", + "java/util.hpp": "vendor-android/mapbox-gl-native/platform/android/src/java/util.hpp", + "java_types.hpp": "vendor-android/mapbox-gl-native/platform/android/src/java_types.hpp", + "jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/jni.hpp", + "jni_native.hpp": "vendor-android/mapbox-gl-native/platform/android/src/jni_native.hpp", + "i18n/collator_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/i18n/collator_jni.hpp", + "i18n/number_format_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/i18n/number_format_jni.hpp", + "logger.hpp": "vendor-android/mapbox-gl-native/platform/android/src/logger.hpp", + "mapbox.hpp": "vendor-android/mapbox-gl-native/platform/android/src/mapbox.hpp", + "map/camera_position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map/camera_position.hpp", + "map/image.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map/image.hpp", + "map_renderer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map_renderer.hpp", + "map_renderer_runnable.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map_renderer_runnable.hpp", + "native_map_view.hpp": "vendor-android/mapbox-gl-native/platform/android/src/native_map_view.hpp", + "run_loop_impl.hpp": "vendor-android/mapbox-gl-native/platform/android/src/run_loop_impl.hpp", + "snapshotter/map_snapshot.hpp": "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshot.hpp", + "snapshotter/map_snapshotter.hpp": "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshotter.hpp", + "style/android_conversion.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/android_conversion.hpp", + "style/conversion/filter.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/filter.hpp", + "style/conversion/position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/position.hpp", + "style/conversion/property_expression.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/property_expression.hpp", + "style/conversion/property_value.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/property_value.hpp", + "style/conversion/transition_options.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/transition_options.hpp", + "style/conversion/url_or_tileset.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/url_or_tileset.hpp", + "style/formatted.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/formatted.hpp", + "style/formatted_section.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/formatted_section.hpp", + "style/layers/background_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/background_layer.hpp", + "style/layers/circle_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/circle_layer.hpp", + "style/layers/custom_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/custom_layer.hpp", + "style/layers/fill_extrusion_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_extrusion_layer.hpp", + "style/layers/fill_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_layer.hpp", + "style/layers/heatmap_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/heatmap_layer.hpp", + "style/layers/hillshade_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/hillshade_layer.hpp", + "style/layers/layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer.hpp", + "style/layers/layer_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer_manager.hpp", + "style/layers/line_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/line_layer.hpp", + "style/layers/raster_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/raster_layer.hpp", + "style/layers/symbol_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/symbol_layer.hpp", + "style/light.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/light.hpp", + "style/position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/position.hpp", + "style/sources/custom_geometry_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/custom_geometry_source.hpp", + "style/sources/geojson_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/geojson_source.hpp", + "style/sources/image_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/image_source.hpp", + "style/sources/raster_dem_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_dem_source.hpp", + "style/sources/raster_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_source.hpp", + "style/sources/source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/source.hpp", + "style/sources/unknown_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/unknown_source.hpp", + "style/sources/vector_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/vector_source.hpp", + "style/transition_options.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/transition_options.hpp", + "style/value.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/value.hpp", + "text/local_glyph_rasterizer_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/text/local_glyph_rasterizer_jni.hpp" + } +} \ No newline at end of file diff --git a/filesource-files.json b/filesource-files.json new file mode 100644 index 000000000..7be8bc8a0 --- /dev/null +++ b/filesource-files.json @@ -0,0 +1,27 @@ +{ + "//": "This file can be edited manually and is the canonical source.", + "sources": [ + "vendor-android/mapbox-gl-native/platform/android/src/asset_manager_file_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/connectivity_listener.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/file_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/http_file_source.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_manager.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_definition.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_error.cpp", + "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_status.cpp", + "vendor-android/mapbox-gl-native/platform/default/src/mbgl/storage/sqlite3.cpp" + ], + "public_headers": {}, + "private_headers": { + "asset_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/asset_manager.hpp", + "asset_manager_file_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/asset_manager_file_source.hpp", + "connectivity_listener.hpp": "vendor-android/mapbox-gl-native/platform/android/src/connectivity_listener.hpp", + "file_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/file_source.hpp", + "offline/offline_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_manager.hpp", + "offline/offline_region.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region.hpp", + "offline/offline_region_definition.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_definition.hpp", + "offline/offline_region_error.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_error.hpp", + "offline/offline_region_status.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_status.hpp" + } +} \ No newline at end of file diff --git a/misc/buck/.buckconfig b/misc/buck/.buckconfig new file mode 100644 index 000000000..f8d656612 --- /dev/null +++ b/misc/buck/.buckconfig @@ -0,0 +1,15 @@ +[ndk] +cpu_abis = armv7 +compiler = clang +app_platform = android-14 + +[project] +ignore = .git +allow_symlinks = allow + +[cxx] +default_platform = iphonesimulator-x86_64 + +[apple] +iphonesimulator_target_sdk_version = 9.0 +iphoneos_target_sdk_version = 9.0 \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/Android.mk b/misc/buck/mapbox-gl-native/Android.mk new file mode 100644 index 000000000..ba1e2dd70 --- /dev/null +++ b/misc/buck/mapbox-gl-native/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := android-core +include $(BUILD_SHARED_LIBRARY) diff --git a/misc/buck/mapbox-gl-native/Application.mk b/misc/buck/mapbox-gl-native/Application.mk new file mode 100644 index 000000000..a11b28deb --- /dev/null +++ b/misc/buck/mapbox-gl-native/Application.mk @@ -0,0 +1,2 @@ +APP_ABI := armeabi-v7a +APP_PLATFORM := android-14 diff --git a/misc/buck/mapbox-gl-native/BUCK b/misc/buck/mapbox-gl-native/BUCK new file mode 100644 index 000000000..30695821e --- /dev/null +++ b/misc/buck/mapbox-gl-native/BUCK @@ -0,0 +1,140 @@ +# BUILD FILE SYNTAX: SKYLARK + +import json + +mbgl_base_path = get_base_path() or '.' +android_base_path = '../../' + +def mbgl_load_file_lists(*argv): + merged = dict(sources = [], public_headers = {}, private_headers = {}) + for arg in argv: + filename = mbgl_base_path + '/' + arg + '-files.json' + add_build_file_dep('//' + filename) + files = json.load(open(filename)) + merged['public_headers'].update(files['public_headers']) + merged['private_headers'].update(files['private_headers']) + merged['sources'] += files['sources'] + return merged + +def android_load_file_lists(*argv): + merged = dict(sources = [], public_headers = {}, private_headers = {}) + for arg in argv: + filename = '../../' + arg + '-files.json' + add_build_file_dep('//' + filename) + files = json.load(open(filename)) + merged['public_headers'].update(files['public_headers']) + merged['private_headers'].update(files['private_headers']) + merged['sources'] += files['sources'] + return merged + +mbgl = dict( + core = mbgl_load_file_lists('src/core', 'platform/default/filesource'), + android = android_load_file_lists('core', 'filesource'), + deps = [], +) + +def mbgl_vendor_library(name): + files = mbgl_load_file_lists('vendor/' + name) + cxx_library( + name = "vendor-" + name, + header_namespace = "", + srcs = files['sources'], + headers = files['private_headers'], + exported_headers = files['public_headers'], + link_style = 'static', + compiler_flags = [ + "-Wno-tautological-unsigned-enum-zero-compare", + ], + ) + mbgl['deps'].append(':vendor-' + name) + +mbgl_vendor_library("icu") +mbgl_vendor_library("boost") +mbgl_vendor_library("cheap-ruler-cpp") +mbgl_vendor_library("earcut.hpp") +mbgl_vendor_library("eternal") +mbgl_vendor_library("geojson-vt-cpp") +mbgl_vendor_library("mapbox-base") +mbgl_vendor_library("sqlite") +mbgl_vendor_library("polylabel") +mbgl_vendor_library("protozero") +mbgl_vendor_library("shelf-pack-cpp") +mbgl_vendor_library("unique_resource") +mbgl_vendor_library("vector-tile") +mbgl_vendor_library("wagyu") + +cxx_library( + name = "core", + + srcs = mbgl['core']['sources'], + platform_srcs = [ + ("android", mbgl['android']['sources']), + ], + + header_namespace = "", + headers = mbgl['core']['private_headers'], + exported_headers = mbgl['core']['public_headers'], + platform_headers = [ + ("android", mbgl['android']['private_headers']) + ], + exported_platform_headers = [ + ("android", mbgl['android']['public_headers']), + ], + + compiler_flags = [ + "-std=c++14", + "-g", + "-Wall", + "-Wextra", + "-Werror", + "-Wno-unused-variable", + "-Wno-unused-parameter", + "-Wno-c++11-narrowing", + "-Wno-tautological-constant-compare", + "-fexceptions", + "-ftemplate-depth=1024", + "-frtti", + ], + + preprocessor_flags = [ + "-DMBGL_USE_GLES2=1", + "-DMBGL_VERSION_REV=\"standalone\"", + "-DRAPIDJSON_HAS_STDSTRING=1", + ], + exported_platform_linker_flags = [ + ("android", [ + "-lz", + "-lEGL", + "-lGLESv2", + "-landroid", + "-ljnigraphics", + "-llog", + "-fvisibility=hidden", + "-Wl,--icf=safe", + "-Wl,--version-script=" + android_base_path + "version-script" + ]), + ], + + visibility = ["PUBLIC"], + deps = mbgl['deps'], + soname = "libmapbox-gl.$(ext)", +) + +ndk_library( + name = "android-core", + deps = [ ":core" ], + flags = [ + "NDK_APPLICATION_MK=$(env PWD)/" + mbgl_base_path + "/Application.mk", + ], +) + +android_manifest( + name = 'android-manifest', + skeleton = 'sdk/src/main/AndroidManifest.xml', +) + +android_library( + name = "android", + deps = [ ":android-core" ], + manifest = ":android-manifest", +) \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/include b/misc/buck/mapbox-gl-native/include new file mode 120000 index 000000000..aabe3d4b8 --- /dev/null +++ b/misc/buck/mapbox-gl-native/include @@ -0,0 +1 @@ +../../../vendor/mapbox-gl-native/include \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/mapbox-gl-native b/misc/buck/mapbox-gl-native/mapbox-gl-native new file mode 120000 index 000000000..e0ea80599 --- /dev/null +++ b/misc/buck/mapbox-gl-native/mapbox-gl-native @@ -0,0 +1 @@ +../../../vendor/mapbox-gl-native \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/platform b/misc/buck/mapbox-gl-native/platform new file mode 120000 index 000000000..d05709529 --- /dev/null +++ b/misc/buck/mapbox-gl-native/platform @@ -0,0 +1 @@ +../../../vendor/mapbox-gl-native/platform \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/sdk b/misc/buck/mapbox-gl-native/sdk new file mode 120000 index 000000000..468e979db --- /dev/null +++ b/misc/buck/mapbox-gl-native/sdk @@ -0,0 +1 @@ +../../../MapboxGLAndroidSDK \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/src b/misc/buck/mapbox-gl-native/src new file mode 120000 index 000000000..86b9c406a --- /dev/null +++ b/misc/buck/mapbox-gl-native/src @@ -0,0 +1 @@ +../../../vendor/mapbox-gl-native/src \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/vendor b/misc/buck/mapbox-gl-native/vendor new file mode 120000 index 000000000..8272665fb --- /dev/null +++ b/misc/buck/mapbox-gl-native/vendor @@ -0,0 +1 @@ +../../../vendor/mapbox-gl-native/vendor \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/vendor-android b/misc/buck/mapbox-gl-native/vendor-android new file mode 120000 index 000000000..c73e2c9ac --- /dev/null +++ b/misc/buck/mapbox-gl-native/vendor-android @@ -0,0 +1 @@ +../../../vendor \ No newline at end of file diff --git a/version-script b/version-script new file mode 100644 index 000000000..7c1e3d54a --- /dev/null +++ b/version-script @@ -0,0 +1,4 @@ +{ + global: JNI_OnLoad; + local: *; +}; \ No newline at end of file From 2da60d28fd1d3a374a94e438877e1b87aa0952fb Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 7 Jan 2020 13:35:50 +0100 Subject: [PATCH 049/185] Use hasInstance on public static getters of Mapbox.java (#128) --- .../src/main/java/com/mapbox/mapboxsdk/Mapbox.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 35f7a5975..bcc793b04 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -115,7 +115,7 @@ public final class Mapbox { * @return the SKU token */ public static String getSkuToken() { - if (INSTANCE.accounts == null) { + if (!hasInstance() || INSTANCE.accounts == null) { throw new MapboxConfigurationException( "A valid access token parameter is required when using a Mapbox service." + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." @@ -179,7 +179,7 @@ public final class Mapbox { */ @Nullable public static TelemetryDefinition getTelemetry() { - return INSTANCE.telemetry; + return hasInstance() ? INSTANCE.telemetry : null; } /** From aa50f6eae24d402125d65cedf387e1c3ac608a13 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 8 Jan 2020 11:06:38 +0100 Subject: [PATCH 050/185] Update major version number to 9 (#132) --- MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/gradle.properties b/MapboxGLAndroidSDK/gradle.properties index e19588917..f93b35ec0 100644 --- a/MapboxGLAndroidSDK/gradle.properties +++ b/MapboxGLAndroidSDK/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=8.6.0-SNAPSHOT +VERSION_NAME=9.0.0-SNAPSHOT # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 From 013076339111ae36862d474895588adec3795d24 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 8 Jan 2020 13:46:13 +0100 Subject: [PATCH 051/185] Update codebase to androidX (#129) * update codebase to androidX --- .../com/mapbox/mapboxsdk/AccountsManager.java | 4 +- .../java/com/mapbox/mapboxsdk/Mapbox.java | 8 ++-- .../com/mapbox/mapboxsdk/ModuleProvider.java | 4 +- .../mapbox/mapboxsdk/ModuleProviderImpl.java | 4 +- .../mapboxsdk/annotations/Annotation.java | 4 +- .../mapboxsdk/annotations/ArrowDirection.java | 2 +- .../annotations/BasePointCollection.java | 4 +- .../mapbox/mapboxsdk/annotations/Bubble.java | 2 +- .../mapboxsdk/annotations/BubbleLayout.java | 2 +- .../annotations/BubblePopupHelper.java | 2 +- .../mapbox/mapboxsdk/annotations/Icon.java | 4 +- .../mapboxsdk/annotations/IconFactory.java | 4 +- .../mapboxsdk/annotations/InfoWindow.java | 6 +-- .../mapbox/mapboxsdk/annotations/Marker.java | 6 +-- .../mapboxsdk/annotations/MarkerOptions.java | 4 +- .../mapbox/mapboxsdk/annotations/Polygon.java | 4 +- .../mapboxsdk/annotations/PolygonOptions.java | 4 +- .../mapboxsdk/annotations/Polyline.java | 2 +- .../annotations/PolylineOptions.java | 4 +- .../mapboxsdk/attribution/Attribution.java | 2 +- .../attribution/AttributionLayout.java | 4 +- .../attribution/AttributionMeasure.java | 4 +- .../attribution/AttributionParser.java | 2 +- .../mapboxsdk/camera/CameraPosition.java | 10 ++--- .../mapbox/mapboxsdk/camera/CameraUpdate.java | 4 +- .../mapboxsdk/camera/CameraUpdateFactory.java | 6 +-- .../MapboxConfigurationException.java | 2 +- .../com/mapbox/mapboxsdk/geometry/LatLng.java | 8 ++-- .../mapboxsdk/geometry/LatLngBounds.java | 8 ++-- .../mapbox/mapboxsdk/geometry/LatLngQuad.java | 4 +- .../mapbox/mapboxsdk/geometry/LatLngSpan.java | 2 +- .../mapboxsdk/geometry/ProjectedMeters.java | 6 +-- .../mapboxsdk/geometry/VisibleRegion.java | 2 +- .../mapbox/mapboxsdk/http/HttpIdentifier.java | 2 +- .../mapbox/mapboxsdk/http/HttpRequestUrl.java | 2 +- .../mapboxsdk/http/LocalRequestTask.java | 4 +- .../mapboxsdk/http/NativeHttpRequest.java | 4 +- .../mapboxsdk/location/CompassEngine.java | 2 +- .../mapboxsdk/location/LatLngEvaluator.java | 2 +- .../location/LayerBitmapProvider.java | 6 +-- .../location/LayerFeatureProvider.java | 4 +- .../location/LayerSourceProvider.java | 2 +- .../location/LocationAnimatorCoordinator.java | 6 +-- .../location/LocationCameraController.java | 6 +-- .../mapboxsdk/location/LocationComponent.java | 10 ++--- .../LocationComponentActivationOptions.java | 4 +- .../LocationComponentCompassEngine.java | 4 +- .../location/LocationComponentOptions.java | 12 +++--- .../LocationComponentPositionManager.java | 4 +- .../location/LocationLayerController.java | 8 ++-- .../mapboxsdk/location/MapboxAnimator.java | 4 +- .../location/MapboxAnimatorProvider.java | 2 +- .../location/MapboxAnimatorSetProvider.java | 2 +- .../location/MapboxCameraAnimatorAdapter.java | 2 +- .../location/MapboxFloatAnimator.java | 2 +- .../location/MapboxLatLngAnimator.java | 2 +- .../mapboxsdk/location/StaleStateManager.java | 2 +- .../com/mapbox/mapboxsdk/location/Utils.java | 4 +- .../mapboxsdk/location/modes/CameraMode.java | 2 +- .../mapboxsdk/location/modes/RenderMode.java | 2 +- .../java/com/mapbox/mapboxsdk/log/Logger.java | 4 +- .../mapboxsdk/maps/AnnotationContainer.java | 4 +- .../mapboxsdk/maps/AnnotationManager.java | 6 +-- .../mapbox/mapboxsdk/maps/Annotations.java | 2 +- .../maps/AttributionDialogManager.java | 4 +- .../maps/CameraChangeDispatcher.java | 4 +- .../mapbox/mapboxsdk/maps/IconManager.java | 2 +- .../java/com/mapbox/mapboxsdk/maps/Image.java | 2 +- .../mapboxsdk/maps/InfoWindowManager.java | 2 +- .../mapbox/mapboxsdk/maps/MapFragment.java | 4 +- .../mapboxsdk/maps/MapGestureDetector.java | 4 +- .../mapbox/mapboxsdk/maps/MapKeyListener.java | 4 +- .../com/mapbox/mapboxsdk/maps/MapView.java | 10 ++--- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 12 +++--- .../mapboxsdk/maps/MapboxMapOptions.java | 12 +++--- .../mapboxsdk/maps/MarkerContainer.java | 4 +- .../com/mapbox/mapboxsdk/maps/Markers.java | 2 +- .../com/mapbox/mapboxsdk/maps/NativeMap.java | 6 +-- .../mapbox/mapboxsdk/maps/NativeMapView.java | 8 ++-- .../mapboxsdk/maps/OnMapReadyCallback.java | 2 +- .../mapboxsdk/maps/PolygonContainer.java | 4 +- .../com/mapbox/mapboxsdk/maps/Polygons.java | 2 +- .../mapboxsdk/maps/PolylineContainer.java | 4 +- .../com/mapbox/mapboxsdk/maps/Polylines.java | 2 +- .../com/mapbox/mapboxsdk/maps/Projection.java | 4 +- .../maps/ShapeAnnotationContainer.java | 4 +- .../java/com/mapbox/mapboxsdk/maps/Style.java | 8 ++-- .../mapboxsdk/maps/SupportMapFragment.java | 6 +-- .../com/mapbox/mapboxsdk/maps/Transform.java | 6 +-- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 16 +++---- .../mapboxsdk/maps/renderer/MapRenderer.java | 6 +-- .../maps/renderer/MapRendererRunnable.java | 2 +- .../maps/renderer/MapRendererScheduler.java | 2 +- .../maps/renderer/egl/EGLConfigChooser.java | 2 +- .../GLSurfaceViewMapRenderer.java | 2 +- .../glsurfaceview/MapboxGLSurfaceView.java | 2 +- .../textureview/TextureViewMapRenderer.java | 2 +- .../textureview/TextureViewRenderThread.java | 6 +-- .../mapboxsdk/maps/widgets/CompassView.java | 10 ++--- .../module/http/HttpRequestImpl.java | 6 +-- .../module/http/HttpRequestUtil.java | 4 +- .../module/telemetry/MapEventFactory.java | 4 +- .../telemetry/OfflineDownloadEndEvent.java | 2 +- .../telemetry/OfflineDownloadStartEvent.java | 2 +- .../module/telemetry/PhoneState.java | 2 +- .../module/telemetry/TelemetryImpl.java | 4 +- .../mapboxsdk/net/ConnectivityReceiver.java | 6 +-- .../net/NativeConnectivityListener.java | 2 +- .../OfflineGeometryRegionDefinition.java | 6 +-- .../mapboxsdk/offline/OfflineManager.java | 8 ++-- .../mapboxsdk/offline/OfflineRegion.java | 8 ++-- .../offline/OfflineRegionDefinition.java | 2 +- .../mapboxsdk/offline/OfflineRegionError.java | 6 +-- .../offline/OfflineRegionStatus.java | 2 +- .../OfflineTilePyramidRegionDefinition.java | 4 +- .../mapboxsdk/snapshotter/MapSnapshot.java | 4 +- .../mapboxsdk/snapshotter/MapSnapshotter.java | 10 ++--- .../mapbox/mapboxsdk/storage/FileSource.java | 8 ++-- .../mapbox/mapboxsdk/storage/Resource.java | 2 +- .../style/expressions/Expression.java | 8 ++-- .../style/layers/BackgroundLayer.java | 15 +++---- .../style/layers/CannotAddLayerException.java | 2 +- .../mapboxsdk/style/layers/CircleLayer.java | 12 +++--- .../mapboxsdk/style/layers/CustomLayer.java | 2 +- .../style/layers/FillExtrusionLayer.java | 12 +++--- .../mapboxsdk/style/layers/FillLayer.java | 12 +++--- .../mapboxsdk/style/layers/HeatmapLayer.java | 12 +++--- .../style/layers/HillshadeLayer.java | 15 +++---- .../mapbox/mapboxsdk/style/layers/Layer.java | 6 +-- .../style/layers/LayoutPropertyValue.java | 2 +- .../mapboxsdk/style/layers/LineLayer.java | 12 +++--- .../style/layers/PaintPropertyValue.java | 2 +- .../mapboxsdk/style/layers/Property.java | 2 +- .../style/layers/PropertyFactory.java | 2 +- .../mapboxsdk/style/layers/PropertyValue.java | 6 +-- .../mapboxsdk/style/layers/RasterLayer.java | 17 +++----- .../mapboxsdk/style/layers/SymbolLayer.java | 13 +++--- .../style/layers/TransitionOptions.java | 2 +- .../mapbox/mapboxsdk/style/light/Light.java | 8 ++-- .../mapboxsdk/style/light/Position.java | 6 +-- .../sources/CannotAddSourceException.java | 2 +- .../style/sources/CustomGeometrySource.java | 10 ++--- .../sources/CustomGeometrySourceOptions.java | 2 +- .../style/sources/GeoJsonOptions.java | 2 +- .../style/sources/GeoJsonSource.java | 8 ++-- .../style/sources/GeometryTileProvider.java | 2 +- .../mapboxsdk/style/sources/ImageSource.java | 10 ++--- .../style/sources/RasterDemSource.java | 8 ++-- .../mapboxsdk/style/sources/RasterSource.java | 6 +-- .../mapboxsdk/style/sources/Source.java | 4 +- .../mapboxsdk/style/sources/TileSet.java | 4 +- .../style/sources/UnknownSource.java | 4 +- .../mapboxsdk/style/sources/VectorSource.java | 10 ++--- .../mapboxsdk/style/types/Formatted.java | 4 +- .../style/types/FormattedSection.java | 8 ++-- .../mapboxsdk/text/LocalGlyphRasterizer.java | 6 +-- .../mapbox/mapboxsdk/utils/AnimatorUtils.java | 8 ++-- .../mapbox/mapboxsdk/utils/BitmapUtils.java | 10 ++--- .../mapbox/mapboxsdk/utils/ColorUtils.java | 6 +-- .../com/mapbox/mapboxsdk/utils/FileUtils.java | 2 +- .../com/mapbox/mapboxsdk/utils/FontUtils.java | 2 +- .../mapboxsdk/utils/MapFragmentUtils.java | 4 +- .../mapbox/mapboxsdk/utils/StringUtils.java | 4 +- .../mapbox/mapboxsdk/utils/ThreadUtils.java | 2 +- .../com/mapbox/mapboxsdk/MapboxInjector.java | 4 +- .../mapboxsdk/annotations/AnnotationTest.java | 2 +- ...ocationComponentActivationOptionsTest.java | 2 +- .../LocationComponentOptionsTest.java | 2 +- .../location/LocationLayerControllerTest.java | 2 +- .../mapboxsdk/maps/AnnotationManagerTest.java | 2 +- .../mapboxsdk/maps/MapTouchListenersTest.java | 2 +- .../mapbox/mapboxsdk/utils/MockParcel.java | 4 +- .../com/mapbox/mapboxsdk/lint/KeepDetector.kt | 2 +- .../src/androidTest/AndroidManifest.xml | 2 +- .../mapbox/mapboxsdk/InstrumentationRunner.kt | 2 +- .../camera/CameraUpdateFactoryTest.kt | 4 +- .../integration/BaseIntegrationTest.kt | 8 ++-- .../integration/FragmentBackStackTest.kt | 8 ++-- .../integration/GLSurfaceViewReopenTest.kt | 6 +-- .../integration/GLSurfaceViewReuseTest.kt | 6 +-- .../integration/OrientationChangeTest.kt | 6 +-- .../QueryRenderedFeaturesBoxCountTest.kt | 6 +-- .../integration/TextureViewReopenTest.kt | 6 +-- .../integration/TextureViewReuseTest.kt | 6 +-- .../integration/ViewPagerScrollTest.kt | 8 ++-- .../location/LocationComponentTest.kt | 14 +++--- .../location/LocationLayerControllerTest.kt | 20 ++++----- .../location/utils/LocationComponentAction.kt | 6 +-- .../utils/StyleChangeIdlingResource.kt | 2 +- .../mapbox/mapboxsdk/maps/BaseLayerTest.kt | 6 +-- .../mapboxsdk/maps/GesturesUiTestUtils.kt | 10 ++--- .../mapboxsdk/maps/MapGestureDetectorTest.kt | 4 +- .../mapbox/mapboxsdk/maps/MapboxMapTest.java | 10 ++--- .../com/mapbox/mapboxsdk/maps/MapboxTest.java | 4 +- .../mapboxsdk/maps/NativeMapViewTest.kt | 8 ++-- .../mapbox/mapboxsdk/maps/TransformTest.kt | 2 +- .../mapboxsdk/maps/VisibleRegionTest.kt | 2 +- .../mapboxsdk/offline/OfflineDownloadTest.kt | 4 +- .../snapshotter/MapSnapshotterTest.kt | 4 +- .../testapp/action/MapboxMapAction.java | 12 +++--- .../testapp/action/OrientationAction.java | 8 ++-- .../mapboxsdk/testapp/action/WaitAction.java | 10 ++--- .../mapboxsdk/testapp/activity/BaseTest.java | 8 ++-- .../testapp/activity/EspressoTest.java | 2 +- .../testapp/activity/activity.junit.ejs | 2 +- .../testapp/annotations/IconTest.java | 4 +- .../testapp/annotations/MarkerTest.java | 8 ++-- .../testapp/camera/CameraForTest.java | 4 +- .../testapp/fragment/MapDialogFragmentTest.kt | 14 +++--- .../geometry/GeoJsonConversionTest.java | 6 +-- .../testapp/maps/ImageMissingTest.kt | 4 +- .../testapp/maps/RemoveUnusedImagesTest.kt | 4 +- .../testapp/maps/RenderViewGetterTest.kt | 6 +-- .../maps/ScreenCoordinateConversion.kt | 4 +- .../mapboxsdk/testapp/maps/StyleLoadTest.kt | 4 +- .../testapp/maps/widgets/AttributionTest.java | 30 ++++++------- .../testapp/maps/widgets/CompassViewTest.java | 10 ++--- .../testapp/maps/widgets/LogoTest.java | 12 +++--- .../mapboxsdk/testapp/offline/CacheTest.kt | 4 +- .../testapp/offline/OfflineManagerTest.kt | 4 +- .../testapp/offline/OfflineUtilsTest.java | 2 +- .../mapboxsdk/testapp/render/RenderTest.java | 20 ++++----- .../testapp/storage/FileSourceMapTest.kt | 6 +-- .../storage/FileSourceStandaloneTest.kt | 6 +-- .../testapp/storage/FileSourceTestUtils.kt | 2 +- .../testapp/string/UppperLowerCaseTest.java | 2 +- .../testapp/style/BackgroundLayerTest.java | 6 +-- .../testapp/style/CircleLayerTest.java | 4 +- .../testapp/style/CustomGeometrySourceTest.kt | 4 +- .../testapp/style/ExpressionTest.java | 2 +- .../testapp/style/FillExtrusionLayerTest.java | 4 +- .../testapp/style/FillLayerTest.java | 4 +- .../testapp/style/GeoJsonSourceTests.java | 8 ++-- .../testapp/style/HeatmapLayerTest.java | 5 +-- .../testapp/style/HillshadeLayerTest.java | 6 +-- .../mapboxsdk/testapp/style/ImageTest.kt | 2 +- .../mapboxsdk/testapp/style/LightTest.java | 12 +++--- .../testapp/style/LineLayerTest.java | 4 +- .../testapp/style/RasterLayerTest.java | 7 +-- .../testapp/style/RuntimeStyleTests.java | 12 +++--- .../style/RuntimeStyleTimingTests.java | 2 +- .../testapp/style/SymbolLayerTest.java | 4 +- .../mapboxsdk/testapp/style/layer.junit.ejs | 2 +- .../mapboxsdk/testapp/style/light.junit.ejs | 2 +- .../utils/SnapshotterIdlingResource.java | 2 +- .../testapp/utils/TestingAsyncUtils.kt | 2 +- .../mapbox/mapboxsdk/utils/FontUtilsTest.java | 2 +- .../activity/FeatureOverviewActivity.java | 8 ++-- .../AnimatedSymbolLayerActivity.java | 2 +- .../annotation/BulkMarkerActivity.java | 4 +- .../DynamicMarkerChangeActivity.java | 8 ++-- .../activity/annotation/PolygonActivity.java | 4 +- .../activity/annotation/PolylineActivity.java | 2 +- .../annotation/PressForMarkerActivity.java | 4 +- .../camera/CameraAnimationTypeActivity.java | 4 +- .../camera/CameraAnimatorActivity.java | 12 +++--- .../camera/CameraPositionActivity.java | 14 +++--- .../camera/GestureDetectorActivity.java | 16 +++---- .../activity/camera/LatLngBoundsActivity.kt | 4 +- .../activity/camera/ManualZoomActivity.java | 2 +- .../activity/camera/MaxMinZoomActivity.java | 4 +- .../activity/camera/ScrollByActivity.java | 14 +++--- .../customlayer/CustomLayerActivity.java | 6 +-- .../DeviceIndependentTestActivity.java | 4 +- .../espresso/EspressoTestActivity.java | 2 +- .../activity/espresso/PixelTestActivity.kt | 2 +- ...QueryRenderedFeaturesBoxCountActivity.java | 2 +- ...yRenderedFeaturesBoxHighlightActivity.java | 2 +- ...enderedFeaturesBoxSymbolCountActivity.java | 2 +- ...eryRenderedFeaturesPropertiesActivity.java | 4 +- .../feature/QuerySourceFeaturesActivity.java | 6 +-- .../fragment/FragmentBackStackActivity.kt | 2 +- .../fragment/MapFragmentActivity.java | 4 +- .../activity/fragment/MultiMapActivity.java | 4 +- .../fragment/NestedViewPagerActivity.kt | 33 +++++++------- .../fragment/SupportMapFragmentActivity.java | 4 +- .../activity/fragment/ViewPagerActivity.kt | 12 +++--- .../imagegenerator/PrintActivity.java | 4 +- .../imagegenerator/SnapshotActivity.kt | 2 +- .../DynamicInfoWindowAdapterActivity.java | 6 +-- .../infowindow/InfoWindowActivity.java | 4 +- .../infowindow/InfoWindowAdapterActivity.java | 4 +- .../LocationComponentActivationActivity.java | 4 +- .../location/LocationFragmentActivity.kt | 8 ++-- .../location/LocationMapChangeActivity.java | 6 +-- .../location/LocationModesActivity.java | 6 +-- .../ManualLocationUpdatesActivity.java | 6 +-- .../maplayout/BottomSheetActivity.java | 16 +++---- .../activity/maplayout/DebugModeActivity.java | 12 +++--- .../activity/maplayout/DoubleMapActivity.java | 8 ++-- .../GLSurfaceRecyclerViewActivity.kt | 21 +++++---- .../LatLngBoundsForCameraActivity.java | 6 +-- .../maplayout/LocalGlyphActivity.java | 2 +- .../activity/maplayout/MapChangeActivity.java | 2 +- .../maplayout/MapInDialogActivity.java | 10 ++--- .../maplayout/MapPaddingActivity.java | 2 +- .../activity/maplayout/OverlayMapActivity.kt | 13 +++--- .../activity/maplayout/SimpleMapActivity.java | 2 +- .../maplayout/VisibilityChangeActivity.java | 2 +- .../ChangeResourcesCachePathActivity.kt | 2 +- .../offline/DeleteRegionActivity.java | 4 +- .../offline/DownloadRegionActivity.kt | 2 +- .../offline/MergeOfflineRegionsActivity.kt | 2 +- .../activity/offline/OfflineActivity.java | 2 +- .../offline/UpdateMetadataActivity.java | 4 +- .../activity/render/RenderTestActivity.java | 4 +- .../render/RenderTestSnapshotter.java | 2 +- .../snapshot/MapSnapshotterActivity.java | 2 +- .../MapSnapshotterLocalStyleActivity.java | 2 +- .../MapSnapshotterMarkerActivity.java | 6 +-- .../snapshot/MapSnapshotterReuseActivity.java | 2 +- .../storage/CacheManagementActivity.kt | 4 +- .../storage/UrlTransformActivity.java | 2 +- .../style/AnimatedImageSourceActivity.java | 4 +- .../style/BuildingFillExtrusionActivity.java | 2 +- .../activity/style/CircleLayerActivity.java | 8 ++-- .../style/CollectionUpdateOnStyleChange.kt | 4 +- .../activity/style/CustomSpriteActivity.java | 6 +-- .../style/DataDrivenStyleActivity.java | 2 +- .../activity/style/DraggableMarkerActivity.kt | 9 ++-- .../activity/style/FillExtrusionActivity.java | 2 +- .../style/FillExtrusionStyleTestActivity.java | 2 +- .../style/GeoJsonClusteringActivity.java | 4 +- .../activity/style/GradientLineActivity.java | 4 +- .../activity/style/GridSourceActivity.java | 4 +- .../activity/style/HeatmapLayerActivity.java | 2 +- .../style/HillshadeLayerActivity.java | 2 +- .../testapp/activity/style/NoStyleActivity.kt | 9 ++-- .../style/RealTimeGeoJsonActivity.java | 4 +- .../activity/style/RuntimeStyleActivity.java | 2 +- .../style/RuntimeStyleTimingTestActivity.java | 2 +- .../activity/style/StyleFileActivity.java | 6 +-- .../style/SymbolGeneratorActivity.java | 4 +- .../activity/style/SymbolLayerActivity.java | 4 +- .../ZoomFunctionSymbolLayerActivity.java | 4 +- .../PerformanceMeasurementActivity.java | 2 +- .../TextureViewAnimationActivity.java | 4 +- .../TextureViewResizeActivity.java | 8 ++-- ...tureViewTransparentBackgroundActivity.java | 2 +- .../turf/PhysicalUnitCircleActivity.kt | 7 +-- .../testapp/adapter/FeatureAdapter.java | 2 +- .../adapter/FeatureSectionAdapter.java | 8 ++-- .../model/customlayer/ExampleCustomLayer.java | 2 +- .../other/OfflineDownloadRegionDialog.java | 6 +-- .../model/other/OfflineListRegionsDialog.java | 6 +-- .../mapboxsdk/testapp/utils/IconUtils.java | 10 ++--- .../testapp/utils/ItemClickSupport.java | 2 +- .../mapboxsdk/testapp/utils/NavUtils.java | 2 +- .../mapboxsdk/testapp/utils/OfflineUtils.java | 2 +- .../testapp/utils/ResourceUtils.java | 2 +- .../utils/TileLoadingMeasurementUtils.java | 4 +- .../mapboxsdk/testapp/utils/TokenUtils.java | 2 +- .../testapp/utils/ViewToBitmapUtil.java | 2 +- .../view/LockableBottomSheetBehavior.java | 4 +- .../mapboxsdk/testapp/view/MapViewPager.java | 4 +- .../main/res/layout/activity_add_sprite.xml | 2 +- .../main/res/layout/activity_bottom_sheet.xml | 14 +++--- .../res/layout/activity_building_layer.xml | 4 +- .../res/layout/activity_camera_animator.xml | 6 +-- .../res/layout/activity_camera_position.xml | 8 ++-- .../main/res/layout/activity_circle_layer.xml | 4 +- ...vity_collection_update_on_style_change.xml | 6 +-- .../main/res/layout/activity_custom_layer.xml | 6 +-- .../main/res/layout/activity_debug_mode.xml | 20 ++++----- .../res/layout/activity_dynamic_marker.xml | 6 +-- .../res/layout/activity_feature_overview.xml | 2 +- .../layout/activity_geojson_clustering.xml | 6 +-- .../res/layout/activity_gesture_detector.xml | 2 +- .../main/res/layout/activity_latlngbounds.xml | 12 +++--- ...vity_location_layer_activation_builder.xml | 4 +- .../activity_location_layer_fragment.xml | 6 +-- .../activity_location_layer_map_change.xml | 6 +-- .../layout/activity_location_layer_mode.xml | 4 +- .../activity_location_manual_update.xml | 8 ++-- .../layout/activity_map_snapshotter_reuse.xml | 2 +- .../src/main/res/layout/activity_overlay.xml | 4 +- .../src/main/res/layout/activity_polyline.xml | 2 +- .../src/main/res/layout/activity_print.xml | 6 +-- .../layout/activity_query_source_features.xml | 6 +-- .../main/res/layout/activity_recyclerview.xml | 6 +-- .../res/layout/activity_region_download.xml | 10 ++--- .../res/layout/activity_restricted_bounds.xml | 4 +- .../main/res/layout/activity_scroll_by.xml | 10 ++--- .../main/res/layout/activity_style_file.xml | 4 +- .../layout/activity_textureview_animate.xml | 4 +- .../activity_textureview_debug_mode.xml | 20 ++++----- .../layout/activity_textureview_resize.xml | 6 +-- .../activity_textureview_transparent.xml | 4 +- .../main/res/layout/activity_viewpager.xml | 2 +- .../src/main/res/layout/item_viewpager.xml | 2 +- gradle.properties | 2 + gradle/dependencies.gradle | 43 ++++++++++--------- 392 files changed, 1040 insertions(+), 1071 deletions(-) create mode 100644 gradle.properties diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java index 5b8f10e01..968c33926 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java @@ -4,8 +4,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.text.format.DateUtils; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index bcc793b04..c8b6701bb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.AssetManager; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java index 9749290eb..63e325404 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProvider.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.http.HttpRequest; import com.mapbox.mapboxsdk.maps.TelemetryDefinition; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java index 2de111c97..68497811a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/ModuleProviderImpl.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.http.HttpRequest; import com.mapbox.mapboxsdk.maps.TelemetryDefinition; import com.mapbox.mapboxsdk.module.http.HttpRequestImpl; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java index 8ea226649..c71b9dcf0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.annotations; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java index 220544815..fcc9ed2de 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.annotations; -import android.support.annotation.IntDef; +import androidx.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java index b94721a80..6ba14ba4e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BasePointCollection.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.annotations; -import android.support.annotation.Keep; +import androidx.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java index 0768f9c2e..e048e1b22 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java @@ -8,7 +8,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; @Deprecated class Bubble extends Drawable { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java index 3ff3143b2..c10e0bbb4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java @@ -5,7 +5,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.RectF; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.widget.LinearLayout; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java index 055bfe536..f4297d432 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.annotations; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.ViewGroup; import android.widget.PopupWindow; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java index 7ace11350..eb3d6f5a5 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.annotations; import android.graphics.Bitmap; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.DisplayMetrics; import java.nio.ByteBuffer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java index 9f0fa62cd..8f8b45696 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java @@ -7,8 +7,8 @@ import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; import android.util.DisplayMetrics; import android.view.WindowManager; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index 5bd9aaef1..b5df3678d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.annotations; import android.content.res.Resources; import android.graphics.PointF; import android.os.Build; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index c26af9436..5bd14a855 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.annotations; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import com.mapbox.mapboxsdk.R; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java index 62c3d378e..494466471 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java @@ -4,8 +4,8 @@ import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java index 5f6cef8d4..f35713622 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.annotations; import android.graphics.Color; -import android.support.annotation.Keep; +import androidx.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java index 452420fcb..17ae49778 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java @@ -4,8 +4,8 @@ package com.mapbox.mapboxsdk.annotations; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java index 76ea15215..36a4d2e9d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.annotations; import android.graphics.Color; -import android.support.annotation.Keep; +import androidx.annotation.Keep; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java index 6a54f948b..ff05631c3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.annotations; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java index 035614a90..159282b7f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.attribution; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java index 25d5de7ea..242b67647 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionLayout.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.attribution; import android.graphics.Bitmap; import android.graphics.PointF; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class AttributionLayout { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java index b40a7be24..cfd1c1f91 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionMeasure.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.attribution; import android.graphics.Bitmap; import android.graphics.PointF; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.widget.TextView; import java.util.Arrays; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java index ff59dbdf9..6d26c104a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.attribution; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.text.Html; import android.text.SpannableStringBuilder; import android.text.Spanned; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java index 54e8fc595..1a44afcb4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -3,11 +3,11 @@ package com.mapbox.mapboxsdk.camera; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.FloatRange; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Size; +import androidx.annotation.FloatRange; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.constants.MapboxConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java index 39b937210..5296af02a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.camera; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java index b611456f4..9adacf2e6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.camera; import android.graphics.Point; import android.graphics.PointF; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java index 431de85f0..04a8ca044 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.exceptions; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * A MapboxConfigurationException is thrown by MapboxMap when the SDK hasn't been properly initialised. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index ce12489b4..ae1eacc5b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -3,10 +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 android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.FloatRange; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.constants.GeometryConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 263780f47..516a9220e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.geometry; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.FloatRange; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.FloatRange; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.constants.GeometryConstants; import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java index d17d0d6fe..4629d8dad 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.geometry; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; /** * A geographical area representing a non-aligned quadrilateral diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java index 941e6652f..bbc64fb81 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.geometry; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * A geographical span defined by its latitude and longitude span. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java index 745a7c6be..d4e6dc310 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.geometry; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * ProjectedMeters is a projection of longitude, latitude points in Mercator meters. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java index a8b4421ee..706bbcd65 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.geometry; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * Contains the four points defining the four-sided polygon that is visible in a map's camera. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java index 5f4f85ea7..1df2c550f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.http; import android.content.Context; import android.content.pm.PackageInfo; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java index 1faf8f5e5..2a85bdee8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.http; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java index 2d9fe43ad..f263fa9c0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.http; import android.content.res.AssetManager; import android.os.AsyncTask; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java index e59b07dc1..47ba2c9fa 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.http; -import android.support.annotation.Keep; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.Mapbox; import java.util.concurrent.locks.ReentrantLock; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java index bb7fd4972..603171505 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.location; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.location.modes.CameraMode; import com.mapbox.mapboxsdk.location.modes.RenderMode; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java index c631b1b75..050798062 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LatLngEvaluator.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location; import android.animation.TypeEvaluator; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; class LatLngEvaluator implements TypeEvaluator { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java index 14a1b49dc..70aabd867 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerBitmapProvider.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.location; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.utils.BitmapUtils; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java index faa83ea0e..69e08caed 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Point; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index cac513c2f..e3c6ebd91 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.location; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.geojson.Feature; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.Layer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 5aad038a2..248c7664b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.location.Location; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.util.SparseArray; import android.view.animation.LinearInterpolator; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index 47d4fe0ae..13b61dfec 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.location; 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.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.view.MotionEvent; import com.mapbox.android.gestures.AndroidGesturesManager; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index f8933d4c1..9df7a1456 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -6,11 +6,11 @@ import android.hardware.SensorManager; import android.location.Location; import android.os.Looper; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresPermission; -import android.support.annotation.StyleRes; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresPermission; +import androidx.annotation.StyleRes; +import androidx.annotation.VisibleForTesting; import android.view.WindowManager; import com.mapbox.android.core.location.LocationEngine; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java index 04987621e..7a7b24149 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.location; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.android.core.location.LocationEngine; import com.mapbox.android.core.location.LocationEngineRequest; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index ce3823303..17fc2c063 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -5,8 +5,8 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.SystemClock; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.Surface; import android.view.WindowManager; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java index 48c89622c..e5b56865d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -5,12 +5,12 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.ColorInt; -import android.support.annotation.Dimension; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StyleRes; +import androidx.annotation.ColorInt; +import androidx.annotation.Dimension; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.mapboxsdk.R; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java index f2e4d0bb4..652b636a9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentPositionManager.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.style.layers.Layer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index 54f8ee6d1..aeb011e81 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; import android.graphics.PointF; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.google.gson.JsonArray; import com.google.gson.JsonObject; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index dff7369cd..7038367e3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -4,8 +4,8 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java index 938f4ec74..7782d8822 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.location; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java index 1d09f8ae7..af7a73644 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.animation.AnimatorSet; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.animation.Interpolator; import java.util.List; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java index 24bb82a2d..52ab7c4fc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java index d7d518bc8..94f405b69 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location; import android.animation.FloatEvaluator; import android.animation.TypeEvaluator; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; class MapboxFloatAnimator extends MapboxAnimator { MapboxFloatAnimator(Float previous, Float target, AnimationsValueChangeListener updateListener, int maxAnimationFps) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java index 507069114..524847036 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.animation.TypeEvaluator; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java index 74c2e3a73..7d9c658d6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/StaleStateManager.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location; import android.os.Handler; import android.os.Message; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.lang.ref.WeakReference; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java index 178183ca0..5389d1062 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java @@ -7,8 +7,8 @@ import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.LayerDrawable; import android.location.Location; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java index 51806a33c..3e280e48d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/CameraMode.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location.modes; import android.location.Location; -import android.support.annotation.IntDef; +import androidx.annotation.IntDef; import com.mapbox.mapboxsdk.location.LocationComponent; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java index 3d20313df..fbb17d224 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/RenderMode.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.location.modes; -import android.support.annotation.IntDef; +import androidx.annotation.IntDef; import com.mapbox.mapboxsdk.location.CompassEngine; import com.mapbox.mapboxsdk.location.LocationComponent; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java index b6c4bc872..ae4cac019 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/log/Logger.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.log; -import android.support.annotation.IntDef; -import android.support.annotation.Keep; +import androidx.annotation.IntDef; +import androidx.annotation.Keep; import android.util.Log; import java.lang.annotation.Retention; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java index e5bf51279..d27bcdf2e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java index 8875e7164..875b7da5a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -4,9 +4,9 @@ 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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.LongSparseArray; import android.view.View; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.R; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java index ae41cbb0c..980425c0c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.annotations.Annotation; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 5384a29fc..bd54d33d9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -7,8 +7,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Toast; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java index a1fd4e7e3..432f68a17 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.maps; import android.os.Handler; import android.os.Message; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.ref.WeakReference; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java index 3a0824ad1..10a356047 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java index a261c2f4b..73ead3bc0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.Keep; +import androidx.annotation.Keep; @Keep class Image { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java index 434244a7c..0f482b2d1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.text.TextUtils; import com.mapbox.mapboxsdk.annotations.InfoWindow; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java index 8af9f2c6a..36625035e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.maps; import android.app.Fragment; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 90e3934f7..461db80c6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -7,8 +7,8 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.InputDevice; import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java index afb80027d..8ddb3bbf1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; import android.os.Handler; import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 558343e8c..094d05f4d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -5,11 +5,11 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import android.support.annotation.CallSuper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.collection.LongSparseArray; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index c6b923865..970ea9801 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -5,12 +5,12 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; -import android.support.annotation.FloatRange; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Size; -import android.support.annotation.UiThread; +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; +import androidx.annotation.UiThread; import android.text.TextUtils; import android.view.View; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 827756870..8867d0768 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -7,12 +7,12 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.support.v4.content.res.ResourcesCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.core.content.res.ResourcesCompat; import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java index b408d9f5c..0358f36b9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.RectF; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java index 62859d58a..311e74140 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.RectF; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.Marker; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 4f7db45ff..806421d01 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 5917a8b42..66b0538d6 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -5,10 +5,10 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.os.Handler; -import android.support.annotation.IntRange; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.IntRange; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import com.mapbox.geojson.Feature; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java index 31b459abb..8a27be1c7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/OnMapReadyCallback.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * Interface definition for a callback to be invoked when the map is ready to be used. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java index a7e2ace06..90d900c75 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.Polygon; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java index 2a0190b5b..0bec558e9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.PolygonOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java index e11da26e0..4de35a1f2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.Polyline; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java index c9a865cdd..10b53e6a6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.annotations.PolylineOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index ae28576fa..66124edee 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; +import androidx.annotation.FloatRange; +import androidx.annotation.NonNull; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.constants.GeometryConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java index 9c2b97b6a..fb06dee1b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.RectF; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index b21186050..31c1ae982 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.StringDef; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringDef; import android.util.DisplayMetrics; import android.util.Pair; import com.mapbox.mapboxsdk.constants.MapboxConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java index 011a0bdaa..33a0ee000 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.maps; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index f785aacf3..9e8fb8420 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 3fd155837..f7bd28eb4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -7,14 +7,14 @@ import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.ColorInt; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Px; -import android.support.annotation.UiThread; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.res.ResourcesCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.FloatRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Px; +import androidx.annotation.UiThread; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java index 947ed3555..08c4c9663 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.maps.renderer; import android.content.Context; -import android.support.annotation.CallSuper; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.CallSuper; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java index 2ec82ea20..0dcf64c8e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps.renderer; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Peer class for {@link Runnable}s to be scheduled on the {@link MapRenderer} thread. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java index fd12cceee..237350461 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps.renderer; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Can be used to schedule work on the map renderer diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java index 178911b0a..0a84464cf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.maps.renderer.egl; import android.opengl.GLSurfaceView; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java index 2d0c0ed69..c1836ebb4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview; import android.content.Context; import android.opengl.GLSurfaceView; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/MapboxGLSurfaceView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/MapboxGLSurfaceView.java index ccdbc5822..e110601b7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/MapboxGLSurfaceView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/MapboxGLSurfaceView.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview; import android.content.Context; import android.opengl.GLSurfaceView; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.AttributeSet; /** diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java index 46e6463fe..36441842a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps.renderer.textureview; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.TextureView; import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java index 205e35641..0604b3de4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.maps.renderer.textureview; import android.graphics.SurfaceTexture; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import android.view.TextureView; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index b593076dc..551aad36f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java @@ -2,11 +2,11 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.content.Context; 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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.core.view.ViewPropertyAnimatorCompat; +import androidx.core.view.ViewPropertyAnimatorListenerAdapter; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java index 24cb353d2..8903bbdf1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.module.http; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import com.mapbox.mapboxsdk.BuildConfig; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtil.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtil.java index 5d8dafbdf..25a96f759 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtil.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestUtil.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.module.http; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import okhttp3.OkHttpClient; import okio.Buffer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactory.java index 14b5c6231..1a4419a20 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/MapEventFactory.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.module.telemetry; import android.os.Bundle; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; +import androidx.annotation.FloatRange; +import androidx.annotation.NonNull; import com.mapbox.android.telemetry.TelemetryUtils; import com.mapbox.mapboxsdk.constants.MapboxConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadEndEvent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadEndEvent.java index 9f1b053a8..0a85b143a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadEndEvent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadEndEvent.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.module.telemetry; import android.annotation.SuppressLint; -import android.support.annotation.FloatRange; +import androidx.annotation.FloatRange; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.offline.OfflineRegion; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadStartEvent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadStartEvent.java index 497c7e658..31f41ffc7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadStartEvent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/OfflineDownloadStartEvent.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.module.telemetry; import android.annotation.SuppressLint; -import android.support.annotation.FloatRange; +import androidx.annotation.FloatRange; import com.mapbox.mapboxsdk.constants.MapboxConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PhoneState.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PhoneState.java index a7f574bf4..ec0e1e17a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PhoneState.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PhoneState.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.res.Configuration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DisplayMetrics; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java index e33fb7c1b..0b0a26254 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.module.telemetry; import android.content.Context; import android.os.Bundle; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; +import androidx.annotation.FloatRange; +import androidx.annotation.NonNull; import com.mapbox.android.accounts.v1.MapboxAccounts; import com.mapbox.android.telemetry.AppUserTurnstile; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java index b62688490..632b519f8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java @@ -7,9 +7,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java index 491013e87..bbc70673a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.net; -import android.support.annotation.Keep; +import androidx.annotation.Keep; import com.mapbox.mapboxsdk.LibraryLoader; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java index 48a46d0b0..0fec147ee 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.offline; import android.os.Parcel; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index b5f296a7a..5d0d33da3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -4,10 +4,10 @@ import android.annotation.SuppressLint; import android.content.Context; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java index 79928c649..994c68ab5 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java @@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.offline; import android.content.Context; import android.os.Handler; import android.os.Looper; -import android.support.annotation.IntDef; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.IntDef; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java index 29ba2e27f..1b29800c3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.offline; import android.os.Parcelable; -import android.support.annotation.Keep; +import androidx.annotation.Keep; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java index 3f60f43c4..9b7ff5355 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.offline; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.StringDef; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.StringDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java index eff132a1a..7f86cd750 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.offline; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * A region's status includes its active/inactive state as well as counts diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java index eff9644e5..67d1744f4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.offline; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java index 4da835a5f..46faf8bd2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.snapshotter; import android.graphics.Bitmap; import android.graphics.PointF; -import android.support.annotation.Keep; +import androidx.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; /** diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 990bd3226..c5e2b0164 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -7,11 +7,11 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Handler; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.support.v4.content.res.ResourcesCompat; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.core.content.res.ResourcesCompat; import android.text.Html; import android.text.TextUtils; import android.util.DisplayMetrics; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index 07e5b7e16..8efd8d219 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -6,10 +6,10 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Environment; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.constants.MapboxConstants; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java index eae83e8c1..f278317d5 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.storage; -import android.support.annotation.IntDef; +import androidx.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 0003006b7..c03bb05b4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.style.expressions; import android.annotation.SuppressLint; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Size; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; import com.google.gson.Gson; import com.google.gson.JsonArray; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java index af37a8bee..a3a537da9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java @@ -2,19 +2,14 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; - /** * The background color or pattern of the map. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CannotAddLayerException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CannotAddLayerException.java index 783f9e902..b85158ce6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CannotAddLayerException.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CannotAddLayerException.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Thrown when adding a layer to a map twice diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index e805b031b..9de4fa089 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -2,18 +2,16 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A filled circle. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java index c03f8689f..0dd0df0b2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Custom layer. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java index 286a6e7ee..d36823df0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java @@ -2,18 +2,16 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * An extruded (3D) polygon. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java index fba023735..8cc6330b7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java @@ -2,18 +2,16 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A filled polygon with an optional stroked border. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java index 3eccd4509..3c652388f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java @@ -2,18 +2,16 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A heatmap. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java index 7e503597e..3efeffc1b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java @@ -2,19 +2,14 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; - /** * Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java index fffa471ba..c84291cd7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.style.expressions.Expression; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java index ed88a8591..5417e814e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; class LayoutPropertyValue extends PropertyValue { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java index d6823e582..0fdbaf7fe 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java @@ -2,18 +2,16 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A stroked line. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java index e6ac2d976..394258834 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; class PaintPropertyValue extends PropertyValue { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java index 52ed6c23a..f2c0c7898 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.StringDef; +import androidx.annotation.StringDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 66a6fe20b..79c8ea128 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; +import androidx.annotation.ColorInt; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.types.Formatted; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java index ddf85f386..735ba3d70 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.JsonArray; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.exceptions.ConversionException; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java index 2fd658dc9..1f4b844cb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java @@ -2,18 +2,11 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; - -import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; /** * Raster map textures such as satellite imagery. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java index 5ab47def4..156e11126 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java @@ -2,20 +2,17 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.TransitionOptions; import com.mapbox.mapboxsdk.style.types.Formatted; -import com.mapbox.mapboxsdk.style.types.FormattedSection; /** * An icon or a text label. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java index 3fa8400ee..98b8154bc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Resembles transition property from the style specification. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java index 020e768ff..24105bb0c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.style.light; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java index 5678b6447..0bb5be53b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.style.light; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Position of the light source relative to lit (extruded) geometries. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CannotAddSourceException.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CannotAddSourceException.java index a418cb61a..d6be7a7c8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CannotAddSourceException.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CannotAddSourceException.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * Thrown when adding a source to a map twice diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java index b75ccf5a9..1bd53fd04 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.support.annotation.WorkerThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.annotation.WorkerThread; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySourceOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySourceOptions.java index b5a5d6aad..dd5998b04 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySourceOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySourceOptions.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.util.HashMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java index 091079ab9..58997b6e1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.style.expressions.Expression; import java.util.HashMap; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index 7a5451528..286d90e8f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; import com.mapbox.geojson.Geometry; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java index 17e7f0f5e..1ca67011a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.WorkerThread; +import androidx.annotation.WorkerThread; import com.mapbox.geojson.FeatureCollection; import com.mapbox.mapboxsdk.geometry.LatLngBounds; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java index 33ec6a74c..09cbb8584 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java @@ -4,11 +4,11 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.DrawableRes; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.DrawableRes; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.geometry.LatLngQuad; import com.mapbox.mapboxsdk.utils.BitmapUtils; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java index 9e360c46c..4648d7efc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import java.net.URI; import java.net.URL; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java index 829226cdd..9eb9f575c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.net.URI; import java.net.URL; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index 7d5838541..7d2c409b0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.utils.ThreadUtils; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java index 1e4be2418..5e8db3839 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.NonNull; -import android.support.annotation.Size; +import androidx.annotation.NonNull; +import androidx.annotation.Size; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java index 8135b055d..1fc3878f9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.style.sources; -import android.support.annotation.Keep; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.UiThread; /** * An unknown type of source diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java index d847418d6..def63df29 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java @@ -1,11 +1,11 @@ package com.mapbox.mapboxsdk.style.sources; import android.net.Uri; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.Size; -import android.support.annotation.UiThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; +import androidx.annotation.UiThread; import com.mapbox.geojson.Feature; import com.mapbox.mapboxsdk.style.expressions.Expression; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java index b76e4f441..d877f4f3f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.style.types; -import android.support.annotation.Keep; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.Nullable; import java.util.Arrays; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java index f553b0433..52d95f906 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.style.types; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.utils.ColorUtils; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java index 32c5e40a4..d698fb181 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java @@ -6,9 +6,9 @@ import android.graphics.Paint; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Typeface; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.WorkerThread; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; /** * LocalGlyphRasterizer is the Android-specific platform implementation used diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java index e90c416a2..4e0125eb8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java @@ -4,10 +4,10 @@ import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.support.annotation.AnimatorRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.animation.FastOutSlowInInterpolator; +import androidx.annotation.AnimatorRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import android.view.View; /** diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java index 3570aa2c0..aa0b370e4 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java @@ -8,11 +8,11 @@ import android.graphics.PorterDuff; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.view.View; import java.io.ByteArrayOutputStream; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java index 8d741d1bd..f33c25701 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java @@ -5,9 +5,9 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; import android.os.Build; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.v4.widget.ImageViewCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.core.widget.ImageViewCompat; import android.util.TypedValue; import android.widget.ImageView; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FileUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FileUtils.java index 87507363f..f1d30354c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FileUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FileUtils.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.utils; import android.os.AsyncTask; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java index 627b34217..c22cb9de7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.utils; import android.graphics.Typeface; import android.os.Build; -import android.support.annotation.RequiresApi; +import androidx.annotation.RequiresApi; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.log.Logger; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java index 884e0a42b..cdd0ff492 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.utils; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/StringUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/StringUtils.java index 8a0be63de..2686d4e53 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/StringUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/StringUtils.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.utils; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; import java.text.Normalizer; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java index 6c4018622..4b724d68e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.utils; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Looper; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.exceptions.CalledFromWorkerThreadException; /** diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java index 966c75631..5004ad5bb 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxInjector.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.lang.reflect.Field; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java index 0c61b01be..7ddd0dc59 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.annotations; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.maps.MapboxMap; import org.junit.Before; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java index 2660c819d..d5256735c 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.location; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.maps.Style; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java index b1e1f14cb..6e454a7f7 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.R; import org.junit.Before; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index ed2d015d8..5ff7c2bb3 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.google.gson.JsonElement; import com.mapbox.geojson.Feature; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java index fd59f52a5..21855fe4f 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps; -import android.support.v4.util.LongSparseArray; +import androidx.collection.LongSparseArray; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java index cb097c283..ac219fed1 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.mapbox.android.gestures.MoveGestureDetector; import com.mapbox.android.gestures.RotateGestureDetector; import com.mapbox.android.gestures.ShoveGestureDetector; diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java index fac69826a..28d55931a 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.utils; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; diff --git a/MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/KeepDetector.kt b/MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/KeepDetector.kt index 21093fc15..93d9a5af9 100644 --- a/MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/KeepDetector.kt +++ b/MapboxGLAndroidSDKLint/src/main/java/com/mapbox/mapboxsdk/lint/KeepDetector.kt @@ -69,7 +69,7 @@ class KeepDetector : Detector(), SourceCodeScanner, FileScanner { } private fun hasKeepAnnotation(uAnnotated: UAnnotated): Boolean { - return uAnnotated.findAnnotation("android.support.annotation.Keep") != null + return uAnnotated.findAnnotation("androidx.annotation.Keep") != null } } } \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/androidTest/AndroidManifest.xml index a9dd564e4..baadbab5c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/AndroidManifest.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt index 5c275df07..48364eab0 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk import android.app.Application import android.content.Context -import android.support.test.runner.AndroidJUnitRunner +import androidx.test.runner.AndroidJUnitRunner class InstrumentationRunner : AndroidJUnitRunner() { override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt index f840e970d..488eb0015 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.camera import android.graphics.PointF -import android.support.test.annotation.UiThreadTest -import android.support.test.runner.AndroidJUnit4 +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.geometry.LatLngBounds import com.mapbox.mapboxsdk.testapp.activity.BaseTest diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt index 2afff34d3..8c79e3ccb 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.integration import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK -import android.support.test.InstrumentationRegistry -import android.support.test.uiautomator.* +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.* import com.mapbox.mapboxsdk.AppCenter import org.junit.Before @@ -27,10 +27,10 @@ abstract class BaseIntegrationTest : AppCenter() { *

    */ fun UiDevice.launchActivity(context: Context, clazz: Class<*>) { - val applicationPackage = InstrumentationRegistry.getTargetContext().packageName + val applicationPackage = InstrumentationRegistry.getInstrumentation().targetContext.packageName val intent = Intent(context, clazz) intent.addFlags(FLAG_ACTIVITY_NEW_TASK) - InstrumentationRegistry.getContext().startActivity(intent) + InstrumentationRegistry.getInstrumentation().context.startActivity(intent) wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT) } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt index 5673ffd4c..049a93aa4 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.UiSelector +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import androidx.test.uiautomator.UiSelector import com.mapbox.mapboxsdk.testapp.activity.fragment.FragmentBackStackActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt index 40bc182bd..95480e4c9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt index 5bf45518e..78f82a142 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt index 8d5b5eb8a..79b2a0c62 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/QueryRenderedFeaturesBoxCountTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/QueryRenderedFeaturesBoxCountTest.kt index e94d568e8..2206088ac 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/QueryRenderedFeaturesBoxCountTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/QueryRenderedFeaturesBoxCountTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesBoxCountActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt index cbfd5d6d5..0786ce7c6 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.textureview.TextureViewDebugModeActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt index dc2f74df4..d3aa19b4c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.testapp.activity.maplayout.TextureRecyclerViewActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt index 5178ea9fc..ec43ab2b5 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.integration -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.UiSelector +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import androidx.test.uiautomator.UiSelector import com.mapbox.mapboxsdk.testapp.activity.fragment.ViewPagerActivity import org.junit.Rule import org.junit.Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index 51c9e1c10..18206de7f 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -6,13 +6,13 @@ import android.content.Context import android.graphics.Color import android.graphics.RectF import android.location.Location -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.IdlingRegistry -import android.support.test.espresso.UiController -import android.support.test.espresso.assertion.ViewAssertions.matches -import android.support.test.espresso.matcher.ViewMatchers.* -import android.support.test.rule.GrantPermissionRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.IdlingRegistry +import androidx.test.espresso.UiController +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.GrantPermissionRule import com.mapbox.geojson.Point import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt index ab70f188c..03c395a59 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -3,16 +3,16 @@ package com.mapbox.mapboxsdk.location import android.Manifest import android.content.Context import android.location.Location -import android.support.test.annotation.UiThreadTest -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.IdlingRegistry -import android.support.test.espresso.UiController -import android.support.test.espresso.assertion.ViewAssertions.matches -import android.support.test.espresso.matcher.ViewMatchers.isDisplayed -import android.support.test.espresso.matcher.ViewMatchers.withId -import android.support.test.rule.GrantPermissionRule -import android.support.test.rule.GrantPermissionRule.grant -import android.support.test.runner.AndroidJUnit4 +import androidx.test.annotation.UiThreadTest +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.IdlingRegistry +import androidx.test.espresso.UiController +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.GrantPermissionRule +import androidx.test.rule.GrantPermissionRule.grant import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.location.LocationComponentConstants.* diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt index 3cb9e51bf..dd8d6fc68 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.location.utils import android.content.Context -import android.support.test.espresso.UiController -import android.support.test.espresso.ViewAction -import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.view.View +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import com.mapbox.mapboxsdk.location.LocationComponent import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt index 050535f6d..43e6d55f6 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.location.utils -import android.support.test.espresso.IdlingResource +import androidx.test.espresso.IdlingResource import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/BaseLayerTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/BaseLayerTest.kt index 27c040fbb..f55555135 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/BaseLayerTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/BaseLayerTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.style.layers.Layer import org.junit.runner.RunWith @@ -16,7 +16,7 @@ abstract class BaseLayerTest : AppCenter() { } fun before() { - val context = InstrumentationRegistry.getContext() + val context = InstrumentationRegistry.getInstrumentation().context nativeMapView = NativeMapView(context, false, null, null, NativeMapViewTest.DummyRenderer(context)) nativeMapView.resizeView(WIDTH, HEIGHT) } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GesturesUiTestUtils.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GesturesUiTestUtils.kt index f3af38645..535046fa7 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GesturesUiTestUtils.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GesturesUiTestUtils.kt @@ -2,13 +2,13 @@ package com.mapbox.mapboxsdk.maps import android.graphics.PointF import android.os.SystemClock -import android.support.test.espresso.Espresso -import android.support.test.espresso.InjectEventSecurityException -import android.support.test.espresso.UiController -import android.support.test.espresso.ViewAction -import android.support.test.espresso.matcher.ViewMatchers import android.view.MotionEvent import android.view.View +import androidx.test.espresso.Espresso +import androidx.test.espresso.InjectEventSecurityException +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.matcher.ViewMatchers import org.hamcrest.Matcher object GesturesUiTestUtils { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt index 525c576df..659c2e1b3 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.matcher.ViewMatchers.withId import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.constants.MapboxConstants diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 00ec1fe60..a9e009cb7 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Color; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import android.view.View; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.Marker; @@ -21,9 +21,9 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertNotNull; import static org.junit.Assert.assertEquals; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java index 5b737dd4d..73e96a963 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.AppCenter; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt index dc313b5f6..fd4cb228d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.maps import android.content.Context import android.graphics.PointF -import android.support.test.InstrumentationRegistry -import android.support.test.annotation.UiThreadTest -import android.support.test.runner.AndroidJUnit4 +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng @@ -40,7 +40,7 @@ class NativeMapViewTest : AppCenter() { @Before @UiThreadTest fun before() { - val context = InstrumentationRegistry.getContext() + val context = InstrumentationRegistry.getInstrumentation().context nativeMapView = NativeMapView(context, 2.0f, false, null, null, DummyRenderer(context)) nativeMapView.resizeView(WIDTH, HEIGHT) } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TransformTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TransformTest.kt index 6b59411ae..7153ed0ac 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TransformTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TransformTest.kt @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.maps -import android.support.test.espresso.UiController +import androidx.test.espresso.UiController import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt index 12dff5d45..245d43378 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.maps import android.graphics.PointF -import android.support.test.espresso.UiController +import androidx.test.espresso.UiController import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt index 6b5bc63ad..37360b519 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.offline -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.geojson.Point import com.mapbox.mapboxsdk.log.Logger import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt index 9fca11c01..167656610 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.snapshotter -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java index 926212afc..3f40c56e2 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java @@ -1,17 +1,17 @@ package com.mapbox.mapboxsdk.testapp.action; -import android.support.annotation.NonNull; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.annotation.NonNull; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import android.view.View; import com.mapbox.mapboxsdk.maps.MapboxMap; import org.hamcrest.Matcher; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; public class MapboxMapAction implements ViewAction { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java index 1bf5a8797..5e3435a08 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java @@ -4,14 +4,14 @@ import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ActivityInfo; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import android.view.View; import android.view.ViewGroup; import org.hamcrest.Matcher; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; public class OrientationAction implements ViewAction { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java index e3741f3d4..5d1380e05 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java @@ -1,13 +1,13 @@ package com.mapbox.mapboxsdk.testapp.action; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import android.view.View; import org.hamcrest.Matcher; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; public final class WaitAction implements ViewAction { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java index b6c16c814..185b3f9bb 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.testapp.activity; import android.content.Context; -import android.support.annotation.CallSuper; -import android.support.annotation.UiThread; -import android.support.test.rule.ActivityTestRule; -import android.support.test.rule.GrantPermissionRule; +import androidx.annotation.CallSuper; +import androidx.annotation.UiThread; +import androidx.test.rule.ActivityTestRule; +import androidx.test.rule.GrantPermissionRule; import com.mapbox.mapboxsdk.AppCenter; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java index c168bf5f2..7c0f564b3 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.support.annotation.UiThread; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs index 22082400b..47501a62e 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs @@ -5,7 +5,7 @@ // This file is generated. Edit android/platform/scripts/generate-test-code.js, then run `make generate-test-android`. package com.mapbox.mapboxsdk.testapp.activity.gen.<%- subPackage %>; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.testapp.activity.BaseTest; import com.mapbox.mapboxsdk.testapp.activity.<%- subPackage %>.<%- activity %>; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java index 559213af3..868af7e55 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.annotations; import android.app.Activity; -import android.support.test.annotation.UiThreadTest; -import android.support.v4.content.res.ResourcesCompat; +import androidx.test.annotation.UiThreadTest; +import androidx.core.content.res.ResourcesCompat; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java index 2328023a3..eda71aedd 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java @@ -10,10 +10,10 @@ import com.mapbox.mapboxsdk.testapp.utils.TestConstants; import org.junit.Ignore; import org.junit.Test; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke; import static org.junit.Assert.assertEquals; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java index 4365ea95f..fcc4106a4 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.camera; -import android.support.annotation.NonNull; -import android.support.test.annotation.UiThreadTest; +import androidx.annotation.NonNull; +import androidx.test.annotation.UiThreadTest; import com.mapbox.geojson.Point; import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.camera.CameraPosition; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt index f695f3efe..9d27ff9e6 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt @@ -1,12 +1,12 @@ package com.mapbox.mapboxsdk.testapp.fragment -import android.support.test.espresso.Espresso -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.action.ViewActions.click -import android.support.test.espresso.matcher.ViewMatchers.withId -import android.support.test.filters.LargeTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.espresso.Espresso +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.testapp.R import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapInDialogActivity diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java index 81d10a5f1..2b59cebae 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.geometry; -import android.support.test.annotation.UiThreadTest; +import androidx.test.annotation.UiThreadTest; import com.google.gson.JsonArray; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Point; @@ -15,8 +15,8 @@ import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils; import org.junit.Test; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; import static com.mapbox.geojson.Feature.fromGeometry; import static com.mapbox.geojson.FeatureCollection.fromFeatures; import static com.mapbox.geojson.GeometryCollection.fromGeometries; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ImageMissingTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ImageMissingTest.kt index dd046f018..36bfb5e9d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ImageMissingTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ImageMissingTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.maps -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RemoveUnusedImagesTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RemoveUnusedImagesTest.kt index d586a7e2d..72255bc91 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RemoveUnusedImagesTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RemoveUnusedImagesTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.maps import android.graphics.Bitmap -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt index afe6e7c09..a898fe024 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/RenderViewGetterTest.kt @@ -1,11 +1,11 @@ package com.mapbox.mapboxsdk.testapp.maps import android.opengl.GLSurfaceView -import android.support.test.annotation.UiThreadTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 import android.view.TextureView import android.view.ViewGroup +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapboxMapOptions diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt index 3894bf46f..b06a7d8c8 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/ScreenCoordinateConversion.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.maps import android.graphics.PointF -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.MapView diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt index 951750f35..178404e9a 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.maps -import android.support.test.espresso.UiController -import android.support.test.runner.AndroidJUnit4 +import androidx.test.espresso.UiController +import androidx.test.ext.junit.runners.AndroidJUnit4 import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.style.layers.SymbolLayer diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java index ca5c9adc1..bb25a1d51 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java @@ -4,9 +4,9 @@ import android.app.Instrumentation; import android.content.Intent; import android.net.Uri; import android.os.Build; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.support.test.espresso.intent.Intents; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.intent.Intents; import android.text.Html; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -24,18 +24,18 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import static android.support.test.espresso.Espresso.onData; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.intent.Intents.intended; -import static android.support.test.espresso.intent.Intents.intending; -import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction; -import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData; -import static android.support.test.espresso.matcher.RootMatchers.isDialog; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.intent.Intents.intended; +import static androidx.test.espresso.intent.Intents.intending; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anything; import static org.hamcrest.core.IsNot.not; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java index 8b62ee761..a01274c8b 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java @@ -10,11 +10,11 @@ import com.mapbox.mapboxsdk.testapp.utils.TestConstants; import org.junit.Ignore; import org.junit.Test; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java index 677ad6caa..e066156b5 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import android.view.View; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -11,10 +11,10 @@ import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import org.hamcrest.Matcher; import org.junit.Test; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.Matchers.not; public class LogoTest extends EspressoTest { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt index da4cfbaf0..ae34a12bf 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/CacheTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.offline import android.content.Context -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity import java.util.concurrent.CountDownLatch diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt index e07dc1e9f..3b855edce 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.offline import android.content.Context -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.offline.OfflineRegion diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineUtilsTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineUtilsTest.java index 48eb8e832..115691c1e 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineUtilsTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineUtilsTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.offline; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.AppCenter; import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/render/RenderTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/render/RenderTest.java index c74e110b6..7ade1c78b 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/render/RenderTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/render/RenderTest.java @@ -1,12 +1,12 @@ package com.mapbox.mapboxsdk.testapp.render; import android.Manifest; -import android.support.test.espresso.IdlingPolicies; -import android.support.test.espresso.IdlingRegistry; -import android.support.test.espresso.IdlingResourceTimeoutException; -import android.support.test.rule.ActivityTestRule; -import android.support.test.rule.GrantPermissionRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.espresso.IdlingPolicies; +import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.IdlingResourceTimeoutException; +import androidx.test.rule.ActivityTestRule; +import androidx.test.rule.GrantPermissionRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.AppCenter; import com.mapbox.mapboxsdk.testapp.activity.render.RenderTestActivity; @@ -21,10 +21,10 @@ import timber.log.Timber; import java.util.concurrent.TimeUnit; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; /** * Instrumentation render tests diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceMapTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceMapTest.kt index d08507470..b1bae5479 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceMapTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceMapTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.storage -import android.support.test.annotation.UiThreadTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.storage.FileSource import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceStandaloneTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceStandaloneTest.kt index 59f0d0423..a1cbb73ba 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceStandaloneTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceStandaloneTest.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.storage -import android.support.test.annotation.UiThreadTest -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.storage.FileSource import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTestUtils.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTestUtils.kt index 6bd97056a..ad701f0c6 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTestUtils.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTestUtils.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.storage import android.app.Activity -import android.support.annotation.WorkerThread +import androidx.annotation.WorkerThread import com.mapbox.mapboxsdk.AppCenter import com.mapbox.mapboxsdk.storage.FileSource import java.io.File diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java index 0ef8051a3..bffbbfcf9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.string; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java index d3edfb852..8ec149874 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java @@ -3,20 +3,18 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; -import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.BackgroundLayer; import org.junit.Test; import org.junit.runner.RunWith; -import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java index 146cfc220..fbe812c7d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index 9c2eb3df8..359dc6469 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.style -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.matcher.ViewMatchers.isRoot +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.matcher.ViewMatchers.isRoot import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_POOL_LIMIT import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_PREFIX import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java index 95bd651cf..fc195e151 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Point; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java index 4b936a4c9..ecbae353c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java index 4e9dddc0a..d886f58cc 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java index 61086e134..37f75a19d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.style; -import android.support.annotation.RawRes; -import android.support.test.espresso.ViewAction; -import android.support.test.runner.AndroidJUnit4; +import androidx.annotation.RawRes; +import androidx.test.espresso.ViewAction; +import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.View; import com.mapbox.geojson.Feature; @@ -28,7 +28,7 @@ import java.util.List; import timber.log.Timber; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static org.junit.Assert.assertEquals; /** diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java index 21a17723d..566dd7a70 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java @@ -2,9 +2,8 @@ package com.mapbox.mapboxsdk.testapp.style; -import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java index 694348b88..60e977429 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java @@ -3,20 +3,18 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; -import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.HillshadeLayer; import org.junit.Test; import org.junit.runner.RunWith; -import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt index eb45ab52c..c4b04cc18 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.style import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable -import android.support.test.runner.AndroidJUnit4 +import androidx.test.ext.junit.runners.AndroidJUnit4 import com.mapbox.mapboxsdk.testapp.R import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction import com.mapbox.mapboxsdk.testapp.activity.EspressoTest diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java index b78a2d26e..3dece5e3e 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.View; import com.mapbox.mapboxsdk.style.light.Light; @@ -21,9 +21,9 @@ import org.hamcrest.Matcher; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java index 4c8e70d3d..18bb31da0 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java index aa50b1fe5..55ffe97dd 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java @@ -2,21 +2,18 @@ package com.mapbox.mapboxsdk.testapp.style; -import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; -import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.RasterLayer; import org.junit.Test; import org.junit.runner.RunWith; -import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java index 2d1fbf5fc..dac7d64fc 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; import android.graphics.PointF; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.View; import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.CircleLayer; @@ -28,9 +28,9 @@ import timber.log.Timber; import java.util.List; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java index 4dd01d06c..f40c538de 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.style; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.testapp.activity.BaseTest; import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTimingTestActivity; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java index 02205b3c9..207d346f4 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index 141114c1a..c71ea0d37 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -8,7 +8,7 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; import android.support.test.annotation.UiThreadTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs index 9bc77b202..e26ec2d6c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs @@ -6,7 +6,7 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.View; import com.mapbox.mapboxsdk.style.light.Light; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/SnapshotterIdlingResource.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/SnapshotterIdlingResource.java index e0da683e6..4580ebd95 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/SnapshotterIdlingResource.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/SnapshotterIdlingResource.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.utils; -import android.support.test.espresso.IdlingResource; +import androidx.test.espresso.IdlingResource; import com.mapbox.mapboxsdk.testapp.activity.render.RenderTestActivity; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestingAsyncUtils.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestingAsyncUtils.kt index 7c23d8d63..a2446715d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestingAsyncUtils.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestingAsyncUtils.kt @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.utils -import android.support.test.espresso.UiController +import androidx.test.espresso.UiController import com.mapbox.mapboxsdk.maps.MapView object TestingAsyncUtils { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java index fa068cb97..4a4607a9d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.utils; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.constants.MapboxConstants; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java index 9279472cb..8203a4198 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java @@ -8,10 +8,10 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; -import android.support.annotation.StringRes; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.adapter.FeatureAdapter; import com.mapbox.mapboxsdk.testapp.adapter.FeatureSectionAdapter; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java index 7e442aa80..7214d7f12 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedSymbolLayerActivity.java @@ -6,7 +6,7 @@ import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.LinearInterpolator; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java index d8fd42876..aa7949cdb 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Bundle; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java index b10332dd6..18282cf2a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java index f69b38638..c1cb167b4 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java index 855b68669..7c2799c07 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java index eebd93749..d30c0ab25 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.graphics.PointF; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java index 54bf89dde..f300cf2d5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java index 7ce54831f..48e1454e1 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java @@ -5,12 +5,12 @@ import android.animation.AnimatorSet; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; -import android.support.v4.view.animation.FastOutLinearInInterpolator; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.support.v4.view.animation.PathInterpolatorCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.collection.LongSparseArray; +import androidx.interpolator.view.animation.FastOutLinearInInterpolator; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import androidx.core.view.animation.PathInterpolatorCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java index 697909765..ad5e0034a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java @@ -3,13 +3,13 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.app.FragmentActivity; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.Toolbar; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.fragment.app.FragmentActivity; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.widget.SeekBar; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java index f39f25d28..2efc95fa4 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java @@ -3,14 +3,14 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.ColorInt; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.ColorInt; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt index b83ba5c4c..4892c8a38 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.camera import android.content.Context import android.os.Bundle -import android.support.design.widget.BottomSheetBehavior -import android.support.v7.app.AppCompatActivity import android.view.View +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.FeatureCollection.fromJson import com.mapbox.geojson.Point diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java index d9b856d8a..95f735956 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.graphics.Point; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java index 6bc23df75..696ddd495 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java index b06889d11..54bb6d2ce 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java @@ -1,13 +1,13 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import android.widget.SeekBar; import android.widget.TextView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java index 35fbb5635..514d362c2 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.testapp.activity.customlayer; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/DeviceIndependentTestActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/DeviceIndependentTestActivity.java index 5a7dab37c..6197206af 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/DeviceIndependentTestActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/DeviceIndependentTestActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.espresso; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java index 51b504414..c2d7f5e30 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.espresso; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.testapp.R; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt index 7de4da198..85144afac 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.espresso import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.OnMapReadyCallback diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java index 96038f372..aef1f8277 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.feature; import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java index 4d1343279..36b30d5c4 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.feature; import android.graphics.Color; import android.graphics.RectF; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java index 22daf262d..a00e923d5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java @@ -4,7 +4,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.RectF; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java index f2f22bae9..ebb71c371 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java @@ -5,8 +5,8 @@ import android.graphics.PointF; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QuerySourceFeaturesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QuerySourceFeaturesActivity.java index f7d5a39e4..13833a260 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QuerySourceFeaturesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QuerySourceFeaturesActivity.java @@ -1,9 +1,9 @@ package com.mapbox.mapboxsdk.testapp.activity.feature; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.google.gson.JsonObject; import com.mapbox.geojson.Feature; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/FragmentBackStackActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/FragmentBackStackActivity.kt index c0f93fce1..ea0f24260 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/FragmentBackStackActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/FragmentBackStackActivity.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.maps.SupportMapFragment diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java index a0e8b31fc..c374b076e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java index f16f01e2d..157283771 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; -import android.support.v4.app.FragmentManager; -import android.support.v7.app.AppCompatActivity; +import androidx.fragment.app.FragmentManager; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.SupportMapFragment; import com.mapbox.mapboxsdk.testapp.R; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/NestedViewPagerActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/NestedViewPagerActivity.kt index de7f0bb5a..e45770e45 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/NestedViewPagerActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/NestedViewPagerActivity.kt @@ -3,17 +3,16 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment import android.annotation.SuppressLint import android.content.Context import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentManager -import android.support.v4.app.FragmentStatePagerAdapter -import android.support.v4.view.ViewPager -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager.widget.ViewPager import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.MapboxMapOptions @@ -35,11 +34,11 @@ class NestedViewPagerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recyclerview) - recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this) recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this), supportFragmentManager) } - class ItemAdapter(private val context: Context, private val inflater: LayoutInflater, private val fragmentManager: FragmentManager) : RecyclerView.Adapter() { + class ItemAdapter(private val context: Context, private val inflater: LayoutInflater, private val fragmentManager: androidx.fragment.app.FragmentManager) : androidx.recyclerview.widget.RecyclerView.Adapter() { private val items = listOf( "one", "two", "three", ViewPagerItem(), "four", "five", "six", "seven", "eight", "nine", "ten", @@ -54,9 +53,9 @@ class NestedViewPagerActivity : AppCompatActivity() { const val TYPE_TEXT = 1 } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder { return if (viewType == TYPE_VIEWPAGER) { - val viewPager = inflater.inflate(R.layout.item_viewpager, parent, false) as ViewPager + val viewPager = inflater.inflate(R.layout.item_viewpager, parent, false) as androidx.viewpager.widget.ViewPager mapHolder = ViewPagerHolder(context, viewPager, fragmentManager) return mapHolder as ViewPagerHolder } else { @@ -68,7 +67,7 @@ class NestedViewPagerActivity : AppCompatActivity() { return items.count() } - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) { if (holder.itemViewType == TYPE_TEXT) { val textHolder = holder as TextHolder textHolder.bind(items[position] as String) @@ -83,14 +82,14 @@ class NestedViewPagerActivity : AppCompatActivity() { } } - class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { + class TextHolder(val textView: TextView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(textView) { fun bind(item: String) { textView.text = item } } class ViewPagerItem - class ViewPagerHolder(context: Context, private val viewPager: ViewPager, fragmentManager: FragmentManager) : RecyclerView.ViewHolder(viewPager) { + class ViewPagerHolder(context: Context, private val viewPager: androidx.viewpager.widget.ViewPager, fragmentManager: androidx.fragment.app.FragmentManager) : androidx.recyclerview.widget.RecyclerView.ViewHolder(viewPager) { init { viewPager.adapter = MapPagerAdapter(context, fragmentManager) viewPager.setOnTouchListener { view, motionEvent -> @@ -102,9 +101,9 @@ class NestedViewPagerActivity : AppCompatActivity() { } } - class MapPagerAdapter(private val context: Context, fm: FragmentManager?) : FragmentStatePagerAdapter(fm) { + class MapPagerAdapter(private val context: Context, fm: androidx.fragment.app.FragmentManager?) : androidx.fragment.app.FragmentStatePagerAdapter(fm) { - override fun getItem(position: Int): Fragment { + override fun getItem(position: Int): androidx.fragment.app.Fragment { val options = MapboxMapOptions.createFromAttributes(context) options.textureMode(true) options.doubleTapGesturesEnabled(false) @@ -149,7 +148,7 @@ class NestedViewPagerActivity : AppCompatActivity() { } } - class EmptyFragment : Fragment() { + class EmptyFragment : androidx.fragment.app.Fragment() { companion object { fun newInstance(): EmptyFragment { return EmptyFragment() diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java index 6760b5da6..840edf512 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt index d1cb9acab..bc3408d29 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment import android.content.Context import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentManager -import android.support.v4.app.FragmentStatePagerAdapter -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.MapboxMapOptions @@ -38,13 +38,13 @@ class ViewPagerActivity : AppCompatActivity() { } } - internal class MapFragmentAdapter(private val context: Context, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) { + internal class MapFragmentAdapter(private val context: Context, fragmentManager: androidx.fragment.app.FragmentManager) : androidx.fragment.app.FragmentStatePagerAdapter(fragmentManager) { override fun getCount(): Int { return NUM_ITEMS } - override fun getItem(position: Int): Fragment? { + override fun getItem(position: Int): androidx.fragment.app.Fragment? { val options = MapboxMapOptions.createFromAttributes(context) options.textureMode(true) options.camera( diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java index 71757c84a..7b6fb7241 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.imagegenerator; import android.graphics.Bitmap; import android.os.Bundle; -import android.support.v4.print.PrintHelper; -import android.support.v7.app.AppCompatActivity; +import androidx.print.PrintHelper; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt index a55081d96..a907a1b48 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.imagegenerator import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.log.Logger import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapboxMap diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java index c5743518b..b07230671 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.infowindow; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.core.content.res.ResourcesCompat; +import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; import com.mapbox.mapboxsdk.annotations.InfoWindow; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java index 5baa21469..b3def6a87 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.infowindow; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java index 5140a969d..5149fa6ab 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.infowindow; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.TextView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationComponentActivationActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationComponentActivationActivity.java index 927a62461..9a05d93da 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationComponentActivationActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationComponentActivationActivity.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.activity.location; import android.annotation.SuppressLint; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.mapbox.android.core.permissions.PermissionsListener; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt index 7e18cbfa2..6058d436f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt @@ -2,13 +2,13 @@ package com.mapbox.mapboxsdk.testapp.activity.location import android.annotation.SuppressLint import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v7.app.AppCompatActivity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment import com.mapbox.android.core.location.LocationEngineCallback import com.mapbox.android.core.location.LocationEngineResult import com.mapbox.android.core.permissions.PermissionsListener @@ -79,7 +79,7 @@ class LocationFragmentActivity : AppCompatActivity() { permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults) } - class LocationFragment : Fragment(), LocationEngineCallback { + class LocationFragment : androidx.fragment.app.Fragment(), LocationEngineCallback { companion object { const val TAG = "LFragment" fun newInstance(): LocationFragment { @@ -159,7 +159,7 @@ class LocationFragmentActivity : AppCompatActivity() { } } - class EmptyFragment : Fragment() { + class EmptyFragment : androidx.fragment.app.Fragment() { companion object { const val TAG = "EmptyFragment" fun newInstance(): EmptyFragment { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java index a9c876c7c..ef8211c54 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.location; import android.annotation.SuppressLint; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.mapbox.android.core.permissions.PermissionsListener; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java index 0ee99a4fe..e76fb59e5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java @@ -4,9 +4,9 @@ import android.annotation.SuppressLint; import android.content.res.Configuration; import android.location.Location; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.ListPopupWindow; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.ListPopupWindow; import android.view.Menu; import android.view.MenuItem; import android.widget.ArrayAdapter; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java index 180fcfc83..afc524fd3 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.location; import android.annotation.SuppressLint; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.mapbox.android.core.location.LocationEngine; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java index 9db7cb2c9..e48e005fd 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java @@ -2,14 +2,14 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetBehavior; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java index 85b31b85f..848651e5a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java @@ -2,12 +2,12 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java index a4ff5c71d..417d47738 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; +import androidx.appcompat.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt index eae8c71f7..2be42a542 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt @@ -2,12 +2,11 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout import android.annotation.SuppressLint import android.os.Bundle -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.ViewGroup import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.testapp.R @@ -26,7 +25,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recyclerview) - recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this) recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this)) } @@ -46,7 +45,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { return R.layout.item_map_gl } - class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater) : RecyclerView.Adapter() { + class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater) : androidx.recyclerview.widget.RecyclerView.Adapter() { private val items = listOf( "one", "two", "three", MapItem(Style.MAPBOX_STREETS), "four", "five", MapItem(Style.DARK), "seven", "eight", "nine", "ten", @@ -61,7 +60,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { const val TYPE_TEXT = 1 } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder { return if (viewType == TYPE_MAP) { val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView val mapHolder = MapHolder(mapView) @@ -72,7 +71,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { } } - override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { + override fun onViewAttachedToWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) { super.onViewAttachedToWindow(holder) if (holder is MapHolder) { val mapView = holder.mapView @@ -81,7 +80,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { } } - override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { + override fun onViewDetachedFromWindow(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) { super.onViewDetachedFromWindow(holder) if (holder is MapHolder) { val mapView = holder.mapView @@ -94,7 +93,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { return items.count() } - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) { if (holder is TextHolder) { holder.bind(items[position] as String) } else if (holder is MapHolder) { @@ -127,7 +126,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { } data class MapItem(val style: String) - class MapHolder(val mapView: MapView) : RecyclerView.ViewHolder(mapView) { + class MapHolder(val mapView: MapView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(mapView) { init { // unfortunately, if there are multiple maps hosted in one activity, state saving is not possible @@ -145,7 +144,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { } } - class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { + class TextHolder(val textView: TextView) : androidx.recyclerview.widget.RecyclerView.ViewHolder(textView) { fun bind(item: String) { textView.text = item } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java index 2493aa00e..537b53ece 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java index 5abf1846b..d25450b9c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java index ee10d39db..92cbb4dcc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java index 18092ce37..6f89704ba 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java @@ -1,11 +1,11 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentManager; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; +import androidx.appcompat.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java index 688ba46f9..44cba564b 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/OverlayMapActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/OverlayMapActivity.kt index 366645995..d88c17311 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/OverlayMapActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/OverlayMapActivity.kt @@ -4,8 +4,9 @@ import android.annotation.SuppressLint import android.content.Context import android.graphics.* import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import android.os.PersistableBundle import android.view.View +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.testapp.R import kotlinx.android.synthetic.main.activity_overlay.* @@ -55,11 +56,11 @@ class OverlayMapActivity : AppCompatActivity() { mapView.onDestroy() } - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) - outState?.let { - mapView.onSaveInstanceState(it) - } + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) + outState?.let { + mapView.onSaveInstanceState(it) + } } class OverlayView(context: Context) : View(context) { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java index 8406fe233..bb8727d37 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.MenuItem; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.Style; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/VisibilityChangeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/VisibilityChangeActivity.java index 567da3f95..583f9b1ac 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/VisibilityChangeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/VisibilityChangeActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.os.Bundle; import android.os.Handler; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt index 85ae845f6..3ad4dacce 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt @@ -4,7 +4,6 @@ import android.annotation.TargetApi import android.content.Context import android.os.Build import android.os.Bundle -import android.support.v7.app.AppCompatActivity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -12,6 +11,7 @@ import android.widget.AdapterView import android.widget.BaseAdapter import android.widget.TextView import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.log.Logger import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.offline.OfflineRegion diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java index 11ee68702..65f20ee8d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.offline; import android.content.Context; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DownloadRegionActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DownloadRegionActivity.kt index 1febe0bfd..171dcc4f1 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DownloadRegionActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DownloadRegionActivity.kt @@ -2,12 +2,12 @@ package com.mapbox.mapboxsdk.testapp.activity.offline import android.os.Bundle import android.os.Handler -import android.support.v7.app.AppCompatActivity import android.view.View import android.widget.ArrayAdapter import android.widget.SeekBar import android.widget.TextView import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.constants.MapboxConstants import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.geometry.LatLngBounds diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MergeOfflineRegionsActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MergeOfflineRegionsActivity.kt index d6a840ad7..01793f965 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MergeOfflineRegionsActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MergeOfflineRegionsActivity.kt @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.offline import android.os.Bundle -import android.support.v7.app.AppCompatActivity import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import com.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.log.Logger import com.mapbox.mapboxsdk.maps.Style diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java index ed3f91b85..ae817546d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.offline; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java index 2d223f1a4..437fa8145 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.offline; import android.content.Context; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.text.InputType; import android.view.LayoutInflater; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java index 7bbaed192..c56cd9ed6 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java @@ -5,8 +5,8 @@ import android.graphics.Bitmap; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import android.view.Gravity; import android.view.ViewGroup; import android.widget.FrameLayout; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestSnapshotter.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestSnapshotter.java index cb971fee7..ecdae12ba 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestSnapshotter.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestSnapshotter.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.render; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.snapshotter.MapSnapshot; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java index ab7ffed83..c15cf4f25 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.snapshot; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.ViewTreeObserver; import android.widget.GridLayout; import android.widget.ImageView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java index 32c340b2c..1dda9f655 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.snapshot; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java index dea10198b..5190bce90 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java @@ -6,9 +6,9 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.PointF; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AppCompatActivity; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java index 14bc089b9..6b54ff9d5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.snapshot; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/CacheManagementActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/CacheManagementActivity.kt index 7ec6a5076..4cb09c02e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/CacheManagementActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/CacheManagementActivity.kt @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.storage import android.os.Bundle import android.os.Looper -import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.snackbar.Snackbar import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.testapp.R import kotlinx.android.synthetic.main.activity_cache_management.* diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java index 624baefb7..b4ce22dfc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.storage; import android.app.Activity; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.Style; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java index 6c3993d4c..2768d3ed7 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java @@ -6,8 +6,8 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.geometry.LatLng; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java index 846650f6c..43b9199aa 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java index 076cd1d8e..dcdc309eb 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java @@ -2,10 +2,10 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CollectionUpdateOnStyleChange.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CollectionUpdateOnStyleChange.kt index 0b9bd15a3..2a8f97afc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CollectionUpdateOnStyleChange.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CollectionUpdateOnStyleChange.kt @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.style import android.graphics.Color import android.os.Bundle -import android.support.design.widget.FloatingActionButton -import android.support.v7.app.AppCompatActivity import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mapbox.geojson.Feature import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.LineString diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java index 2b2b90b60..0dc627b8d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.BitmapFactory; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import com.mapbox.geojson.Feature; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java index f56694454..3573b284a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt index 249c4e6ec..9d2cb1e09 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt @@ -2,10 +2,11 @@ package com.mapbox.mapboxsdk.testapp.activity.style import android.graphics.PointF import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity +import android.os.PersistableBundle import android.view.MotionEvent import android.view.View +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.snackbar.Snackbar import com.mapbox.android.gestures.AndroidGesturesManager import com.mapbox.android.gestures.MoveGestureDetector import com.mapbox.geojson.Feature @@ -318,8 +319,8 @@ class DraggableMarkerActivity : AppCompatActivity() { mapView.onDestroy() } - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) outState?.let { mapView.onSaveInstanceState(it) } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java index ad953ef6b..845ad4380 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.camera.CameraPosition; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java index 7f6fe4d0a..2e47ac36f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Style; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java index cb2701d43..5a84ce876 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java @@ -4,8 +4,8 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.PointF; import android.os.Bundle; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.core.content.res.ResourcesCompat; +import androidx.appcompat.app.AppCompatActivity; import android.view.MenuItem; import android.widget.Toast; import com.mapbox.geojson.Feature; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GradientLineActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GradientLineActivity.java index 9c7c7560c..b51a35c19 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GradientLineActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GradientLineActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java index 037437f5c..a16cbb67c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java index 57d68f7f0..fca61f541 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Style; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HillshadeLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HillshadeLayerActivity.java index 0ed3a5d13..e3a2bc252 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HillshadeLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HillshadeLayerActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/NoStyleActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/NoStyleActivity.kt index ebc59e653..fbc5667b5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/NoStyleActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/NoStyleActivity.kt @@ -2,8 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.style import android.graphics.drawable.Drawable import android.os.Bundle -import android.support.v4.content.res.ResourcesCompat -import android.support.v7.app.AppCompatActivity +import android.os.PersistableBundle +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.res.ResourcesCompat import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.Style @@ -67,8 +68,8 @@ class NoStyleActivity : AppCompatActivity() { mapView.onDestroy() } - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) outState?.let { mapView.onSaveInstanceState(it) } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java index 4802787ab..ee97e26fa 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index 09bb00b84..1ae2499c6 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java index 375e23666..acca4c86f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java index 5e3ed1248..c6d794d6a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java index e80d6fe3e..3ac7c7c76 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java @@ -7,8 +7,8 @@ import android.graphics.Color; import android.graphics.PointF; import android.os.AsyncTask; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java index ee562ad6e..c2425b9c1 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java @@ -4,8 +4,8 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PointF; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java index 5710ae260..9520fac92 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java @@ -2,8 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.PointF; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import com.google.gson.JsonObject; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java index f15e1baa6..cdf712530 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java @@ -4,7 +4,7 @@ import android.app.ActivityManager; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewAnimationActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewAnimationActivity.java index ac4b36b32..167f75d84 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewAnimationActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewAnimationActivity.java @@ -3,8 +3,8 @@ package com.mapbox.mapboxsdk.testapp.activity.textureview; import android.animation.ObjectAnimator; import android.os.Bundle; import android.os.Handler; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewResizeActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewResizeActivity.java index 4aabedff6..0213c6d3f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewResizeActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewResizeActivity.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.testapp.activity.textureview; import android.os.Bundle; -import android.support.design.widget.CoordinatorLayout; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import com.mapbox.mapboxsdk.maps.MapView; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java index 63571922e..8c34f8d9d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.activity.textureview; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.ViewGroup; import android.widget.ImageView; import com.mapbox.mapboxsdk.camera.CameraPosition; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/PhysicalUnitCircleActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/PhysicalUnitCircleActivity.kt index 5f7377c92..a31ee2c58 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/PhysicalUnitCircleActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/PhysicalUnitCircleActivity.kt @@ -2,8 +2,9 @@ package com.mapbox.mapboxsdk.testapp.activity.turf import android.graphics.Color import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import android.os.PersistableBundle import android.widget.SeekBar +import androidx.appcompat.app.AppCompatActivity import com.mapbox.geojson.Point import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng @@ -116,8 +117,8 @@ class PhysicalUnitCircleActivity : AppCompatActivity(), SeekBar.OnSeekBarChangeL mapView.onDestroy() } - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) outState?.let { mapView.onSaveInstanceState(it) } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java index 7ac3401a0..77d1dd532 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.adapter; import android.graphics.Typeface; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java index 65e2b4f18..5b62f257d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java @@ -1,10 +1,10 @@ package com.mapbox.mapboxsdk.testapp.adapter; import android.content.Context; -import android.support.annotation.IdRes; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.IdRes; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer.java index da28f2156..ce219e1d0 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/customlayer/ExampleCustomLayer.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.model.customlayer; -import android.support.annotation.Keep; +import androidx.annotation.Keep; @Keep public class ExampleCustomLayer { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java index 89096a0a6..b2fddf659 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java @@ -3,9 +3,9 @@ package com.mapbox.mapboxsdk.testapp.model.other; import android.app.Activity; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.appcompat.app.AlertDialog; import android.widget.EditText; import com.mapbox.mapboxsdk.testapp.R; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java index dbaae589e..8263a7d1d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.testapp.model.other; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.appcompat.app.AlertDialog; import com.mapbox.mapboxsdk.testapp.R; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java index b6768a91a..841cb9210 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java @@ -4,11 +4,11 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.v4.content.res.ResourcesCompat; -import android.support.v4.graphics.drawable.DrawableCompat; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.core.content.res.ResourcesCompat; +import androidx.core.graphics.drawable.DrawableCompat; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java index 0939181ef..98a713f8d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.utils; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.view.View; import com.mapbox.mapboxsdk.testapp.R; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/NavUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/NavUtils.java index f59e80e92..dab86a7bc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/NavUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/NavUtils.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.utils; import android.app.Activity; import android.content.Intent; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity; public class NavUtils { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java index 7a6e6ac06..79709f59c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk.testapp.utils; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ResourceUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ResourceUtils.java index 6b522ac21..710841209 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ResourceUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ResourceUtils.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.testapp.utils; import android.content.Context; -import android.support.annotation.RawRes; +import androidx.annotation.RawRes; import android.util.TypedValue; import java.io.BufferedReader; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java index c8af9aee2..db89e92d0 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java @@ -9,8 +9,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.StringDef; +import androidx.annotation.NonNull; +import androidx.annotation.StringDef; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java index e08fdb915..65c9d8c67 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.utils; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.Mapbox; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ViewToBitmapUtil.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ViewToBitmapUtil.java index e8091248f..8fd861ac9 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ViewToBitmapUtil.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ViewToBitmapUtil.java @@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.testapp.utils; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; /** diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/LockableBottomSheetBehavior.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/LockableBottomSheetBehavior.java index a69fb48ab..42cac8eb0 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/LockableBottomSheetBehavior.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/LockableBottomSheetBehavior.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.view; import android.content.Context; -import android.support.design.widget.BottomSheetBehavior; -import android.support.design.widget.CoordinatorLayout; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import androidx.coordinatorlayout.widget.CoordinatorLayout; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/MapViewPager.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/MapViewPager.java index 92c28d7ed..7af379619 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/MapViewPager.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/view/MapViewPager.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.testapp.view; import android.content.Context; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; +import androidx.viewpager.widget.PagerTabStrip; +import androidx.viewpager.widget.ViewPager; import android.util.AttributeSet; import android.view.SurfaceView; import android.view.View; diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml index ff8070dfc..6c550f7ba 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml @@ -14,7 +14,7 @@ app:mapbox_cameraTargetLng="13.400972" app:mapbox_cameraZoom="16"/> - - - + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> - + - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml index 70141250d..bb34d83d7 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml @@ -11,7 +11,7 @@ app:mapbox_cameraTilt="45" app:mapbox_cameraZoom="15"/> - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml index 9b57e18a7..c90903e58 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml @@ -1,12 +1,12 @@ - - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml index 2bc4ff7ed..f5bd0c001 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml @@ -13,7 +13,7 @@ app:mapbox_cameraTargetLng="103.849218" app:mapbox_cameraZoom="10"/> - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml index 800926f89..262bb0739 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml @@ -1,5 +1,5 @@ - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml index af2123028..c4d31742e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml @@ -1,5 +1,5 @@ - - - + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"/> - - - + - - + - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml index e119d3cf7..1a16ab6d9 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml @@ -1,5 +1,5 @@ - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml index 28b23b633..c016a1043 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml index 58e49c3ce..d692e55e4 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml @@ -15,7 +15,7 @@ app:mapbox_cameraTargetLng="-0.11968" app:mapbox_cameraZoom="15" /> - - - + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> - + - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_activation_builder.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_activation_builder.xml index daae10ad0..935f35b83 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_activation_builder.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_activation_builder.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_fragment.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_fragment.xml index 3c1436a1a..7cc66cf75 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_fragment.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_fragment.xml @@ -1,5 +1,5 @@ - @@ -9,7 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_map_change.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_map_change.xml index 54171a073..b23242024 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_map_change.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_map_change.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_mode.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_mode.xml index e23d876e3..a13940f29 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_mode.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_mode.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_manual_update.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_manual_update.xml index 3aac74a1e..d02eb757f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_manual_update.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_manual_update.xml @@ -1,5 +1,5 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_reuse.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_reuse.xml index 5ce25a69d..6ca92308a 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_reuse.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_snapshotter_reuse.xml @@ -10,7 +10,7 @@ android:layout_centerInParent="true" android:contentDescription=""/> - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml index 9bcfd0300..97ea61c0d 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml @@ -14,7 +14,7 @@ app:mapbox_cameraTargetLng="7.573781" app:mapbox_cameraZoom="4" /> - - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_source_features.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_source_features.xml index 27c77cf00..148bab50c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_source_features.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_source_features.xml @@ -1,5 +1,5 @@ - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml index 7d57f112b..c089bb8b2 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml @@ -1,12 +1,12 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_region_download.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_region_download.xml index 4242da9fb..9ecb2aa37 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_region_download.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_region_download.xml @@ -1,12 +1,12 @@ - - - + - - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml index bea754c16..5efd4e45b 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml @@ -1,5 +1,5 @@ - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml index fea40d55a..0740ff404 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + - @@ -88,7 +88,7 @@ app:mapbox_cameraTargetLng="-3.599007" app:mapbox_cameraZoom="15" /> - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml index 0261131df..19f68f136 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml @@ -13,7 +13,7 @@ app:mapbox_cameraTargetLng="13.400972" app:mapbox_cameraZoom="16"/> - - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_debug_mode.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_debug_mode.xml index 480de550a..503ef68dd 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_debug_mode.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_debug_mode.xml @@ -1,5 +1,5 @@ - - - + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"/> - - - + - - + - \ No newline at end of file + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_resize.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_resize.xml index b00076e77..beeec6f52 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_resize.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_resize.xml @@ -1,5 +1,5 @@ - - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml index 096d44e22..e300ec389 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml @@ -1,5 +1,5 @@ - - + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml index 516bf60b6..fcce18b68 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml @@ -9,7 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - Date: Wed, 8 Jan 2020 17:19:35 +0200 Subject: [PATCH 052/185] Bump the gl-native pin and update changelog for alpha.1 for release-unicorn. (#133) --- CHANGELOG.md | 42 +++++++++++++++++++++++++++-------------- vendor/mapbox-gl-native | 2 +- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b57a16ac4..d924fe2f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,30 +2,44 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master +## 9.0.0-alpha.1 - January 8, 2020 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0...android-v9.0.0-alpha.1) since [Mapbox Maps SDK for Android v8.6.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0): +### Features + - Update codebase to androidX. [#129](https://github.com/mapbox/mapbox-gl-native-android/pull/129) + ### Bug fixes -- Fixed a crash caused by an unintentional minification of the `LocalGlyphRasterizer`. [#102](https://github.com/mapbox/mapbox-gl-native-android/pull/102) -- Deprecated `MapboxMap#cycleDebugOptions` and fixed an `UnsatisfiedLinkError` when accessed. [#104](https://github.com/mapbox/mapbox-gl-native-android/pull/104) + - Deprecated `MapboxMap#cycleDebugOptions` and fixed an `UnsatisfiedLinkError` when accessed. [#104](https://github.com/mapbox/mapbox-gl-native-android/pull/104) + - Fixed a null pointer issue on the public static getters of `Mapbox.java`, in case the user hasn't called `Mapbox.getInstance()`. [#128](https://github.com/mapbox/mapbox-gl-native-android/pull/128) + +## 8.6.0 - December 20, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0-beta.1...android-v8.6.0) since [Mapbox Maps SDK for Android v8.6.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0-beta.1): +### Bug fixes + - Revert of a commit that resulted in a native crash when cycle debug options was invoked, issue was only impacting v8.6.0-beta.1 [#16074](https://github.com/mapbox/mapbox-gl-native/pull/16074) + - Fixed a crash caused by an unintentional minification of the `LocalGlyphRasterizer`. The full class definition is now kept when minification is used by end developer [#102](https://github.com/mapbox/mapbox-gl-native-android/pull/102) + - Fixed intermittent offline download failures by clearing the batch buffer if a download is interrupted. [#16074](https://github.com/mapbox/mapbox-gl-native/pull/16074) + - Fixed error for excessively overscaled lines [#16045](https://github.com/mapbox/mapbox-gl-native/pull/16045) + - Fixed signed to unsigned implicit conversion errors in symbol placement. [#16008](https://github.com/mapbox/mapbox-gl-native/pull/16008) + - Fixed error that would result when 0.0 was passed into `text-size` [#16080](https://github.com/mapbox/mapbox-gl-native/pull/16080) ## 8.6.0-beta.1 - December 6, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.2...android-v8.6.0-beta.1) since [Mapbox Maps SDK for Android v8.6.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.2): +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0-alpha.2...android-v8.6.0-beta.1) since [Mapbox Maps SDK for Android v8.6.0-alpha.2](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0-alpha.2): ### Features -- Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) -- Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87) -- Bulk conversion of geographic coordinates to screen coordinate using reusable double arrays. [#91](https://github.com/mapbox/mapbox-gl-native-android/pull/91) + - Introduce OfflineManager.runPackDatabaseAutomatically(boolean) and remove the redundant OfflineRegion.deleteAndSkipPackDatabase() method [#78](https://github.com/mapbox/mapbox-gl-native-android/pull/78) + - Expose getter for the view used for rendering OpenGL content on [#87](https://github.com/mapbox/mapbox-gl-native-android/pull/87) + - Bulk conversion of geographic coordinates to screen coordinate using reusable double arrays. [#91](https://github.com/mapbox/mapbox-gl-native-android/pull/91) ### Performance improvements -- Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) + - Make network requests for expired resources lower priority than requests for new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) ### Bug fixes -- Fixed a runtime crash of Proguard optimized builds on < API 21 devices by including the missing SoLoader flag. [#71](https://github.com/mapbox/mapbox-gl-native-android/pull/71) -- Fixed a bug where location camera mode transition callback would not get notified if the requested mode was already set. [#80](https://github.com/mapbox/mapbox-gl-native-android/pull/80) -- Fixed a bug where location tilt/zoom while tracking callback would not get notified if the request was ignored. [#83](https://github.com/mapbox/mapbox-gl-native-android/pull/83) -- Use -Oz to reduce binary size [#15984](https://github.com/mapbox/mapbox-gl-native/pull/15984) -- Use icf=all compile flag to reduce binary size [#15987](https://github.com/mapbox/mapbox-gl-native/pull/15987) + - Fixed a runtime crash of Proguard optimized builds on < API 21 devices by including the missing SoLoader flag. [#71](https://github.com/mapbox/mapbox-gl-native-android/pull/71) + - Fixed a bug where location camera mode transition callback would not get notified if the requested mode was already set. [#80](https://github.com/mapbox/mapbox-gl-native-android/pull/80) + - Fixed a bug where location tilt/zoom while tracking callback would not get notified if the request was ignored. [#83](https://github.com/mapbox/mapbox-gl-native-android/pull/83) + - Use -Oz to reduce binary size [#15984](https://github.com/mapbox/mapbox-gl-native/pull/15984) + - Use icf=all compile flag to reduce binary size [#15987](https://github.com/mapbox/mapbox-gl-native/pull/15987) ## 8.6.0-alpha.2 - November 22, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.6.0-alpha.1): +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0-alpha.1...android-v8.6.0-alpha.2) since [Mapbox Maps SDK for Android v8.6.0-alpha.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0-alpha.1): ### Bug fixes - Synchronise LibaryLoader#loadLibrary to avoid race conditions resulting in UnsatisfiedLinkError [#58](https://github.com/mapbox/mapbox-gl-native-android/pull/58) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 1ac3e9e9c..d148908cf 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 1ac3e9e9c2a8bfc731e3bba978a28562c3f083e5 +Subproject commit d148908cf14c78505ebc924a1783bbd44de0e399 From de4e18b7f5025be3289fecd0ffb532416bde7f2a Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 8 Jan 2020 19:52:21 +0200 Subject: [PATCH 053/185] [ci] Archive debuggable objects as a single tar file in android-release job. (#134) --- .circleci/config.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 068e1dba1..4d8d3f482 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -326,23 +326,14 @@ jobs: command: make android-javadoc - save-dependencies: { gradle: true } - run: - name: gzip debugable .so files + name: archive debugable objects command: | - gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so && \ - gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so && \ - gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so && \ - gzip MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so + cd MapboxGLAndroidSDK/build/intermediates/cmake/release && tar -zcvf debuggable-objects.tar.gz obj && cd - - store_artifacts: path: MapboxGLAndroidSDKTestApp/build/outputs/apk/release destination: . - store_artifacts: - path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so.gz - - store_artifacts: - path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so.gz - - store_artifacts: - path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so.gz - - store_artifacts: - path: MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so.gz + path: MapboxGLAndroidSDK/build/intermediates/cmake/release/debuggable-objects.tar.gz - deploy: name: Publish to Bintray command: | From 509eeb89d30f87ef3ce7fa3682895e76e061458c Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 9 Jan 2020 14:40:17 +0100 Subject: [PATCH 054/185] [filesource] - update javadoc of setResourceCachePath (#135) --- .../main/java/com/mapbox/mapboxsdk/storage/FileSource.java | 4 ++-- MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index 8efd8d219..4d3fc3056 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -261,10 +261,10 @@ public class FileSource { /** * Changes the path of the resources cache database. - * Note that the external storage setting needs to be activated in the manifest. *

    * The callback reference is strongly kept throughout the process, * so it needs to be wrapped in a weak reference or released on the client side if necessary. + *

    * * @param context the context of the path * @param path the new database path @@ -280,10 +280,10 @@ public class FileSource { /** * Changes the path of the resources cache database. - * Note that the external storage setting needs to be activated in the manifest. *

    * The callback reference is strongly kept throughout the process, * so it needs to be wrapped in a weak reference or released on the client side if necessary. + *

    * * @param path the new database path * @param callback the callback to obtain the result diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index e29f6e74c..ee239a6d5 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1026,6 +1026,7 @@ android:value="pk.eyJ1IjoiYmxzdGFnaW5nIiwiYSI6ImNpdDF3OHpoaTAwMDcyeXA5Y3Z0Nmk2dzEifQ.0IfB7v5Qbm2MGVYt8Kb8fg" /> + From ca64ba520d72fd4f27ede750fb2dc9cb31e98092 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 9 Jan 2020 15:23:54 +0100 Subject: [PATCH 055/185] [deps] update mapbox-gestures-android to 0.6.0 and mapbox-java to 5.0.0 (#136) --- gradle/dependencies.gradle | 4 ++-- vendor/mapbox-gestures-android | 2 +- vendor/mapbox-java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 9d87409e9..0531c0ade 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -7,10 +7,10 @@ ext { ] versions = [ - mapboxServices : '4.9.0', + mapboxServices : '5.0.0', mapboxTelemetry : '4.5.1', mapboxCore : '1.3.0', - mapboxGestures : '0.5.1', + mapboxGestures : '0.6.0', mapboxAccounts : '0.2.0', appCompat : '1.0.0', constraintLayout: '1.1.3', diff --git a/vendor/mapbox-gestures-android b/vendor/mapbox-gestures-android index ae08de82c..ac3a194ea 160000 --- a/vendor/mapbox-gestures-android +++ b/vendor/mapbox-gestures-android @@ -1 +1 @@ -Subproject commit ae08de82ca178dca7f005dfc8056554cf77124ad +Subproject commit ac3a194eadd669d1473d49da9359722182a06785 diff --git a/vendor/mapbox-java b/vendor/mapbox-java index f590c74df..4fcda5bcb 160000 --- a/vendor/mapbox-java +++ b/vendor/mapbox-java @@ -1 +1 @@ -Subproject commit f590c74df50f1b1e8edf2a4cf4908701b85861f2 +Subproject commit 4fcda5bcb69b166fb116119a511aa9289bb77954 From 5284d51cad1816a4f92019e51a6ce90b5fb0db6b Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Thu, 9 Jan 2020 07:51:52 -0800 Subject: [PATCH 056/185] adjusted snapshot section of readme (#125) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd284d06c..6b3fb758e 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ More information about building and distributing this project in [DISTRIBUTE.md] #### Using the SDK snapshot -Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example, the `7.3.0-SNAPSHOT` would look like: +Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number: ```java // Mapbox SDK dependency From 6470565b663d85c6a2b32b799eaecf344901153b Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 9 Jan 2020 17:22:54 +0100 Subject: [PATCH 057/185] [docs] update changelog for v8.6.1 patch release (#137) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d924fe2f1..e8e3454b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 8.6.1 - January 9, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0...android-v8.6.1) since [Mapbox Maps SDK for Android v8.6.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0): +### Bug fixes + - Fixed native crash when using a GeoJsonSource when destructing the underlying GeoJSONVTData [#16106](https://github.com/mapbox/mapbox-gl-native/pull/16106). + ## 9.0.0-alpha.1 - January 8, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0...android-v9.0.0-alpha.1) since [Mapbox Maps SDK for Android v8.6.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0): ### Features From 7c9a8fc5561eb0234757134177a901623f5e0f07 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 9 Jan 2020 19:38:29 +0200 Subject: [PATCH 058/185] Add getVisibleCoordinateBounds method. (#109) * Update visible region constructor doc. * Add getVisibleCoordinateBounds method. * Fix LatLngBounds#contains method, update to use Map::latLngBoundsForCameraUnwrapped(const CameraOptions& camera) on native side. * Revert changes in LatLngBounds#contains. --- .../mapboxsdk/geometry/LatLngBounds.java | 2 +- .../mapboxsdk/geometry/VisibleRegion.java | 6 +- .../com/mapbox/mapboxsdk/maps/NativeMap.java | 2 + .../mapbox/mapboxsdk/maps/NativeMapView.java | 10 ++ .../com/mapbox/mapboxsdk/maps/Projection.java | 13 ++ .../mapboxsdk/maps/VisibleRegionTest.kt | 118 ++++++++++++++++++ vendor/mapbox-gl-native | 2 +- 7 files changed, 148 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 516a9220e..d31fe187f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -373,7 +373,7 @@ public class LatLngBounds implements Parcelable { private boolean containsLongitude(final double longitude) { return (longitude <= this.longitudeEast) - && (longitude >= this.longitudeWest); + && (longitude >= this.longitudeWest); } /** diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java index 706bbcd65..09d0bea88 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java @@ -54,10 +54,10 @@ public class VisibleRegion implements Parcelable { /** * 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. + * @param farLeft A LatLng object containing the latitude and longitude of the far left corner of the region. + * @param farRight A LatLng object containing the latitude and longitude of the far right corner of the region. * @param nearLeft A LatLng object containing the latitude and longitude of the near left corner of the region. - * @param nearRight A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param nearRight A LatLng object containing the latitude and longitude of the near right corner of the region. * @param latLngBounds The smallest bounding box that includes the visible region defined in this class. */ public VisibleRegion(LatLng farLeft, LatLng farRight, LatLng nearLeft, LatLng nearRight, LatLngBounds latLngBounds) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 806421d01..a601096a6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -195,6 +195,8 @@ interface NativeMap { void pixelsForLatLngs(@NonNull double[] input, @NonNull double[] output); + void getVisibleCoordinateBounds(@NonNull double[] output); + LatLng latLngForPixel(@NonNull PointF pixel); void latLngsForPixels(@NonNull double[] input, @NonNull double[] output); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 66b0538d6..dfeac768c 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -650,6 +650,13 @@ final class NativeMapView implements NativeMap { } } + @Override + public void getVisibleCoordinateBounds(@NonNull double[] output) { + if (!checkState("getVisibleCoordinateBounds")) { + nativeGetVisibleCoordinateBounds(output); + } + } + @Override public LatLng latLngForPixel(@NonNull PointF pixel) { if (checkState("latLngForPixel")) { @@ -1282,6 +1289,9 @@ final class NativeMapView implements NativeMap { @Keep private native void nativePixelsForLatLngs(double[] input, double[] output, float pixelRatio); + @Keep + private native void nativeGetVisibleCoordinateBounds(double[] output); + @NonNull @Keep private native LatLng nativeLatLngForPixel(float x, float y); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index 66124edee..7de543302 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -203,6 +203,19 @@ public class Projection { LatLngBounds.from(north, east, south, west)); } + /** + * Gets a projection of the viewing frustum for converting between screen coordinates and + * geo-latitude/longitude coordinate bounds. + *

    + * This method ignores the content padding. + * + * @param bounds an array of 4 output values representing bounds(in the order of latNorth, + * lonEast, latSouth, lonWest). + */ + public void getVisibleCoordinateBounds(@NonNull double[] bounds) { + nativeMapView.getVisibleCoordinateBounds(bounds); + } + /** * Takes two {@link Point}s and finds the geographic bearing between them. * diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt index 245d43378..924dd9986 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt @@ -4,6 +4,7 @@ import android.graphics.PointF import androidx.test.espresso.UiController import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.geometry.LatLngBounds import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke import com.mapbox.mapboxsdk.testapp.activity.BaseTest import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity @@ -394,6 +395,123 @@ class VisibleRegionTest : BaseTest() { } } + @Test + fun visibleRegionWithBoundsEqualTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0)) + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(0f, 0f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f), + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()), + mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()), + mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f) + ) + val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapboxMap.projection.getVisibleCoordinateBounds(bounds) + val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3]) + val visibleRegion = mapboxMap.projection.visibleRegion + assertTrue(latLngBounds == visibleRegion.latLngBounds) + assertTrue(latLngs.all { latLngBounds.contains(it) }) + } + } + + @Test + fun visibleRegionBoundsOverDatelineTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(0f, 0f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f) + .also { it.longitude += 360 }, + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f) + .also { it.longitude += 360 }, + mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()) + .also { it.longitude += 360 }, + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()), + mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()), + mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f) + ) + val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapboxMap.projection.getVisibleCoordinateBounds(bounds) + val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3]) + assertTrue(latLngs.all { latLngBounds.contains(it) }) + } + } + + @Test + fun visibleRegionBoundsOverDatelineLatitudeZeroTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) + val shift = mapboxMap.getLatLngFromScreenCoords(0f, 0f) + mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(0.0, 180.0 - shift.longitude))) + + val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapboxMap.projection.getVisibleCoordinateBounds(bounds) + val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3]) + val visibleRegion = mapboxMap.projection.visibleRegion + assertTrue(latLngBounds == visibleRegion.latLngBounds) + } + } + + @Test + fun visibleRotatedRegionBoundEqualTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0)) + val d = Math.min(mapboxMap.width, mapboxMap.height) / 4 + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + ) + + for (bearing in 45 until 360 step 45) { + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())) + val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapboxMap.projection.getVisibleCoordinateBounds(bounds) + val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3]) + val visibleRegion = mapboxMap.projection.visibleRegion + assertTrue(latLngBounds == visibleRegion.latLngBounds) + assertTrue(latLngs.all { latLngBounds.contains(it) }) + } + } + } + + @Test + fun visibleRotatedRegionBoundsOverDatelineTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 179.0), 8.0)) + val d = Math.min(mapboxMap.width, mapboxMap.height) / 4 + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + ) + + for (bearing in 45 until 360 step 45) { + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())) + val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0) + mapboxMap.projection.getVisibleCoordinateBounds(bounds) + val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3]) + assertTrue(latLngs.all { latLngBounds.contains(it) }) + } + } + } + private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng { return this.projection.fromScreenLocation(PointF(x, y)) } diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index d148908cf..236afc039 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit d148908cf14c78505ebc924a1783bbd44de0e399 +Subproject commit 236afc03958cc729b3b8121a1c5a72660f0e9fa2 From ef4c225290572e9b171e77e8386da48234f55533 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Wed, 15 Jan 2020 12:36:25 +0200 Subject: [PATCH 059/185] AccountManager: write user ID synchronously, keep it in memory. (#145) * AccountManager: write user ID synchronously, keep it in memory. * Unit tests: run AccountsManagerTest with Robolectric. --- .../com/mapbox/mapboxsdk/AccountsManager.java | 45 ++++++++++--------- .../mapbox/mapboxsdk/AccountsManagerTest.java | 3 ++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java index 968c33926..3bcb2a1e1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java @@ -38,6 +38,7 @@ class AccountsManager { private static final String PREFERENCE_TIMESTAMP = "com.mapbox.mapboxsdk.accounts.timestamp"; private SharedPreferences sharedPreferences; + private String userId; private String skuToken; private long timestamp; private boolean isManaged; @@ -57,8 +58,7 @@ class AccountsManager { private void initialize() { retrieveSkuTokenAndTimestamp(); if (isManaged) { - String userId = validateUserId(); - validateRotation(userId); + validateRotation(); } } @@ -92,22 +92,9 @@ class AccountsManager { timestamp = sharedPreferences.getLong(PREFERENCE_TIMESTAMP, 0L); } - private String validateUserId() { - SharedPreferences sharedPreferences = getSharedPreferences(); - String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); - if (TextUtils.isEmpty(userId)) { - userId = generateUserId(); - SharedPreferences.Editor editor = getSharedPreferences().edit(); - editor.putString(PREFERENCE_USER_ID, userId); - editor.apply(); - } - - return userId; - } - - private void validateRotation(String userId) { + private void validateRotation() { if (TextUtils.isEmpty(skuToken) || timestamp == 0L) { - skuToken = generateSkuToken(userId); + skuToken = generateSkuToken(getUserId()); timestamp = persistRotation(skuToken); } } @@ -115,9 +102,7 @@ class AccountsManager { String getSkuToken() { if (isManaged) { if (isExpired()) { - SharedPreferences sharedPreferences = getSharedPreferences(); - String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); - skuToken = generateSkuToken(userId); + skuToken = generateSkuToken(getUserId()); timestamp = persistRotation(skuToken); } } else { @@ -158,6 +143,26 @@ class AccountsManager { return System.currentTimeMillis(); } + private synchronized String getUserId() { + if (!TextUtils.isEmpty(userId)) { + return userId; + } + + SharedPreferences sharedPreferences = getSharedPreferences(); + userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); + + if (TextUtils.isEmpty(userId)) { + userId = generateUserId(); + SharedPreferences.Editor editor = getSharedPreferences().edit(); + editor.putString(PREFERENCE_USER_ID, userId); + if (!editor.commit()) { + Logger.e(TAG, "Failed to save user id."); + } + } + + return userId; + } + @NonNull private String generateUserId() { return MapboxAccounts.obtainEndUserId(); diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java index 5ce71ceac..6ff9a377c 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java @@ -4,6 +4,8 @@ import android.content.SharedPreferences; import android.text.format.DateUtils; import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_PREFERENCE_SKU_TOKEN; import static org.junit.Assert.assertEquals; @@ -13,6 +15,7 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@RunWith(RobolectricTestRunner.class) public class AccountsManagerTest { @Test public void testIsExpired() { From 369c41ad67653cfdd7641ea3264afc3e363abb06 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 15 Jan 2020 10:38:36 +0100 Subject: [PATCH 060/185] [map] expose pixel ratio as public API on MapView --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapView.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 094d05f4d..e6cdd3021 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -542,7 +542,13 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } } - private float getPixelRatio() { + /** + * Returns the map pixel ratio, by default it returns the device pixel ratio. + * Can be overwritten using {@link MapboxMapOptions#pixelRatio(float)}. + * + * @return the current map pixel ratio + */ + public float getPixelRatio() { // check is user defined his own pixel ratio value float pixelRatio = mapboxMapOptions.getPixelRatio(); if (pixelRatio == 0) { From c275ad2e6d7c59b94d24179195cfbd423449c506 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 17 Jan 2020 09:56:47 +0100 Subject: [PATCH 061/185] [sku] append sku token to offline download requests --- .../mapbox/mapboxsdk/http/HttpRequestUrl.java | 16 +++++++++------- .../mapboxsdk/module/http/HttpRequestUrlTest.kt | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java index 2a85bdee8..c5e372772 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java @@ -6,6 +6,8 @@ import com.mapbox.mapboxsdk.Mapbox; public class HttpRequestUrl { + private static final StringBuilder requestBuilder = new StringBuilder(); + private HttpRequestUrl() { } @@ -22,20 +24,20 @@ public class HttpRequestUrl { * @return the adapted resource url */ public static String buildResourceUrl(@NonNull String host, String resourceUrl, int querySize, boolean offline) { + requestBuilder.setLength(0); // clear previous builder + requestBuilder.append(resourceUrl); if (isValidMapboxEndpoint(host)) { if (querySize == 0) { - resourceUrl = resourceUrl + "?"; + requestBuilder.append("?"); } else { - resourceUrl = resourceUrl + "&"; + requestBuilder.append("&"); } - // Only add SKU token to requests not tagged as "offline" usage. if (offline) { - resourceUrl = resourceUrl + "offline=true"; - } else { - resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken(); + requestBuilder.append("offline=true&"); } + requestBuilder.append("sku=").append(Mapbox.getSkuToken()); } - return resourceUrl; + return requestBuilder.toString(); } /** diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt index 5db7b0b0f..a50870f23 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt @@ -20,14 +20,14 @@ class HttpRequestUrlTest { @Test fun testOfflineFlagMapboxCom() { - val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true" + val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true&sku=foobar" val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true) assertEquals(expected, actual) } @Test fun testOfflineFlagMapboxCn() { - val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true" + val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true&sku=foobar" val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true) assertEquals(expected, actual) } From c7af6c9f15f0a9397a8de72e8abe09549c7cf372 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Tue, 21 Jan 2020 09:20:43 -0500 Subject: [PATCH 062/185] add stale bot settings file (#150) --- .github/stale.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..6f5511017 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,28 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +exemptProjects: true +exemptMilestones: true + +staleLabel: archived + +limitPerRun: 1 + +# SEMVER-MAJOR - @tobrun +exemptLabels: + - SEMVER-MAJOR + +pulls: + daysUntilStale: 60 + daysUntilClose: -1 + markComment: false + closeComment: > + This pull request has been automatically detected as stale because it has not had + recent activity and will be archived. Thank you for your contributions. + +issues: + daysUntilStale: 180 + daysUntilClose: -1 + markComment: false + closeComment: > + This issue has been automatically detected as stale because it has not had + recent activity and will be archived. Thank you for your contributions. From 37df74d7467373821e87c41d656d61230b8445c9 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 22 Jan 2020 11:04:53 +0100 Subject: [PATCH 063/185] [docs] update changelog for v8.6.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e3454b6..aa3dcb1bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 8.6.2 - January 22, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.1...android-v8.6.2) since [Mapbox Maps SDK for Android v8.6.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.1): +### Bug fixes + - Append sku token to offline download requests [#148](https://github.com/mapbox/mapbox-gl-native-android/pull/148) + - Write user id synchronously to avoid null entries as part of the URL [#145](https://github.com/mapbox/mapbox-gl-native-android/pull/145) + ## 8.6.1 - January 9, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0...android-v8.6.1) since [Mapbox Maps SDK for Android v8.6.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0): ### Bug fixes From c4d4f5d10a8666fe162e02ed5b65fe4ec3dd1eff Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 22 Jan 2020 20:11:03 +0100 Subject: [PATCH 064/185] [android] - expose UiSettings configuration for disabling horizontall scroll gestures --- .../mapboxsdk/constants/MapboxConstants.java | 6 ++++ .../mapboxsdk/maps/MapGestureDetector.java | 21 +++++++++-- .../mapboxsdk/maps/MapboxMapOptions.java | 36 +++++++++++++++++-- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 30 ++++++++++++++++ .../src/main/res-public/values/public.xml | 1 + .../src/main/res/values/attrs.xml | 1 + .../mapboxsdk/maps/MapboxMapOptionsTest.java | 7 ++++ .../mapbox/mapboxsdk/maps/UiSettingsTest.java | 13 +++++++ .../camera/GestureDetectorActivity.java | 3 ++ .../src/main/res/menu/menu_gestures.xml | 3 ++ 10 files changed, 116 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 6156b3af7..42aa9206e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -73,6 +73,11 @@ public class MapboxConstants { */ public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; + /** + * Vertical angle threshold for a horizontal disabled fling gesture + */ + public static final long ANGLE_THRESHOLD_IGNORE_VERTICAL_FLING = 75; + /** * Value by which the default rotation threshold will be increased when scaling * @@ -195,6 +200,7 @@ public class MapboxConstants { public static final String STATE_CAMERA_POSITION = "mapbox_cameraPosition"; public static final String STATE_ZOOM_ENABLED = "mapbox_zoomEnabled"; public static final String STATE_SCROLL_ENABLED = "mapbox_scrollEnabled"; + public static final String STATE_HORIZONAL_SCROLL_ENABLED = "mapbox_horizontalScrollEnabled"; public static final String STATE_ROTATE_ENABLED = "mapbox_rotateEnabled"; public static final String STATE_TILT_ENABLED = "mapbox_tiltEnabled"; public static final String STATE_DOUBLE_TAP_ENABLED = "mapbox_doubleTapEnabled"; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 461db80c6..3deed84cf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -7,8 +7,10 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; import android.os.Handler; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import android.view.InputDevice; import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; @@ -423,9 +425,6 @@ final class MapGestureDetector { return false; } - transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - // tilt results in a bigger translation, limiting input for #5281 double tilt = transform.getTilt(); double tiltFactor = 1.5 + ((tilt != 0) ? (tilt / 10) : 0); @@ -434,6 +433,17 @@ final class MapGestureDetector { // calculate animation time based on displacement long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE); + if (!uiSettings.isHorizontalScrollGesturesEnabled()) { + // determine if angle of fling is valid for performing a vertical fling + double angle = Math.abs(Math.toDegrees(Math.atan(offsetX / offsetY))); + if (angle > MapboxConstants.ANGLE_THRESHOLD_IGNORE_VERTICAL_FLING) { + return false; + } + offsetX = 0.0; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); // update transformation transform.moveBy(offsetX, offsetY, animationTime); @@ -476,6 +486,11 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + // Disable scrolling horizontal if not allowed + if (!uiSettings.isHorizontalScrollGesturesEnabled()) { + distanceX = 0; + } + // Scroll the map transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 8867d0768..3a2040095 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -7,12 +7,14 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; + import androidx.annotation.ColorInt; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.content.res.ResourcesCompat; + import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; @@ -65,6 +67,7 @@ public class MapboxMapOptions implements Parcelable { private boolean rotateGesturesEnabled = true; private boolean scrollGesturesEnabled = true; + private boolean horizontalScrollGesturesEnabled = true; private boolean tiltGesturesEnabled = true; private boolean zoomGesturesEnabled = true; private boolean doubleTapGesturesEnabled = true; @@ -127,6 +130,7 @@ public class MapboxMapOptions implements Parcelable { rotateGesturesEnabled = in.readByte() != 0; scrollGesturesEnabled = in.readByte() != 0; + horizontalScrollGesturesEnabled = in.readByte() != 0; tiltGesturesEnabled = in.readByte() != 0; zoomGesturesEnabled = in.readByte() != 0; doubleTapGesturesEnabled = in.readByte() != 0; @@ -191,6 +195,8 @@ public class MapboxMapOptions implements Parcelable { typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiZoomGestures, true)); mapboxMapOptions.scrollGesturesEnabled( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiScrollGestures, true)); + mapboxMapOptions.horizontalScrollGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiHorizontalScrollGestures, true)); mapboxMapOptions.rotateGesturesEnabled( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiRotateGestures, true)); mapboxMapOptions.tiltGesturesEnabled( @@ -261,7 +267,7 @@ public class MapboxMapOptions implements Parcelable { mapboxMapOptions.setPrefetchesTiles( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); mapboxMapOptions.setPrefetchZoomDelta( - typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); + typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); mapboxMapOptions.renderSurfaceOnTop( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false)); @@ -546,6 +552,18 @@ public class MapboxMapOptions implements Parcelable { return this; } + /** + * Specifies if the horizontal scroll gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions horizontalScrollGesturesEnabled(boolean enabled) { + horizontalScrollGesturesEnabled = enabled; + return this; + } + /** * Specifies if the tilt gesture is enabled for a map view. * @@ -652,7 +670,7 @@ public class MapboxMapOptions implements Parcelable { * tile at the (current_zoom_level - delta) is rendered as soon as possible at the * expense of a little bandwidth. * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) - * Setting zoom delta to 0 will disable pre-fetching. + * Setting zoom delta to 0 will disable pre-fetching. * Default zoom delta is 4. * * @param delta zoom delta @@ -926,6 +944,15 @@ public class MapboxMapOptions implements Parcelable { return scrollGesturesEnabled; } + /** + * Get the current configured horizontal scroll gesture state for a map view. + * + * @return True indicates horizontal scroll gesture is enabled + */ + public boolean getHorizontalScrollGesturesEnabled() { + return horizontalScrollGesturesEnabled; + } + /** * Get the current configured tilt gesture state for a map view. * @@ -1108,6 +1135,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (rotateGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (scrollGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (horizontalScrollGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (tiltGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); @@ -1182,6 +1210,9 @@ public class MapboxMapOptions implements Parcelable { if (scrollGesturesEnabled != options.scrollGesturesEnabled) { return false; } + if (horizontalScrollGesturesEnabled != options.horizontalScrollGesturesEnabled) { + return false; + } if (tiltGesturesEnabled != options.tiltGesturesEnabled) { return false; } @@ -1263,6 +1294,7 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (rotateGesturesEnabled ? 1 : 0); result = 31 * result + (scrollGesturesEnabled ? 1 : 0); + result = 31 * result + (horizontalScrollGesturesEnabled ? 1 : 0); result = 31 * result + (tiltGesturesEnabled ? 1 : 0); result = 31 * result + (zoomGesturesEnabled ? 1 : 0); result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index f7bd28eb4..8fb791463 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -58,6 +58,8 @@ public final class UiSettings { private boolean scrollGesturesEnabled = true; + private boolean horizontalScrollGesturesEnabled = true; + private boolean doubleTapGesturesEnabled = true; private boolean quickZoomGesturesEnabled = true; @@ -117,6 +119,7 @@ public final class UiSettings { private void initialiseGestures(MapboxMapOptions options) { setZoomGesturesEnabled(options.getZoomGesturesEnabled()); setScrollGesturesEnabled(options.getScrollGesturesEnabled()); + setHorizontalScrollGesturesEnabled(options.getHorizontalScrollGesturesEnabled()); setRotateGesturesEnabled(options.getRotateGesturesEnabled()); setTiltGesturesEnabled(options.getTiltGesturesEnabled()); setDoubleTapGesturesEnabled(options.getDoubleTapGesturesEnabled()); @@ -124,6 +127,7 @@ public final class UiSettings { } private void saveGestures(Bundle outState) { + outState.putBoolean(MapboxConstants.STATE_HORIZONAL_SCROLL_ENABLED, isHorizontalScrollGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, isZoomGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, isScrollGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, isRotateGesturesEnabled()); @@ -140,6 +144,7 @@ public final class UiSettings { } private void restoreGestures(Bundle savedInstanceState) { + setHorizontalScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_HORIZONAL_SCROLL_ENABLED)); setZoomGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED)); setScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED)); setRotateGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED)); @@ -849,6 +854,31 @@ public final class UiSettings { return scrollGesturesEnabled; } + /** + *

    + * Changes whether the user may scroll horizontally around the map. + *

    + *

    + * This setting controls only user interactions with the map. If you set the value to false, + * you may still change the map location programmatically. + *

    + * The default value is true. + * + * @param horizontalScrollGesturesEnabled If true, scrolling horizontally is enabled. + */ + public void setHorizontalScrollGesturesEnabled(boolean horizontalScrollGesturesEnabled) { + this.horizontalScrollGesturesEnabled = horizontalScrollGesturesEnabled; + } + + /** + * Returns whether the user may scroll horizontally around the map. + * + * @return If true, scrolling horizontally is enabled. + */ + public boolean isHorizontalScrollGesturesEnabled() { + return horizontalScrollGesturesEnabled; + } + /** * Returns whether scale velocity animation should execute after users finishes a gesture. * diff --git a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 36071cc2a..83c25432d 100644 --- a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -31,6 +31,7 @@ + diff --git a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index 137f72f8d..a38f6e9fb 100644 --- a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -26,6 +26,7 @@ + diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index c46e6e319..b72b34210 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -135,6 +135,13 @@ public class MapboxMapOptionsTest { assertFalse(new MapboxMapOptions().scrollGesturesEnabled(false).getScrollGesturesEnabled()); } + @Test + public void testHorizontalScrollGesturesEnabled() { + assertTrue(new MapboxMapOptions().getHorizontalScrollGesturesEnabled()); + assertTrue(new MapboxMapOptions().horizontalScrollGesturesEnabled(true).getHorizontalScrollGesturesEnabled()); + assertFalse(new MapboxMapOptions().horizontalScrollGesturesEnabled(false).getHorizontalScrollGesturesEnabled()); + } + @Test public void testZoomGesturesEnabled() { assertTrue(new MapboxMapOptions().getZoomGesturesEnabled()); diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java index a84e93cd7..df6df7afd 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java @@ -282,6 +282,19 @@ public class UiSettingsTest { assertEquals("Scroll gesture should be disabled", false, uiSettings.isScrollGesturesEnabled()); } + + @Test + public void testHorizontalScrollGesturesEnabled() { + uiSettings.setHorizontalScrollGesturesEnabled(true); + assertEquals("Scroll gesture should be enabled", true, uiSettings.isHorizontalScrollGesturesEnabled()); + } + + @Test + public void testHorizontalScrollGesturesDisabled() { + uiSettings.setHorizontalScrollGesturesEnabled(false); + assertEquals("Scroll gesture should be disabled", false, uiSettings.isHorizontalScrollGesturesEnabled()); + } + @Test public void testScrollGestureChangeAllowed() { uiSettings.setScrollGesturesEnabled(false); diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java index 2efc95fa4..def33190e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java @@ -259,6 +259,9 @@ public class GestureDetectorActivity extends AppCompatActivity { case R.id.menu_gesture_quick_zoom: uiSettings.setQuickZoomGesturesEnabled(!uiSettings.isQuickZoomGesturesEnabled()); return true; + case R.id.menu_gesture_scroll_horizontal: + uiSettings.setHorizontalScrollGesturesEnabled(!uiSettings.isHorizontalScrollGesturesEnabled()); + return true; } return super.onOptionsItemSelected(item); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_gestures.xml b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_gestures.xml index 12f3b0576..510f965ff 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_gestures.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_gestures.xml @@ -18,6 +18,9 @@ + From 4defb4769d55717b8671b3527d55aec4e0380f37 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 24 Jan 2020 17:11:03 +0100 Subject: [PATCH 065/185] [docs] update changelog for v9.0.0-beta.1 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa3dcb1bc..536e36c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 9.0.0-beta.1 - January 24, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-alpha.1...android-v9.0.0-beta.1) since [Mapbox Maps SDK for Android v9.0.0-alpha.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-alpha.1): +### Features + - Introduce a gesture setting to disable horizontal scrolling [#156](https://github.com/mapbox/mapbox-gl-native-android/pull/156) + - Introduce pixel ratio as public API on MapView [#146](https://github.com/mapbox/mapbox-gl-native-android/pull/146) + - Introduce getVisibleCoordinateBounds method that allows for object reuse [#109](https://github.com/mapbox/mapbox-gl-native-android/pull/109) + - Update Mapbox dependencies to AndroidX [#136](https://github.com/mapbox/mapbox-gl-native-android/pull/136) + ## 8.6.2 - January 22, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.1...android-v8.6.2) since [Mapbox Maps SDK for Android v8.6.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.1): ### Bug fixes From a5477963ae712133ef9c7fda0375015e4cdeba76 Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 22 Jan 2020 13:24:14 +0100 Subject: [PATCH 066/185] [deps] update accounts library to 0.7.0 to include androidX optimised library --- gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 0531c0ade..b9900d124 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -11,7 +11,7 @@ ext { mapboxTelemetry : '4.5.1', mapboxCore : '1.3.0', mapboxGestures : '0.6.0', - mapboxAccounts : '0.2.0', + mapboxAccounts : '0.7.0', appCompat : '1.0.0', constraintLayout: '1.1.3', recyclerView : '1.1.0', From aea886e74116c9210e32d8cc274f2e6e5e65b191 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 29 Jan 2020 15:03:42 +0200 Subject: [PATCH 067/185] Lazy load view components in MapView. (#141) * Lazy load view components in MapView. * Fix failing tests. * Fix style. * Lazy inflating view components. * Remove debug logging. * Fix android ui tests. --- .../com/mapbox/mapboxsdk/maps/MapView.java | 108 ++++++---- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 188 ++++++++++++++---- .../res/layout/mapbox_mapview_internal.xml | 27 --- .../mapbox/mapboxsdk/maps/UiSettingsTest.java | 62 ++++-- .../testapp/maps/widgets/AttributionTest.java | 14 +- .../testapp/maps/widgets/CompassViewTest.java | 13 +- .../testapp/maps/widgets/LogoTest.java | 15 +- 7 files changed, 281 insertions(+), 146 deletions(-) delete mode 100644 MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index e6cdd3021..553a6a5f6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -5,20 +5,20 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.UiThread; -import androidx.collection.LongSparseArray; import android.util.AttributeSet; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.TextureView; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.collection.LongSparseArray; + import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.mapboxsdk.MapStrictMode; import com.mapbox.mapboxsdk.Mapbox; @@ -73,14 +73,20 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private View renderView; private AttributionClickListener attributionClickListener; - private MapboxMapOptions mapboxMapOptions; + MapboxMapOptions mapboxMapOptions; private MapRenderer mapRenderer; private boolean destroyed; + @Nullable private CompassView compassView; private PointF focalPoint; - private ImageView attrView; - private ImageView logoView; + + // callback for focal point invalidation + private final FocalPointInvalidator focalInvalidator = new FocalPointInvalidator(); + // callback for registering touch listeners + private final GesturesManagerInteractionListener registerTouchListener = new GesturesManagerInteractionListener(); + // callback for camera change events + private final CameraChangeDispatcher cameraDispatcher = new CameraChangeDispatcher(); @Nullable private MapGestureDetector mapGestureDetector; @@ -131,14 +137,6 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { mapboxMapOptions = options; - // inflate view - View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this); - compassView = view.findViewById(R.id.compassView); - attrView = view.findViewById(R.id.attributionView); - attrView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_info_bg_selector)); - logoView = view.findViewById(R.id.logoView); - logoView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_logo_icon)); - // add accessibility support setContentDescription(context.getString(R.string.mapbox_mapActionDescription)); setWillNotDraw(false); @@ -149,18 +147,11 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { Context context = getContext(); // callback for focal point invalidation - final FocalPointInvalidator focalInvalidator = new FocalPointInvalidator(); focalInvalidator.addListener(createFocalPointChangeListener()); - // callback for registering touch listeners - GesturesManagerInteractionListener registerTouchListener = new GesturesManagerInteractionListener(); - - // callback for camera change events - final CameraChangeDispatcher cameraDispatcher = new CameraChangeDispatcher(); - // setup components for MapboxMap creation Projection proj = new Projection(nativeMapView, this); - UiSettings uiSettings = new UiSettings(proj, focalInvalidator, compassView, attrView, logoView, getPixelRatio()); + UiSettings uiSettings = new UiSettings(proj, focalInvalidator, getPixelRatio(), this); LongSparseArray annotationsArray = new LongSparseArray<>(); IconManager iconManager = new IconManager(nativeMapView); Annotations annotations = new AnnotationContainer(nativeMapView, annotationsArray); @@ -169,30 +160,23 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray); ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray); AnnotationManager annotationManager = new AnnotationManager(this, annotationsArray, iconManager, - annotations, markers, polygons, polylines, shapeAnnotations); + annotations, markers, polygons, polylines, shapeAnnotations); Transform transform = new Transform(this, nativeMapView, cameraDispatcher); // MapboxMap List developerAnimationListeners = new ArrayList<>(); mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, proj, registerTouchListener, cameraDispatcher, - developerAnimationListeners); + developerAnimationListeners); mapboxMap.injectAnnotationManager(annotationManager); // user input mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, - annotationManager, cameraDispatcher); + annotationManager, cameraDispatcher); mapKeyListener = new MapKeyListener(transform, uiSettings, mapGestureDetector); - // compass - compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraDispatcher)); - compassView.setOnClickListener(createCompassClickListener(cameraDispatcher)); - // LocationComponent mapboxMap.injectLocationComponent(new LocationComponent(mapboxMap, transform, developerAnimationListeners)); - // inject widgets with MapboxMap - attrView.setOnClickListener(attributionClickListener = new AttributionClickListener(context, mapboxMap)); - // Ensure this view is interactable setClickable(true); setLongClickable(true); @@ -213,6 +197,44 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { mapCallback.initialised(); } + protected CompassView initialiseCompassView() { + compassView = new CompassView(this.getContext()); + addView(compassView); + compassView.setTag("compassView"); + compassView.getLayoutParams().width = LayoutParams.WRAP_CONTENT; + compassView.getLayoutParams().height = LayoutParams.WRAP_CONTENT; + compassView.setContentDescription(getResources().getString(R.string.mapbox_compassContentDescription)); + compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraDispatcher)); + compassView.setOnClickListener(createCompassClickListener(cameraDispatcher)); + return compassView; + } + + protected ImageView initialiseAttributionView() { + ImageView attrView = new ImageView(this.getContext()); + addView(attrView); + attrView.setTag("attrView"); + attrView.getLayoutParams().width = LayoutParams.WRAP_CONTENT; + attrView.getLayoutParams().height = LayoutParams.WRAP_CONTENT; + attrView.setAdjustViewBounds(true); + attrView.setClickable(true); + attrView.setFocusable(true); + attrView.setContentDescription(getResources().getString(R.string.mapbox_attributionsIconContentDescription)); + attrView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_info_bg_selector)); + // inject widgets with MapboxMap + attrView.setOnClickListener(attributionClickListener = new AttributionClickListener(getContext(), mapboxMap)); + return attrView; + } + + protected ImageView initialiseLogoView() { + ImageView logoView = new ImageView(this.getContext()); + addView(logoView); + logoView.setTag("logoView"); + logoView.getLayoutParams().width = LayoutParams.WRAP_CONTENT; + logoView.getLayoutParams().height = LayoutParams.WRAP_CONTENT; + logoView.setImageDrawable(BitmapUtils.getDrawableFromRes(getContext(), R.drawable.mapbox_logo_icon)); + return logoView; + } + private FocalPointChangeListener createFocalPointChangeListener() { return new FocalPointChangeListener() { @Override @@ -223,7 +245,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } private MapboxMap.OnCompassAnimationListener createCompassAnimationListener(@NonNull final CameraChangeDispatcher - cameraChangeDispatcher) { + cameraChangeDispatcher) { return new MapboxMap.OnCompassAnimationListener() { @Override public void onCompassAnimation() { @@ -232,7 +254,9 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { @Override public void onCompassAnimationFinished() { - compassView.isAnimating(false); + if (compassView != null) { + compassView.isAnimating(false); + } cameraChangeDispatcher.onCameraIdle(); } }; @@ -289,7 +313,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { TextureView textureView = new TextureView(getContext()); boolean translucentSurface = options.getTranslucentTextureSurface(); mapRenderer = new TextureViewMapRenderer(getContext(), - textureView, localFontFamily, translucentSurface) { + textureView, localFontFamily, translucentSurface) { @Override protected void onSurfaceCreated(GL10 gl, EGLConfig config) { MapView.this.onSurfaceCreated(); @@ -316,7 +340,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { boolean crossSourceCollisions = mapboxMapOptions.getCrossSourceCollisions(); nativeMapView = new NativeMapView( - getContext(), getPixelRatio(), crossSourceCollisions, this, mapChangeReceiver, mapRenderer + getContext(), getPixelRatio(), crossSourceCollisions, this, mapChangeReceiver, mapRenderer ); } @@ -1225,7 +1249,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { public void setGesturesManager(AndroidGesturesManager gesturesManager, boolean attachDefaultListeners, boolean setDefaultMutuallyExclusives) { mapGestureDetector.setGesturesManager( - getContext(), gesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); + getContext(), gesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); } @Override @@ -1235,8 +1259,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } private class MapCallback implements OnDidFinishLoadingStyleListener, - OnDidFinishRenderingFrameListener, OnDidFinishLoadingMapListener, - OnCameraIsChangingListener, OnCameraDidChangeListener, OnDidFailLoadingMapListener { + OnDidFinishRenderingFrameListener, OnDidFinishLoadingMapListener, + OnCameraIsChangingListener, OnCameraDidChangeListener, OnDidFailLoadingMapListener { private final List onMapReadyCallbackList = new ArrayList<>(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 8fb791463..b59e944d5 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -7,17 +7,19 @@ import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + import androidx.annotation.ColorInt; import androidx.annotation.FloatRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.UiThread; +import androidx.annotation.VisibleForTesting; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.camera.CameraPosition; @@ -34,18 +36,23 @@ public final class UiSettings { @NonNull private final FocalPointChangeListener focalPointChangeListener; @NonNull - private final Projection projection; + private final MapView mapView; @NonNull - private final CompassView compassView; + private final Projection projection; + @VisibleForTesting + @Nullable + CompassView compassView; private final int[] compassMargins = new int[4]; - @NonNull - private final ImageView attributionsView; + @VisibleForTesting + @Nullable + ImageView attributionsView; private final int[] attributionsMargins = new int[4]; private AttributionDialogManager attributionDialogManager; - @NonNull - private final View logoView; + @VisibleForTesting + @Nullable + ImageView logoView; private final int[] logoMargins = new int[4]; private final float pixelRatio; @@ -79,23 +86,34 @@ public final class UiSettings { @Nullable private PointF userProvidedFocalPoint; + @VisibleForTesting + boolean isCompassInitialized = false; + @VisibleForTesting + boolean isAttributionInitialized = false; + @VisibleForTesting + boolean isLogoInitialized = false; + private double clockwiseBearing; + UiSettings(@NonNull Projection projection, @NonNull FocalPointChangeListener listener, - @NonNull CompassView compassView, @NonNull ImageView attributionsView, @NonNull View logoView, - float pixelRatio) { + float pixelRatio, MapView mapView) { this.projection = projection; this.focalPointChangeListener = listener; - this.compassView = compassView; - this.attributionsView = attributionsView; - this.logoView = logoView; this.pixelRatio = pixelRatio; + this.mapView = mapView; } void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) { Resources resources = context.getResources(); initialiseGestures(options); - initialiseCompass(options, resources); - initialiseLogo(options, resources); - initialiseAttribution(context, options); + if (options.getCompassEnabled()) { + initialiseCompass(options, resources); + } + if (options.getLogoEnabled()) { + initialiseLogo(options, resources); + } + if (options.getAttributionEnabled()) { + initialiseAttribution(context, options); + } } void onSaveInstanceState(@NonNull Bundle outState) { @@ -163,6 +181,8 @@ public final class UiSettings { } private void initialiseCompass(MapboxMapOptions options, @NonNull Resources resources) { + isCompassInitialized = true; + compassView = mapView.initialiseCompassView(); setCompassEnabled(options.getCompassEnabled()); setCompassGravity(options.getCompassGravity()); int[] compassMargins = options.getCompassMargins(); @@ -192,6 +212,11 @@ public final class UiSettings { } private void restoreCompass(Bundle savedInstanceState) { + boolean compassEnabled = savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_ENABLED); + if (compassEnabled && !isCompassInitialized) { + compassView = mapView.initialiseCompassView(); + isCompassInitialized = true; + } setCompassEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_ENABLED)); setCompassGravity(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_GRAVITY)); setCompassMargins(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_LEFT), @@ -200,10 +225,12 @@ public final class UiSettings { savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM)); setCompassFadeFacingNorth(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH)); setCompassImage(BitmapUtils.getDrawableFromByteArray( - compassView.getContext(), savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP))); + mapView.getContext(), savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP))); } private void initialiseLogo(MapboxMapOptions options, @NonNull Resources resources) { + isLogoInitialized = true; + logoView = mapView.initialiseLogoView(); setLogoEnabled(options.getLogoEnabled()); setLogoGravity(options.getLogoGravity()); setLogoMargins(resources, options.getLogoMargins()); @@ -229,6 +256,11 @@ public final class UiSettings { } private void restoreLogo(Bundle savedInstanceState) { + boolean logoEnabled = savedInstanceState.getBoolean(MapboxConstants.STATE_LOGO_ENABLED); + if (logoEnabled && !isLogoInitialized) { + logoView = mapView.initialiseLogoView(); + isLogoInitialized = true; + } setLogoEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_LOGO_ENABLED)); setLogoGravity(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_GRAVITY)); setLogoMargins(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT), @@ -238,6 +270,8 @@ public final class UiSettings { } private void initialiseAttribution(@NonNull Context context, MapboxMapOptions options) { + isAttributionInitialized = true; + attributionsView = mapView.initialiseAttributionView(); setAttributionEnabled(options.getAttributionEnabled()); setAttributionGravity(options.getAttributionGravity()); setAttributionMargins(context, options.getAttributionMargins()); @@ -269,6 +303,11 @@ public final class UiSettings { } private void restoreAttribution(Bundle savedInstanceState) { + boolean attributionEnabled = savedInstanceState.getBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED); + if (attributionEnabled && !isAttributionInitialized) { + attributionsView = mapView.initialiseAttributionView(); + isAttributionInitialized = true; + } setAttributionEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED)); setAttributionGravity(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY)); setAttributionMargins(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT), @@ -289,7 +328,13 @@ public final class UiSettings { * @param compassEnabled True to enable the compass; false to disable the compass. */ public void setCompassEnabled(boolean compassEnabled) { - compassView.setEnabled(compassEnabled); + if (compassEnabled && !isCompassInitialized) { + initialiseCompass(mapView.mapboxMapOptions, mapView.getContext().getResources()); + } + if (compassView != null) { + compassView.setEnabled(compassEnabled); + compassView.update(clockwiseBearing); + } } /** @@ -298,7 +343,11 @@ public final class UiSettings { * @return True if the compass is enabled; false if the compass is disabled. */ public boolean isCompassEnabled() { - return compassView.isEnabled(); + if (compassView != null) { + return compassView.isEnabled(); + } else { + return false; + } } /** @@ -312,7 +361,9 @@ public final class UiSettings { */ @UiThread public void setCompassGravity(int gravity) { - setWidgetGravity(compassView, gravity); + if (compassView != null) { + setWidgetGravity(compassView, gravity); + } } /** @@ -324,7 +375,9 @@ public final class UiSettings { * @param compassFadeFacingNorth True to enable the fading animation; false to disable it */ public void setCompassFadeFacingNorth(boolean compassFadeFacingNorth) { - compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth); + if (compassView != null) { + compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth); + } } /** @@ -336,7 +389,9 @@ public final class UiSettings { * @param compass the drawable to show as image compass */ public void setCompassImage(@NonNull Drawable compass) { - compassView.setCompassImage(compass); + if (compassView != null) { + compassView.setCompassImage(compass); + } } /** @@ -345,7 +400,11 @@ public final class UiSettings { * @return True if the compass will fade, false if it remains visible */ public boolean isCompassFadeWhenFacingNorth() { - return compassView.isFadeCompassViewFacingNorth(); + if (compassView != null) { + return compassView.isFadeCompassViewFacingNorth(); + } else { + return false; + } } /** @@ -354,7 +413,11 @@ public final class UiSettings { * @return The gravity */ public int getCompassGravity() { - return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).gravity; + if (compassView != null) { + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).gravity; + } else { + return -1; + } } /** @@ -368,7 +431,9 @@ public final class UiSettings { */ @UiThread public void setCompassMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { - setWidgetMargins(compassView, compassMargins, left, top, right, bottom); + if (compassView != null) { + setWidgetMargins(compassView, compassMargins, left, top, right, bottom); + } } /** @@ -416,14 +481,20 @@ public final class UiSettings { * * @return the drawable used as compass image */ - @NonNull + @Nullable public Drawable getCompassImage() { - return compassView.getCompassImage(); + if (compassView != null) { + return compassView.getCompassImage(); + } else { + return null; + } } void update(@NonNull CameraPosition cameraPosition) { - double clockwiseBearing = -cameraPosition.bearing; - compassView.update(clockwiseBearing); + clockwiseBearing = -cameraPosition.bearing; + if (compassView != null) { + compassView.update(clockwiseBearing); + } } /** @@ -435,7 +506,12 @@ public final class UiSettings { * @param enabled True to enable the logo; false to disable the logo. */ public void setLogoEnabled(boolean enabled) { - logoView.setVisibility(enabled ? View.VISIBLE : View.GONE); + if (enabled && !isLogoInitialized) { + initialiseLogo(mapView.mapboxMapOptions, mapView.getContext().getResources()); + } + if (logoView != null) { + logoView.setVisibility(enabled ? View.VISIBLE : View.GONE); + } } /** @@ -444,7 +520,11 @@ public final class UiSettings { * @return True if the logo is enabled; false if the logo is disabled. */ public boolean isLogoEnabled() { - return logoView.getVisibility() == View.VISIBLE; + if (logoView != null) { + return logoView.getVisibility() == View.VISIBLE; + } else { + return false; + } } /** @@ -457,7 +537,9 @@ public final class UiSettings { * @param gravity Android SDK Gravity. */ public void setLogoGravity(int gravity) { - setWidgetGravity(logoView, gravity); + if (logoView != null) { + setWidgetGravity(logoView, gravity); + } } /** @@ -466,7 +548,11 @@ public final class UiSettings { * @return The gravity */ public int getLogoGravity() { - return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).gravity; + if (logoView != null) { + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).gravity; + } else { + return -1; + } } /** @@ -479,7 +565,9 @@ public final class UiSettings { * @param bottom The bottom margin in pixels. */ public void setLogoMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { - setWidgetMargins(logoView, logoMargins, left, top, right, bottom); + if (logoView != null) { + setWidgetMargins(logoView, logoMargins, left, top, right, bottom); + } } /** @@ -531,7 +619,12 @@ public final class UiSettings { * @param enabled True to enable the attribution; false to disable the attribution. */ public void setAttributionEnabled(boolean enabled) { - attributionsView.setVisibility(enabled ? View.VISIBLE : View.GONE); + if (enabled && !isAttributionInitialized) { + initialiseAttribution(mapView.getContext(), mapView.mapboxMapOptions); + } + if (attributionsView != null) { + attributionsView.setVisibility(enabled ? View.VISIBLE : View.GONE); + } } /** @@ -540,7 +633,11 @@ public final class UiSettings { * @return True if the attribution is enabled; false if the attribution is disabled. */ public boolean isAttributionEnabled() { - return attributionsView.getVisibility() == View.VISIBLE; + if (attributionsView != null) { + return attributionsView.getVisibility() == View.VISIBLE; + } else { + return false; + } } @@ -575,7 +672,9 @@ public final class UiSettings { * @param gravity Android SDK Gravity. */ public void setAttributionGravity(int gravity) { - setWidgetGravity(attributionsView, gravity); + if (attributionsView != null) { + setWidgetGravity(attributionsView, gravity); + } } /** @@ -584,7 +683,11 @@ public final class UiSettings { * @return The gravity */ public int getAttributionGravity() { - return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).gravity; + if (attributionsView != null) { + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).gravity; + } else { + return -1; + } } /** @@ -596,7 +699,9 @@ public final class UiSettings { * @param bottom The bottom margin in pixels. */ public void setAttributionMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { - setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom); + if (attributionsView != null) { + setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom); + } } /** @@ -608,6 +713,9 @@ public final class UiSettings { */ public void setAttributionTintColor(@ColorInt int tintColor) { // Check that the tint color being passed in isn't transparent. + if (attributionsView == null) { + return; + } if (Color.alpha(tintColor) == 0) { ColorUtils.setTintList(attributionsView, ContextCompat.getColor(attributionsView.getContext(), R.color.mapbox_blue)); diff --git a/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml deleted file mode 100644 index e5cde7e44..000000000 --- a/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java index df6df7afd..06d390d40 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java @@ -1,5 +1,7 @@ package com.mapbox.mapboxsdk.maps; +import android.content.Context; +import android.content.res.Resources; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -21,6 +23,14 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; public class UiSettingsTest { + @InjectMocks + MapView mapview = mock(MapView.class); + + @InjectMocks + Context context = mock(Context.class); + + @InjectMocks + Resources resources = mock(Resources.class); @InjectMocks Projection projection = mock(Projection.class); @@ -32,7 +42,7 @@ public class UiSettingsTest { CompassView compassView = mock(CompassView.class); @InjectMocks - ImageView imageView = mock(ImageView.class); + ImageView attributionView = mock(ImageView.class); @InjectMocks ImageView logoView = mock(ImageView.class); @@ -41,10 +51,18 @@ public class UiSettingsTest { FrameLayout.LayoutParams layoutParams = mock(FrameLayout.LayoutParams.class); private UiSettings uiSettings; + private MapboxMapOptions mapboxMapOptions; @Before public void beforeTest() { - uiSettings = new UiSettings(projection, focalPointChangeListener, compassView, imageView, logoView, 1); + uiSettings = new UiSettings(projection, focalPointChangeListener, 1, mapview); + uiSettings.compassView = this.compassView; + uiSettings.attributionsView = this.attributionView; + uiSettings.logoView = this.logoView; + when(compassView.getContext()).thenReturn(context); + when(attributionView.getContext()).thenReturn(context); + when(logoView.getContext()).thenReturn(context); + when(context.getResources()).thenReturn(resources); } @Test @@ -53,12 +71,18 @@ public class UiSettingsTest { } @Test - public void testCompassEnabled() { + public void testGetCompassEnabled() { when(compassView.isEnabled()).thenReturn(true); - uiSettings.setCompassEnabled(true); assertEquals("Compass should be enabled", true, uiSettings.isCompassEnabled()); } + @Test + public void testSetCompassEnabled() { + uiSettings.isCompassInitialized = true; + uiSettings.setCompassEnabled(true); + verify(compassView).setEnabled(true); + } + @Test public void testCompassDisabled() { uiSettings.setCompassEnabled(false); @@ -75,7 +99,7 @@ public class UiSettingsTest { @Test public void testCompassMargins() { - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); when(compassView.getLayoutParams()).thenReturn(layoutParams); layoutParams.leftMargin = 1; layoutParams.topMargin = 2; @@ -99,6 +123,7 @@ public class UiSettingsTest { @Test public void testLogoEnabled() { + uiSettings.isLogoInitialized = true; uiSettings.setLogoEnabled(true); assertEquals("Logo should be enabled", true, uiSettings.isLogoEnabled()); } @@ -120,7 +145,7 @@ public class UiSettingsTest { @Test public void testLogoMargins() { - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); when(logoView.getLayoutParams()).thenReturn(layoutParams); layoutParams.leftMargin = 1; layoutParams.topMargin = 2; @@ -135,21 +160,22 @@ public class UiSettingsTest { @Test public void testAttributionEnabled() { - when(imageView.getVisibility()).thenReturn(View.VISIBLE); + uiSettings.isAttributionInitialized = true; + when(attributionView.getVisibility()).thenReturn(View.VISIBLE); uiSettings.setAttributionEnabled(true); assertEquals("Attribution should be enabled", true, uiSettings.isAttributionEnabled()); } @Test public void testAttributionDisabled() { - when(imageView.getVisibility()).thenReturn(View.GONE); + when(attributionView.getVisibility()).thenReturn(View.GONE); uiSettings.setAttributionEnabled(false); assertEquals("Attribution should be disabled", false, uiSettings.isAttributionEnabled()); } @Test public void testAttributionGravity() { - when(imageView.getLayoutParams()).thenReturn(layoutParams); + when(attributionView.getLayoutParams()).thenReturn(layoutParams); layoutParams.gravity = Gravity.END; uiSettings.setAttributionGravity(Gravity.END); assertEquals("Attribution gravity should be same", Gravity.END, uiSettings.getAttributionGravity()); @@ -157,8 +183,8 @@ public class UiSettingsTest { @Test public void testAttributionMargins() { - when(imageView.getLayoutParams()).thenReturn(layoutParams); - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); + when(attributionView.getLayoutParams()).thenReturn(layoutParams); + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); layoutParams.leftMargin = 1; layoutParams.topMargin = 2; layoutParams.rightMargin = 3; @@ -359,14 +385,14 @@ public class UiSettingsTest { public void testDisableRotateWhenScalingEnabled() { uiSettings.setDisableRotateWhenScaling(true); assertEquals("Rotate disabling should be enabled", true, - uiSettings.isDisableRotateWhenScaling()); + uiSettings.isDisableRotateWhenScaling()); } @Test public void testDisableRotateWhenScalingDisabled() { uiSettings.setDisableRotateWhenScaling(false); assertEquals("Rotate disabling should be disabled", false, - uiSettings.isDisableRotateWhenScaling()); + uiSettings.isDisableRotateWhenScaling()); } @Test @@ -379,7 +405,7 @@ public class UiSettingsTest { public void testIncreaseScaleThresholdWhenRotatingDisabled() { uiSettings.setIncreaseScaleThresholdWhenRotating(false); assertEquals("Scale threshold increase should be disabled", false, - uiSettings.isIncreaseScaleThresholdWhenRotating()); + uiSettings.isIncreaseScaleThresholdWhenRotating()); } @Test @@ -404,7 +430,7 @@ public class UiSettingsTest { public void testAreAllGesturesEnabled() { uiSettings.setAllGesturesEnabled(true); assertEquals("All gestures check should return true", true, - uiSettings.areAllGesturesEnabled()); + uiSettings.areAllGesturesEnabled()); } @Test @@ -412,20 +438,20 @@ public class UiSettingsTest { uiSettings.setAllGesturesEnabled(true); uiSettings.setScrollGesturesEnabled(false); assertEquals("All gestures check should return false", false, - uiSettings.areAllGesturesEnabled()); + uiSettings.areAllGesturesEnabled()); } @Test public void testZoomRateDefaultValue() { assertEquals("Default zoom rate should be 1.0f", 1.0f, - uiSettings.getZoomRate(), 0); + uiSettings.getZoomRate(), 0); } @Test public void testZoomRate() { uiSettings.setZoomRate(0.83f); assertEquals("Zoom rate should be 0.83f", 0.83f, - uiSettings.getZoomRate(), 0); + uiSettings.getZoomRate(), 0); } @Test diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java index bb25a1d51..cb0366aa8 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java @@ -35,9 +35,11 @@ import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData; import static androidx.test.espresso.matcher.RootMatchers.isDialog; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anything; +import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNot.not; import static org.junit.Assume.assumeTrue; @@ -56,10 +58,10 @@ public class AttributionTest extends EspressoTest { validateTestSetup(); // Default - onView(withId(R.id.attributionView)).check(matches(isDisplayed())); + onView(withTagValue(is("attrView"))).check(matches(isDisplayed())); // Disabled - onView(withId(R.id.attributionView)) + onView(withTagValue(is("attrView"))) .perform(new DisableAction(mapboxMap)) .check(matches(not(isDisplayed()))); } @@ -73,7 +75,7 @@ public class AttributionTest extends EspressoTest { } // click on View to open dialog - onView(withId(R.id.attributionView)).perform(click()); + onView(withTagValue(is("attrView"))).perform(click()); onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed())); // test for trigger url intent @@ -94,7 +96,7 @@ public class AttributionTest extends EspressoTest { } // click on View to open dialog - onView(withId(R.id.attributionView)).perform(click()); + onView(withTagValue(is("attrView"))).perform(click()); onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed())); // test for trigger url intent @@ -115,7 +117,7 @@ public class AttributionTest extends EspressoTest { } // click on View to open dialog - onView(withId(R.id.attributionView)).perform(click()); + onView(withTagValue(is("attrView"))).perform(click()); onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed())); // test for trigger url intent @@ -137,7 +139,7 @@ public class AttributionTest extends EspressoTest { validateTestSetup(); // click on View to open dialog - onView(withId(R.id.attributionView)).perform(click()); + onView(withTagValue(is("attrView"))).perform(click()); onView(withText(R.string.mapbox_attributionsDialogTitle)).inRoot(isDialog()).check(matches(isDisplayed())); // click on item to open second dialog diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java index a01274c8b..09b242e48 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java @@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.action.WaitAction; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestConstants; + import org.junit.Ignore; import org.junit.Test; @@ -14,8 +14,9 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; @@ -24,7 +25,7 @@ public class CompassViewTest extends EspressoTest { @Test public void testDefault() { validateTestSetup(); - onView(withId(R.id.compassView)).check(matches(not(isDisplayed()))); + onView(withTagValue(is("compassView"))).check(matches(not(isDisplayed()))); } @Test @@ -41,7 +42,7 @@ public class CompassViewTest extends EspressoTest { )); uiController.loopMainThreadForAtLeast(500); }); - onView(withId(R.id.compassView)).check(matches(isDisplayed())); + onView(withTagValue(is("compassView"))).check(matches(isDisplayed())); } @Test @@ -55,9 +56,9 @@ public class CompassViewTest extends EspressoTest { .target(new LatLng()) .build() ))); - onView(withId(R.id.compassView)).perform(click()); + onView(withTagValue(is("compassView"))).perform(click()); WaitAction.invoke(500); - onView(withId(R.id.compassView)).check(matches(not(isDisplayed()))); + onView(withTagValue(is("compassView"))).check(matches(not(isDisplayed()))); invoke(mapboxMap, (uiController, mapboxMap) -> { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); assertEquals("Camera bearing should face north, ", 0, cameraPosition.bearing, TestConstants.BEARING_DELTA); diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java index e066156b5..b85f85b9e 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java @@ -1,11 +1,11 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets; +import android.view.View; + import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; -import android.view.View; import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import org.hamcrest.Matcher; @@ -14,7 +14,8 @@ import org.junit.Test; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; public class LogoTest extends EspressoTest { @@ -22,16 +23,16 @@ public class LogoTest extends EspressoTest { @Test public void testDefault() { validateTestSetup(); - onView(withId(R.id.logoView)).check(matches(isDisplayed())); + onView(withTagValue(is("logoView"))).check(matches(isDisplayed())); } @Test public void testDisabled() { validateTestSetup(); - onView(withId(R.id.logoView)) - .perform(new DisableAction(mapboxMap)) - .check(matches(not(isDisplayed()))); + onView(withTagValue(is("logoView"))) + .perform(new DisableAction(mapboxMap)) + .check(matches(not(isDisplayed()))); } private class DisableAction implements ViewAction { From 834c8310a5f31f571ede5cf886942f20b496cdbd Mon Sep 17 00:00:00 2001 From: tobrun Date: Mon, 13 Jan 2020 10:58:03 +0100 Subject: [PATCH 068/185] [deps] update telemetry dependency and update vendor submodule --- gradle/dependencies.gradle | 4 ++-- vendor/mapbox-events-android | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index b9900d124..6bccb5b05 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,8 +8,8 @@ ext { versions = [ mapboxServices : '5.0.0', - mapboxTelemetry : '4.5.1', - mapboxCore : '1.3.0', + mapboxTelemetry : '4.7.1', + mapboxCore : '1.4.1', mapboxGestures : '0.6.0', mapboxAccounts : '0.7.0', appCompat : '1.0.0', diff --git a/vendor/mapbox-events-android b/vendor/mapbox-events-android index 58fbec16c..24bb138ec 160000 --- a/vendor/mapbox-events-android +++ b/vendor/mapbox-events-android @@ -1 +1 @@ -Subproject commit 58fbec16cdedb909eb63c68e46708fe9268b6fed +Subproject commit 24bb138eca7821d14932fffa1e7461f472212034 From b15e9f88fc9382132fded1b1b11930e9fbe7398f Mon Sep 17 00:00:00 2001 From: tobrun Date: Wed, 29 Jan 2020 11:50:21 +0100 Subject: [PATCH 069/185] [location] add location permission --- MapboxGLAndroidSDK/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/MapboxGLAndroidSDK/src/main/AndroidManifest.xml index dcbec69bf..eb482b73b 100644 --- a/MapboxGLAndroidSDK/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDK/src/main/AndroidManifest.xml @@ -11,5 +11,5 @@ - + From 5b1a4ff265283fec1dada033ebc378bd5f4e1586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 6 Feb 2020 15:13:42 +0100 Subject: [PATCH 070/185] expose option to pass intermadiate points for smooth location animation --- .../location/LocationAnimatorCoordinator.java | 103 ++++++++++---- .../mapboxsdk/location/LocationComponent.java | 53 +++++++- .../mapboxsdk/location/MapboxAnimator.java | 8 +- .../location/MapboxAnimatorProvider.java | 14 +- .../location/MapboxCameraAnimatorAdapter.java | 7 +- .../location/MapboxFloatAnimator.java | 7 +- .../location/MapboxLatLngAnimator.java | 5 +- .../LocationAnimatorCoordinatorTest.kt | 126 +++++++++++++++--- .../mapboxsdk/location/MapboxAnimatorTest.kt | 4 +- 9 files changed, 262 insertions(+), 65 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 248c7664b..474e524d1 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -3,12 +3,14 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.location.Location; import android.os.SystemClock; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import android.util.SparseArray; import android.view.animation.LinearInterpolator; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; +import androidx.annotation.VisibleForTesting; + import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.log.Logger; @@ -33,6 +35,8 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation; +import static com.mapbox.mapboxsdk.location.Utils.normalize; +import static com.mapbox.mapboxsdk.location.Utils.shortestRotation; final class LocationAnimatorCoordinator { @@ -74,6 +78,12 @@ final class LocationAnimatorCoordinator { void feedNewLocation(@NonNull Location newLocation, @NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { + feedNewLocation(new Location[] {newLocation}, currentCameraPosition, isGpsNorth, false); + } + + void feedNewLocation(@NonNull @Size(min = 1) Location[] newLocations, + @NonNull CameraPosition currentCameraPosition, boolean isGpsNorth, boolean lookAheadUpdate) { + Location newLocation = newLocations[newLocations.length - 1]; if (previousLocation == null) { previousLocation = newLocation; locationUpdateTimestamp = SystemClock.elapsedRealtime() - TRANSITION_ANIMATION_DURATION_MS; @@ -82,16 +92,23 @@ final class LocationAnimatorCoordinator { LatLng previousLayerLatLng = getPreviousLayerLatLng(); float previousLayerBearing = getPreviousLayerGpsBearing(); LatLng previousCameraLatLng = currentCameraPosition.target; - float previousCameraBearing = (float) currentCameraPosition.bearing; + float previousCameraBearing = normalize((float) currentCameraPosition.bearing); + + // generate targets for layer + LatLng[] latLngValues = getLatLngValues(previousLayerLatLng, newLocations); + Float[] bearingValues = getBearingValues(previousLayerBearing, newLocations); + updateLayerAnimators(latLngValues, bearingValues); + + // replace the animation start with the camera's previous value + latLngValues[0] = previousCameraLatLng; + if (isGpsNorth) { + bearingValues = new Float[] {previousCameraBearing, 0f}; + } else { + bearingValues[0] = previousCameraBearing; + } + updateCameraAnimators(latLngValues, bearingValues); LatLng targetLatLng = new LatLng(newLocation); - float targetLayerBearing = newLocation.getBearing(); - float targetCameraBearing = newLocation.getBearing(); - targetCameraBearing = checkGpsNorth(isGpsNorth, targetCameraBearing); - - updateLayerAnimators(previousLayerLatLng, targetLatLng, previousLayerBearing, targetLayerBearing); - updateCameraAnimators(previousCameraLatLng, previousCameraBearing, targetLatLng, targetCameraBearing); - boolean snap = immediateAnimation(projection, previousCameraLatLng, targetLatLng) || immediateAnimation(projection, previousLayerLatLng, targetLatLng); @@ -102,6 +119,15 @@ final class LocationAnimatorCoordinator { if (previousUpdateTimeStamp == 0) { animationDuration = 0; + } else if (lookAheadUpdate) { + long currentTimestamp = System.currentTimeMillis(); + if (currentTimestamp > newLocation.getTime()) { + animationDuration = 0; + Logger.e("LocationAnimatorCoordinator", + "Lookahead enabled, but the target location's timestamp is smaller than current timestamp"); + } else { + animationDuration = newLocation.getTime() - currentTimestamp; + } } else { animationDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * durationMultiplier) /* make animation slightly longer with durationMultiplier, defaults to 1.1f */; @@ -207,23 +233,35 @@ final class LocationAnimatorCoordinator { return previousRadius; } - private void updateLayerAnimators(LatLng previousLatLng, LatLng targetLatLng, - float previousBearing, float targetBearing) { - createNewLatLngAnimator(ANIMATOR_LAYER_LATLNG, previousLatLng, targetLatLng); + private LatLng[] getLatLngValues(LatLng previousLatLng, Location[] targetLocations) { + LatLng[] latLngs = new LatLng[targetLocations.length + 1]; + latLngs[0] = previousLatLng; + for (int i = 1; i < latLngs.length; i++) { + latLngs[i] = new LatLng(targetLocations[i - 1]); + } + return latLngs; + } + + private Float[] getBearingValues(Float previousBearing, Location[] targetLocations) { + Float[] bearings = new Float[targetLocations.length + 1]; // Because Location bearing values are normalized to [0, 360] // we need to do the same for the previous bearing value to determine the shortest path - previousBearing = Utils.normalize(previousBearing); - float normalizedLayerBearing = Utils.shortestRotation(targetBearing, previousBearing); - createNewFloatAnimator(ANIMATOR_LAYER_GPS_BEARING, previousBearing, normalizedLayerBearing); + bearings[0] = normalize(previousBearing); + for (int i = 1; i < bearings.length; i++) { + bearings[i] = shortestRotation(targetLocations[i - 1].getBearing(), bearings[i - 1]); + } + return bearings; } - private void updateCameraAnimators(LatLng previousCameraLatLng, float previousCameraBearing, - LatLng targetLatLng, float targetBearing) { - createNewLatLngAnimator(ANIMATOR_CAMERA_LATLNG, previousCameraLatLng, targetLatLng); + private void updateLayerAnimators(LatLng[] latLngValues, Float[] bearingValues) { + createNewLatLngAnimator(ANIMATOR_LAYER_LATLNG, latLngValues); + createNewFloatAnimator(ANIMATOR_LAYER_GPS_BEARING, bearingValues); + } - float normalizedCameraBearing = Utils.shortestRotation(targetBearing, previousCameraBearing); - createNewFloatAnimator(ANIMATOR_CAMERA_GPS_BEARING, previousCameraBearing, normalizedCameraBearing); + private void updateCameraAnimators(LatLng[] latLngValues, Float[] bearingValues) { + createNewLatLngAnimator(ANIMATOR_CAMERA_LATLNG, latLngValues); + createNewFloatAnimator(ANIMATOR_CAMERA_GPS_BEARING, bearingValues); } private void updateCompassAnimators(float targetCompassBearing, float previousLayerBearing, @@ -241,36 +279,45 @@ final class LocationAnimatorCoordinator { private void updateZoomAnimator(float targetZoomLevel, float previousZoomLevel, @Nullable MapboxMap.CancelableCallback cancelableCallback) { - createNewCameraAdapterAnimator(ANIMATOR_ZOOM, previousZoomLevel, targetZoomLevel, cancelableCallback); + createNewCameraAdapterAnimator(ANIMATOR_ZOOM, new Float[] {previousZoomLevel, targetZoomLevel}, cancelableCallback); } private void updateTiltAnimator(float targetTilt, float previousTiltLevel, @Nullable MapboxMap.CancelableCallback cancelableCallback) { - createNewCameraAdapterAnimator(ANIMATOR_TILT, previousTiltLevel, targetTilt, cancelableCallback); + createNewCameraAdapterAnimator(ANIMATOR_TILT, new Float[] {previousTiltLevel, targetTilt}, cancelableCallback); } private void createNewLatLngAnimator(@MapboxAnimator.Type int animatorType, LatLng previous, LatLng target) { + createNewLatLngAnimator(animatorType, new LatLng[] {previous, target}); + } + + private void createNewLatLngAnimator(@MapboxAnimator.Type int animatorType, LatLng[] values) { cancelAnimator(animatorType); MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); if (listener != null) { - animatorArray.put(animatorType, animatorProvider.latLngAnimator(previous, target, listener, maxAnimationFps)); + animatorArray.put(animatorType, animatorProvider.latLngAnimator(values, listener, maxAnimationFps)); } } private void createNewFloatAnimator(@MapboxAnimator.Type int animatorType, float previous, float target) { + createNewFloatAnimator(animatorType, new Float[] {previous, target}); + } + + private void createNewFloatAnimator(@MapboxAnimator.Type int animatorType, @NonNull @Size(min = 2) Float[] values) { cancelAnimator(animatorType); MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); if (listener != null) { - animatorArray.put(animatorType, animatorProvider.floatAnimator(previous, target, listener, maxAnimationFps)); + animatorArray.put(animatorType, animatorProvider.floatAnimator(values, listener, maxAnimationFps)); } } - private void createNewCameraAdapterAnimator(@MapboxAnimator.Type int animatorType, float previous, float target, + private void createNewCameraAdapterAnimator(@MapboxAnimator.Type int animatorType, + @NonNull @Size(min = 2) Float[] values, @Nullable MapboxMap.CancelableCallback cancelableCallback) { cancelAnimator(animatorType); MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(animatorType); if (listener != null) { - animatorArray.put(animatorType, animatorProvider.cameraAnimator(previous, target, listener, cancelableCallback)); + animatorArray.put(animatorType, animatorProvider.cameraAnimator(values, listener, cancelableCallback)); } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 9df7a1456..0f7dfded0 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -6,12 +6,13 @@ import android.hardware.SensorManager; import android.location.Location; import android.os.Looper; import android.os.SystemClock; +import android.view.WindowManager; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresPermission; import androidx.annotation.StyleRes; import androidx.annotation.VisibleForTesting; -import android.view.WindowManager; import com.mapbox.android.core.location.LocationEngine; import com.mapbox.android.core.location.LocationEngineCallback; @@ -889,6 +890,32 @@ public final class LocationComponent { updateLocation(location, false); } + /** + * Use to either force a location update or to manually control when the user location gets + * updated. + *

    + * This method can be used to provide the list of locations where the last one is the target location + * and the rest are intermediate points used as the animation path. + * The puck and the camera will be animated between each of the points linearly until reaching the target. + * + * @param locations where the location icon is placed on the map + * @param lookAheadUpdate If set to true, the last location's timestamp has to be greater than current timestamp and + * should represent the time at which the animation should actually reach this position, + * cutting out the time interpolation delay. + */ + public void forceLocationUpdate(@Nullable List locations, boolean lookAheadUpdate) { + checkActivationState(); + if (locations != null && locations.size() >= 1) { + updateLocation( + locations.get(locations.size() - 1), // target location + locations.subList(0, locations.size() - 1), // intermediate locations + false, + lookAheadUpdate); + } else { + updateLocation(null, false); + } + } + /** * Set max FPS at which location animators can output updates. The throttling will only impact the location puck * and camera tracking smooth animations. @@ -1341,6 +1368,11 @@ public final class LocationComponent { * @param location the latest user location */ private void updateLocation(@Nullable final Location location, boolean fromLastLocation) { + updateLocation(location, null, fromLastLocation, false); + } + + private void updateLocation(@Nullable final Location location, @Nullable List intermediatePoints, + boolean fromLastLocation, boolean lookAheadUpdate) { if (location == null) { return; } else if (!isLayerReady) { @@ -1362,11 +1394,28 @@ public final class LocationComponent { } CameraPosition currentCameraPosition = mapboxMap.getCameraPosition(); boolean isGpsNorth = getCameraMode() == CameraMode.TRACKING_GPS_NORTH; - locationAnimatorCoordinator.feedNewLocation(location, currentCameraPosition, isGpsNorth); + if (intermediatePoints != null) { + locationAnimatorCoordinator.feedNewLocation( + getTargetLocationWithIntermediates(location, intermediatePoints), + currentCameraPosition, + isGpsNorth, + lookAheadUpdate); + } else { + locationAnimatorCoordinator.feedNewLocation(location, currentCameraPosition, isGpsNorth); + } updateAccuracyRadius(location, false); lastLocation = location; } + private Location[] getTargetLocationWithIntermediates(Location location, List intermediatePoints) { + Location[] locations = new Location[intermediatePoints.size() + 1]; + locations[locations.length - 1] = location; + for (int i = 0; i < intermediatePoints.size(); i++) { + locations[i] = intermediatePoints.get(i); + } + return locations; + } + private void showLocationLayerIfHidden() { boolean isLocationLayerHidden = locationLayerController.isHidden(); if (isEnabled && isComponentStarted && isLocationLayerHidden) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index 7038367e3..f9a213241 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -4,8 +4,10 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; + import androidx.annotation.IntDef; import androidx.annotation.NonNull; +import androidx.annotation.Size; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -48,13 +50,13 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. private final double minUpdateInterval; private long timeElapsed; - MapboxAnimator(@NonNull K previous, @NonNull K target, @NonNull AnimationsValueChangeListener updateListener, + MapboxAnimator(@NonNull @Size(min = 2) K[] values, @NonNull AnimationsValueChangeListener updateListener, int maxAnimationFps) { minUpdateInterval = 1E9 / maxAnimationFps; - setObjectValues(previous, target); + setObjectValues((Object[]) values); setEvaluator(provideEvaluator()); this.updateListener = updateListener; - this.target = target; + this.target = values[values.length - 1]; addUpdateListener(this); addListener(new AnimatorListener()); } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java index 7782d8822..c1109b959 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java @@ -20,21 +20,19 @@ final class MapboxAnimatorProvider { return INSTANCE; } - MapboxLatLngAnimator latLngAnimator(LatLng previous, LatLng target, - MapboxAnimator.AnimationsValueChangeListener updateListener, + MapboxLatLngAnimator latLngAnimator(LatLng[] values, MapboxAnimator.AnimationsValueChangeListener updateListener, int maxAnimationFps) { - return new MapboxLatLngAnimator(previous, target, updateListener, maxAnimationFps); + return new MapboxLatLngAnimator(values, updateListener, maxAnimationFps); } - MapboxFloatAnimator floatAnimator(Float previous, Float target, - MapboxAnimator.AnimationsValueChangeListener updateListener, + MapboxFloatAnimator floatAnimator(Float[] values, MapboxAnimator.AnimationsValueChangeListener updateListener, int maxAnimationFps) { - return new MapboxFloatAnimator(previous, target, updateListener, maxAnimationFps); + return new MapboxFloatAnimator(values, updateListener, maxAnimationFps); } - MapboxCameraAnimatorAdapter cameraAnimator(Float previous, Float target, + MapboxCameraAnimatorAdapter cameraAnimator(Float[] values, MapboxAnimator.AnimationsValueChangeListener updateListener, @Nullable MapboxMap.CancelableCallback cancelableCallback) { - return new MapboxCameraAnimatorAdapter(previous, target, updateListener, cancelableCallback); + return new MapboxCameraAnimatorAdapter(values, updateListener, cancelableCallback); } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java index 52ab7c4fc..a3b9fff42 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxCameraAnimatorAdapter.java @@ -2,7 +2,10 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.Size; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -10,10 +13,10 @@ class MapboxCameraAnimatorAdapter extends MapboxFloatAnimator { @Nullable private final MapboxMap.CancelableCallback cancelableCallback; - MapboxCameraAnimatorAdapter(Float previous, Float target, + MapboxCameraAnimatorAdapter(@NonNull @Size(min = 2) Float[] values, AnimationsValueChangeListener updateListener, @Nullable MapboxMap.CancelableCallback cancelableCallback) { - super(previous, target, updateListener, Integer.MAX_VALUE); + super(values, updateListener, Integer.MAX_VALUE); this.cancelableCallback = cancelableCallback; addListener(new MapboxAnimatorListener()); } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java index 94f405b69..cad5fc983 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxFloatAnimator.java @@ -2,11 +2,14 @@ package com.mapbox.mapboxsdk.location; import android.animation.FloatEvaluator; import android.animation.TypeEvaluator; + import androidx.annotation.NonNull; +import androidx.annotation.Size; class MapboxFloatAnimator extends MapboxAnimator { - MapboxFloatAnimator(Float previous, Float target, AnimationsValueChangeListener updateListener, int maxAnimationFps) { - super(previous, target, updateListener, maxAnimationFps); + MapboxFloatAnimator(@NonNull @Size(min = 2) Float[] values, + @NonNull AnimationsValueChangeListener updateListener, int maxAnimationFps) { + super(values, updateListener, maxAnimationFps); } @NonNull diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java index 524847036..a32bf63ef 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxLatLngAnimator.java @@ -1,15 +1,16 @@ package com.mapbox.mapboxsdk.location; import android.animation.TypeEvaluator; + import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; class MapboxLatLngAnimator extends MapboxAnimator { - MapboxLatLngAnimator(LatLng previous, LatLng target, AnimationsValueChangeListener updateListener, + MapboxLatLngAnimator(@NonNull LatLng[] values, @NonNull AnimationsValueChangeListener updateListener, int maxAnimationFps) { - super(previous, target, updateListener, maxAnimationFps); + super(values, updateListener, maxAnimationFps); } @NonNull diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt index 1b927d213..bd741e5b9 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -56,34 +56,32 @@ class LocationAnimatorCoordinatorTest { // workaround https://github.com/mockk/mockk/issues/229#issuecomment-457816131 registerInstanceFactory { AnimationsValueChangeListener {} } registerInstanceFactory { AnimationsValueChangeListener {} } - val previousFloatSlot = slot() - val targetFloatSlot = slot() + val floatsSlot = slot>() val listenerSlot = slot>() val maxFpsSlot = slot() every { - animatorProvider.floatAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), capture(maxFpsSlot)) + animatorProvider.floatAnimator(capture(floatsSlot), capture(listenerSlot), capture(maxFpsSlot)) } answers { - MapboxFloatAnimator(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, maxFpsSlot.captured) + MapboxFloatAnimator(floatsSlot.captured, listenerSlot.captured, maxFpsSlot.captured) } - val previousLatLngSlot = slot() - val targetLatLngSlot = slot() + val latLngsSlot = slot>() every { - animatorProvider.latLngAnimator(capture(previousLatLngSlot), capture(targetLatLngSlot), capture(listenerSlot), capture(maxFpsSlot)) + animatorProvider.latLngAnimator(capture(latLngsSlot), capture(listenerSlot), capture(maxFpsSlot)) } answers { - MapboxLatLngAnimator(previousLatLngSlot.captured, targetLatLngSlot.captured, listenerSlot.captured, maxFpsSlot.captured) + MapboxLatLngAnimator(latLngsSlot.captured, listenerSlot.captured, maxFpsSlot.captured) } val callback = slot() every { - animatorProvider.cameraAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), capture(callback)) + animatorProvider.cameraAnimator(capture(floatsSlot), capture(listenerSlot), capture(callback)) } answers { - MapboxCameraAnimatorAdapter(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, callback.captured) + MapboxCameraAnimatorAdapter(floatsSlot.captured, listenerSlot.captured, callback.captured) } every { - animatorProvider.cameraAnimator(capture(previousFloatSlot), capture(targetFloatSlot), capture(listenerSlot), null) + animatorProvider.cameraAnimator(capture(floatsSlot), capture(listenerSlot), null) } answers { - MapboxCameraAnimatorAdapter(previousFloatSlot.captured, targetFloatSlot.captured, listenerSlot.captured, null) + MapboxCameraAnimatorAdapter(floatsSlot.captured, listenerSlot.captured, null) } } @@ -106,10 +104,12 @@ class LocationAnimatorCoordinatorTest { locationAnimatorCoordinator.feedNewLocation(location, cameraPosition, false) val cameraLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG]?.target as LatLng - assertEquals(cameraLatLngTarget.latitude, cameraLatLngTarget.latitude) + assertEquals(location.latitude, cameraLatLngTarget.latitude) + assertEquals(location.longitude, cameraLatLngTarget.longitude) val layerLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG]?.target as LatLng - assertEquals(layerLatLngTarget.latitude, layerLatLngTarget.latitude) + assertEquals(location.latitude, layerLatLngTarget.latitude) + assertEquals(location.longitude, layerLatLngTarget.longitude) val cameraBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING]?.target as Float assertEquals(location.bearing, cameraBearingTarget) @@ -118,6 +118,100 @@ class LocationAnimatorCoordinatorTest { assertEquals(location.bearing, layerBearingTarget) } + @Test + fun feedNewLocation_animatorValue_multiplePoints() { + val previousLocation = Location("") + previousLocation.latitude = 0.0 + previousLocation.longitude = 0.0 + previousLocation.bearing = 0f + + val locationInter = Location("") + locationInter.latitude = 51.1 + locationInter.longitude = 17.1 + locationInter.bearing = 35f + val location = Location("") + location.latitude = 51.2 + location.longitude = 17.2 + location.bearing = 36f + locationAnimatorCoordinator.feedNewLocation(arrayOf(locationInter, location), cameraPosition, false, false) + + val cameraLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG]?.target as LatLng + assertEquals(location.latitude, cameraLatLngTarget.latitude) + assertEquals(location.longitude, cameraLatLngTarget.longitude) + + val layerLatLngTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG]?.target as LatLng + assertEquals(location.latitude, layerLatLngTarget.latitude) + assertEquals(location.longitude, layerLatLngTarget.longitude) + + val cameraBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING]?.target as Float + assertEquals(location.bearing, cameraBearingTarget) + + val layerBearingTarget = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING]?.target as Float + assertEquals(location.bearing, layerBearingTarget) + + verify { + animatorProvider.latLngAnimator( + arrayOf( + LatLng(previousLocation.latitude, previousLocation.longitude), + LatLng(locationInter.latitude, locationInter.longitude), + LatLng(location.latitude, location.longitude) + ), any(), any() + ) + } + verify { + animatorProvider.floatAnimator( + arrayOf(previousLocation.bearing, locationInter.bearing, location.bearing), any(), any() + ) + } + } + + @Test + fun feedNewLocation_animatorValue_multiplePoints_animationDuration() { + every { projection.getMetersPerPixelAtLatitude(any()) } answers { 10000.0 } // disable snap + val locationInter = Location("") + locationInter.latitude = 51.1 + locationInter.longitude = 17.1 + locationInter.bearing = 35f + val location = Location("") + location.latitude = 51.2 + location.longitude = 17.2 + location.bearing = 36f + locationAnimatorCoordinator.feedNewLocation(arrayOf(locationInter, location), cameraPosition, false, false) + + verify { + animatorSetProvider.startAnimation(eq(listOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG], + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING] + )), any(), 0) + } + } + + @Test + fun feedNewLocation_animatorValue_multiplePoints_animationDuration_lookAhead() { + every { projection.getMetersPerPixelAtLatitude(any()) } answers { 10000.0 } // disable snap + val locationInter = Location("") + locationInter.latitude = 51.1 + locationInter.longitude = 17.1 + locationInter.bearing = 35f + val location = Location("") + location.latitude = 51.2 + location.longitude = 17.2 + location.bearing = 36f + location.time = System.currentTimeMillis() + 2000 + locationAnimatorCoordinator.feedNewLocation(arrayOf(locationInter, location), cameraPosition, false, true) + + verify { + animatorSetProvider.startAnimation(eq(listOf( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_LATLNG], + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_GPS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_LATLNG], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_GPS_BEARING] + )), any(), more(1500L)) + } + } + @Test fun feedNewLocation_animatorValue_correctRotation_1() { val location = Location("") @@ -508,8 +602,8 @@ class LocationAnimatorCoordinatorTest { fun maxFps_givenToAnimator() { locationAnimatorCoordinator.setMaxAnimationFps(5) locationAnimatorCoordinator.feedNewLocation(Location(""), cameraPosition, false) - verify { animatorProvider.latLngAnimator(any(), any(), any(), 5) } - verify { animatorProvider.floatAnimator(any(), any(), any(), 5) } + verify { animatorProvider.latLngAnimator(any(), any(), 5) } + verify { animatorProvider.floatAnimator(any(), any(), 5) } } private fun getListenerHoldersSet(vararg animatorTypes: Int): Set { diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt index 7c126c783..0c5b770b4 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/MapboxAnimatorTest.kt @@ -17,7 +17,7 @@ class MapboxAnimatorTest { every { valueAnimator.animatedValue } answers { 5f } val listener = mockk>() every { listener.onNewAnimationValue(any()) } answers {} - val mapboxAnimator = MapboxFloatAnimator(0f, 10f, listener, Int.MAX_VALUE) + val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, Int.MAX_VALUE) for (i in 0 until 5) mapboxAnimator.onAnimationUpdate(valueAnimator) @@ -31,7 +31,7 @@ class MapboxAnimatorTest { every { valueAnimator.animatedValue } answers { 5f } val listener = mockk>() every { listener.onNewAnimationValue(any()) } answers {} - val mapboxAnimator = MapboxFloatAnimator(0f, 10f, listener, 5) + val mapboxAnimator = MapboxFloatAnimator(floatArrayOf(0f, 10f).toTypedArray(), listener, 5) for (i in 0 until 5) { mapboxAnimator.onAnimationUpdate(valueAnimator) From 1b5aeebc870250605a3f5bf8be0517d52c551548 Mon Sep 17 00:00:00 2001 From: Pablo Guardiola Date: Fri, 7 Feb 2020 16:38:01 -0500 Subject: [PATCH 071/185] update mapbox-gl-native downstream vendor to 3ea459233a60ee737d0b637582f94024f3763797 to fix https://github.com/mapbox/mapbox-gl-native/issues/16180 reproducible in the navigation sdk https://github.com/mapbox/mapbox-navigation-android/pull/2452 --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 236afc039..3ea459233 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 236afc03958cc729b3b8121a1c5a72660f0e9fa2 +Subproject commit 3ea459233a60ee737d0b637582f94024f3763797 From 94a7727fc6f789df6fd14e5ad05eee8b1d0308a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 11 Feb 2020 13:55:34 +0100 Subject: [PATCH 072/185] bump snapshot to 9.1.0 --- MapboxGLAndroidSDK/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MapboxGLAndroidSDK/gradle.properties b/MapboxGLAndroidSDK/gradle.properties index f93b35ec0..cb3bea48c 100644 --- a/MapboxGLAndroidSDK/gradle.properties +++ b/MapboxGLAndroidSDK/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=9.0.0-SNAPSHOT +VERSION_NAME=9.1.0-SNAPSHOT # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 @@ -6,4 +6,4 @@ android.buildOnlyTargetAbi=true # Roboelectric 4.0 required config for < Android Studio v3.3.0 # http://robolectric.org/migrating/#migrating-to-40 -android.enableUnitTestBinaryResources=true \ No newline at end of file +android.enableUnitTestBinaryResources=true From a8ebcb890c5bb4a5a91df88ff24b0e1bf3b3b2fe Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 13 Feb 2020 13:55:39 +0200 Subject: [PATCH 073/185] Revert "[sku] append sku token to offline download requests" (#173) This reverts commit c275ad2e6d7c59b94d24179195cfbd423449c506. --- .../mapbox/mapboxsdk/http/HttpRequestUrl.java | 16 +++++++--------- .../mapboxsdk/module/http/HttpRequestUrlTest.kt | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java index c5e372772..2a85bdee8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java @@ -6,8 +6,6 @@ import com.mapbox.mapboxsdk.Mapbox; public class HttpRequestUrl { - private static final StringBuilder requestBuilder = new StringBuilder(); - private HttpRequestUrl() { } @@ -24,20 +22,20 @@ public class HttpRequestUrl { * @return the adapted resource url */ public static String buildResourceUrl(@NonNull String host, String resourceUrl, int querySize, boolean offline) { - requestBuilder.setLength(0); // clear previous builder - requestBuilder.append(resourceUrl); if (isValidMapboxEndpoint(host)) { if (querySize == 0) { - requestBuilder.append("?"); + resourceUrl = resourceUrl + "?"; } else { - requestBuilder.append("&"); + resourceUrl = resourceUrl + "&"; } + // Only add SKU token to requests not tagged as "offline" usage. if (offline) { - requestBuilder.append("offline=true&"); + resourceUrl = resourceUrl + "offline=true"; + } else { + resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken(); } - requestBuilder.append("sku=").append(Mapbox.getSkuToken()); } - return requestBuilder.toString(); + return resourceUrl; } /** diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt index a50870f23..5db7b0b0f 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt @@ -20,14 +20,14 @@ class HttpRequestUrlTest { @Test fun testOfflineFlagMapboxCom() { - val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true&sku=foobar" + val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true" val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true) assertEquals(expected, actual) } @Test fun testOfflineFlagMapboxCn() { - val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true&sku=foobar" + val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true" val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true) assertEquals(expected, actual) } From 61a2f2bf4bd72ed6becc76add476adde71da8732 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 13 Feb 2020 15:16:39 +0200 Subject: [PATCH 074/185] [docs] Update changelog for v9.0.0 (#174) --- CHANGELOG.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 536e36c5d..f3b6a282a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,16 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## 9.0.0-beta.1 - January 24, 2019 +## 9.0.0 - February 13, 2020 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-beta.1...android-v9.0.0) since [Mapbox Maps SDK for Android v9.0.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-beta.1): +### Features + - Introduce lazy loading of view components on MapView [#141](https://github.com/mapbox/mapbox-gl-native-android/pull/141) + - Update Mapbox dependencies to AndroidX [#144](https://github.com/mapbox/mapbox-gl-native-android/pull/144) [#155](https://github.com/mapbox/mapbox-gl-native-android/pull/155) + +### Bug fixes + - Revert a commit that appended sku token to offline download requests [#173](https://github.com/mapbox/mapbox-gl-native-android/pull/173) + +## 9.0.0-beta.1 - January 24, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-alpha.1...android-v9.0.0-beta.1) since [Mapbox Maps SDK for Android v9.0.0-alpha.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-alpha.1): ### Features - Introduce a gesture setting to disable horizontal scrolling [#156](https://github.com/mapbox/mapbox-gl-native-android/pull/156) @@ -10,13 +19,13 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Introduce getVisibleCoordinateBounds method that allows for object reuse [#109](https://github.com/mapbox/mapbox-gl-native-android/pull/109) - Update Mapbox dependencies to AndroidX [#136](https://github.com/mapbox/mapbox-gl-native-android/pull/136) -## 8.6.2 - January 22, 2019 +## 8.6.2 - January 22, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.1...android-v8.6.2) since [Mapbox Maps SDK for Android v8.6.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.1): ### Bug fixes - Append sku token to offline download requests [#148](https://github.com/mapbox/mapbox-gl-native-android/pull/148) - Write user id synchronously to avoid null entries as part of the URL [#145](https://github.com/mapbox/mapbox-gl-native-android/pull/145) -## 8.6.1 - January 9, 2019 +## 8.6.1 - January 9, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.0...android-v8.6.1) since [Mapbox Maps SDK for Android v8.6.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.0): ### Bug fixes - Fixed native crash when using a GeoJsonSource when destructing the underlying GeoJSONVTData [#16106](https://github.com/mapbox/mapbox-gl-native/pull/16106). From 205ddee44045851fafbbd8ee797ece5032e213c9 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 13 Feb 2020 17:02:16 +0200 Subject: [PATCH 075/185] [docs] Update changelog for v9.0.0 after bumping gl-native. (#176) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b6a282a..18c0dcaab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Update Mapbox dependencies to AndroidX [#144](https://github.com/mapbox/mapbox-gl-native-android/pull/144) [#155](https://github.com/mapbox/mapbox-gl-native-android/pull/155) ### Bug fixes + - Fixed a bug that would cause `symbol-sort-key` not equally sort icon and text [#16023](https://github.com/mapbox/mapbox-gl-native/pull/16023) - Revert a commit that appended sku token to offline download requests [#173](https://github.com/mapbox/mapbox-gl-native-android/pull/173) ## 9.0.0-beta.1 - January 24, 2020 From 1366078200ef04b54a24bd1bc51f3ea50dac6deb Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Mon, 10 Feb 2020 22:28:14 +0200 Subject: [PATCH 076/185] [deps] Bump GL Native to master And update the buildsystem to reflect the changes. --- gradle/native-build.gradle | 4 ++-- vendor/mapbox-gl-native | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index eef917c70..48d430fda 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -21,7 +21,7 @@ ext.nativeBuild = { nativeTargets -> if (abi != 'none') { externalNativeBuild { cmake { - path "../vendor/mapbox-gl-native/next/CMakeLists.txt" + path "../vendor/mapbox-gl-native/CMakeLists.txt" version "3.10.2" } } @@ -63,4 +63,4 @@ ext.nativeBuild = { nativeTargets -> } } } -} \ No newline at end of file +} diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 3ea459233..a23100586 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 3ea459233a60ee737d0b637582f94024f3763797 +Subproject commit a23100586098c2d44682444cdd31001f1eba5859 From 6109d74b8a7c252dae380eb4c1de7a802e7d17db Mon Sep 17 00:00:00 2001 From: tobrun Date: Tue, 18 Feb 2020 14:01:17 +0100 Subject: [PATCH 077/185] [build] remove buck, update to latest gl-native --- .circleci/config.yml | 35 +---- misc/buck/.buckconfig | 15 --- misc/buck/mapbox-gl-native/Android.mk | 4 - misc/buck/mapbox-gl-native/Application.mk | 2 - misc/buck/mapbox-gl-native/BUCK | 140 -------------------- misc/buck/mapbox-gl-native/include | 1 - misc/buck/mapbox-gl-native/mapbox-gl-native | 1 - misc/buck/mapbox-gl-native/platform | 1 - misc/buck/mapbox-gl-native/sdk | 1 - misc/buck/mapbox-gl-native/src | 1 - misc/buck/mapbox-gl-native/vendor | 1 - misc/buck/mapbox-gl-native/vendor-android | 1 - vendor/mapbox-gl-native | 2 +- 13 files changed, 2 insertions(+), 203 deletions(-) delete mode 100644 misc/buck/.buckconfig delete mode 100644 misc/buck/mapbox-gl-native/Android.mk delete mode 100644 misc/buck/mapbox-gl-native/Application.mk delete mode 100644 misc/buck/mapbox-gl-native/BUCK delete mode 120000 misc/buck/mapbox-gl-native/include delete mode 120000 misc/buck/mapbox-gl-native/mapbox-gl-native delete mode 120000 misc/buck/mapbox-gl-native/platform delete mode 120000 misc/buck/mapbox-gl-native/sdk delete mode 120000 misc/buck/mapbox-gl-native/src delete mode 120000 misc/buck/mapbox-gl-native/vendor delete mode 120000 misc/buck/mapbox-gl-native/vendor-android diff --git a/.circleci/config.yml b/.circleci/config.yml index 4d8d3f482..3afb5a441 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,16 +4,8 @@ workflows: version: 2 mapbox-gl-native-android: jobs: - - android-debug-arm-v7-buck - android-arm-template: name: android-debug-arm-v8 - - android-arm-template: - name: android-gnustl-arm-v7 - stl: gnustl_shared - firebase_device_id: "flo" - firebase_device_os: "21" - image: android-ndk-r17c:1d5db0eb34 - abi: arm-v7 - android-release: filters: tags: @@ -345,29 +337,4 @@ jobs: make run-android-upload-to-artifactory fi fi - - generate-api-javadoc - # ------------------------------------------------------------------------------ - android-debug-arm-v7-buck: - docker: - - image: mbgl/android-ndk-r17c-buck:07c5ef2e71 - working_directory: /src - environment: - LIBSYSCONFCPUS: 2 - JOBS: 2 - BUILDTYPE: Debug - ANDROID_NDK: /android/sdk/ndk-bundle - steps: - - checkout - - npm-install - - run: - name: Checkout submodules - command: | - git submodule update --init --recursive - - npm-install-vendor - - prepare-environment - - run: - name: Build Android library - command: | - cd misc/buck - buck build mapbox-gl-native:android-core - # ------------------------------------------------------------------------------ \ No newline at end of file + - generate-api-javadoc \ No newline at end of file diff --git a/misc/buck/.buckconfig b/misc/buck/.buckconfig deleted file mode 100644 index f8d656612..000000000 --- a/misc/buck/.buckconfig +++ /dev/null @@ -1,15 +0,0 @@ -[ndk] -cpu_abis = armv7 -compiler = clang -app_platform = android-14 - -[project] -ignore = .git -allow_symlinks = allow - -[cxx] -default_platform = iphonesimulator-x86_64 - -[apple] -iphonesimulator_target_sdk_version = 9.0 -iphoneos_target_sdk_version = 9.0 \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/Android.mk b/misc/buck/mapbox-gl-native/Android.mk deleted file mode 100644 index ba1e2dd70..000000000 --- a/misc/buck/mapbox-gl-native/Android.mk +++ /dev/null @@ -1,4 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_MODULE := android-core -include $(BUILD_SHARED_LIBRARY) diff --git a/misc/buck/mapbox-gl-native/Application.mk b/misc/buck/mapbox-gl-native/Application.mk deleted file mode 100644 index a11b28deb..000000000 --- a/misc/buck/mapbox-gl-native/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_ABI := armeabi-v7a -APP_PLATFORM := android-14 diff --git a/misc/buck/mapbox-gl-native/BUCK b/misc/buck/mapbox-gl-native/BUCK deleted file mode 100644 index 30695821e..000000000 --- a/misc/buck/mapbox-gl-native/BUCK +++ /dev/null @@ -1,140 +0,0 @@ -# BUILD FILE SYNTAX: SKYLARK - -import json - -mbgl_base_path = get_base_path() or '.' -android_base_path = '../../' - -def mbgl_load_file_lists(*argv): - merged = dict(sources = [], public_headers = {}, private_headers = {}) - for arg in argv: - filename = mbgl_base_path + '/' + arg + '-files.json' - add_build_file_dep('//' + filename) - files = json.load(open(filename)) - merged['public_headers'].update(files['public_headers']) - merged['private_headers'].update(files['private_headers']) - merged['sources'] += files['sources'] - return merged - -def android_load_file_lists(*argv): - merged = dict(sources = [], public_headers = {}, private_headers = {}) - for arg in argv: - filename = '../../' + arg + '-files.json' - add_build_file_dep('//' + filename) - files = json.load(open(filename)) - merged['public_headers'].update(files['public_headers']) - merged['private_headers'].update(files['private_headers']) - merged['sources'] += files['sources'] - return merged - -mbgl = dict( - core = mbgl_load_file_lists('src/core', 'platform/default/filesource'), - android = android_load_file_lists('core', 'filesource'), - deps = [], -) - -def mbgl_vendor_library(name): - files = mbgl_load_file_lists('vendor/' + name) - cxx_library( - name = "vendor-" + name, - header_namespace = "", - srcs = files['sources'], - headers = files['private_headers'], - exported_headers = files['public_headers'], - link_style = 'static', - compiler_flags = [ - "-Wno-tautological-unsigned-enum-zero-compare", - ], - ) - mbgl['deps'].append(':vendor-' + name) - -mbgl_vendor_library("icu") -mbgl_vendor_library("boost") -mbgl_vendor_library("cheap-ruler-cpp") -mbgl_vendor_library("earcut.hpp") -mbgl_vendor_library("eternal") -mbgl_vendor_library("geojson-vt-cpp") -mbgl_vendor_library("mapbox-base") -mbgl_vendor_library("sqlite") -mbgl_vendor_library("polylabel") -mbgl_vendor_library("protozero") -mbgl_vendor_library("shelf-pack-cpp") -mbgl_vendor_library("unique_resource") -mbgl_vendor_library("vector-tile") -mbgl_vendor_library("wagyu") - -cxx_library( - name = "core", - - srcs = mbgl['core']['sources'], - platform_srcs = [ - ("android", mbgl['android']['sources']), - ], - - header_namespace = "", - headers = mbgl['core']['private_headers'], - exported_headers = mbgl['core']['public_headers'], - platform_headers = [ - ("android", mbgl['android']['private_headers']) - ], - exported_platform_headers = [ - ("android", mbgl['android']['public_headers']), - ], - - compiler_flags = [ - "-std=c++14", - "-g", - "-Wall", - "-Wextra", - "-Werror", - "-Wno-unused-variable", - "-Wno-unused-parameter", - "-Wno-c++11-narrowing", - "-Wno-tautological-constant-compare", - "-fexceptions", - "-ftemplate-depth=1024", - "-frtti", - ], - - preprocessor_flags = [ - "-DMBGL_USE_GLES2=1", - "-DMBGL_VERSION_REV=\"standalone\"", - "-DRAPIDJSON_HAS_STDSTRING=1", - ], - exported_platform_linker_flags = [ - ("android", [ - "-lz", - "-lEGL", - "-lGLESv2", - "-landroid", - "-ljnigraphics", - "-llog", - "-fvisibility=hidden", - "-Wl,--icf=safe", - "-Wl,--version-script=" + android_base_path + "version-script" - ]), - ], - - visibility = ["PUBLIC"], - deps = mbgl['deps'], - soname = "libmapbox-gl.$(ext)", -) - -ndk_library( - name = "android-core", - deps = [ ":core" ], - flags = [ - "NDK_APPLICATION_MK=$(env PWD)/" + mbgl_base_path + "/Application.mk", - ], -) - -android_manifest( - name = 'android-manifest', - skeleton = 'sdk/src/main/AndroidManifest.xml', -) - -android_library( - name = "android", - deps = [ ":android-core" ], - manifest = ":android-manifest", -) \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/include b/misc/buck/mapbox-gl-native/include deleted file mode 120000 index aabe3d4b8..000000000 --- a/misc/buck/mapbox-gl-native/include +++ /dev/null @@ -1 +0,0 @@ -../../../vendor/mapbox-gl-native/include \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/mapbox-gl-native b/misc/buck/mapbox-gl-native/mapbox-gl-native deleted file mode 120000 index e0ea80599..000000000 --- a/misc/buck/mapbox-gl-native/mapbox-gl-native +++ /dev/null @@ -1 +0,0 @@ -../../../vendor/mapbox-gl-native \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/platform b/misc/buck/mapbox-gl-native/platform deleted file mode 120000 index d05709529..000000000 --- a/misc/buck/mapbox-gl-native/platform +++ /dev/null @@ -1 +0,0 @@ -../../../vendor/mapbox-gl-native/platform \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/sdk b/misc/buck/mapbox-gl-native/sdk deleted file mode 120000 index 468e979db..000000000 --- a/misc/buck/mapbox-gl-native/sdk +++ /dev/null @@ -1 +0,0 @@ -../../../MapboxGLAndroidSDK \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/src b/misc/buck/mapbox-gl-native/src deleted file mode 120000 index 86b9c406a..000000000 --- a/misc/buck/mapbox-gl-native/src +++ /dev/null @@ -1 +0,0 @@ -../../../vendor/mapbox-gl-native/src \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/vendor b/misc/buck/mapbox-gl-native/vendor deleted file mode 120000 index 8272665fb..000000000 --- a/misc/buck/mapbox-gl-native/vendor +++ /dev/null @@ -1 +0,0 @@ -../../../vendor/mapbox-gl-native/vendor \ No newline at end of file diff --git a/misc/buck/mapbox-gl-native/vendor-android b/misc/buck/mapbox-gl-native/vendor-android deleted file mode 120000 index c73e2c9ac..000000000 --- a/misc/buck/mapbox-gl-native/vendor-android +++ /dev/null @@ -1 +0,0 @@ -../../../vendor \ No newline at end of file diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index a23100586..a551f70c6 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit a23100586098c2d44682444cdd31001f1eba5859 +Subproject commit a551f70c6da8973f23e10cf19b630376553ab699 From 18264df98db09a3588966981d22d06fed95da9be Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 19 Feb 2020 08:52:39 +0800 Subject: [PATCH 078/185] Add expression in. (#171) * Add expression in. * Add test for expression in. --- .../style/expressions/Expression.java | 36 +++++++++++++++++++ .../style/expressions/ExpressionTest.java | 22 ++++++++++++ .../activity/style/RuntimeStyleActivity.java | 34 ++++++++++++++++++ .../src/main/res/menu/menu_runtime_style.xml | 4 +++ .../src/main/res/values/actions.xml | 1 + 5 files changed, 97 insertions(+) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index c03bb05b4..71775486f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -1536,6 +1536,42 @@ public class Expression { return at(literal(number), expression); } + /** + * Retrieves whether an item exists in an array or a substring exists in a string. + * + * @param needle the item expression + * @param haystack the array or string expression + * @return true if exists. + * @see Style specification + */ + public static Expression in(@NonNull Expression needle, @NonNull Expression haystack) { + return new Expression("in", needle, haystack); + } + + /** + * Retrieves whether an item exists in an array or a substring exists in a string. + * + * @param needle the item expression + * @param haystack the array or string expression + * @return true if exists. + * @see Style specification + */ + public static Expression in(@NonNull Number needle, @NonNull Expression haystack) { + return new Expression("in", literal(needle), haystack); + } + + /** + * Retrieves whether an item exists in an array or a substring exists in a string. + * + * @param needle the item expression + * @param haystack the array or string expression + * @return true if exists. + * @see Style specification + */ + public static Expression in(@NonNull String needle, @NonNull Expression haystack) { + return new Expression("in", literal(needle), haystack); + } + /** * Retrieves a property value from the current feature's properties, * or from another object if a second argument is provided. diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java index fe91da8d5..ca35c648e 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java @@ -48,6 +48,7 @@ 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.in; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; import static com.mapbox.mapboxsdk.style.expressions.Expression.isSupportedScript; import static com.mapbox.mapboxsdk.style.expressions.Expression.length; @@ -446,6 +447,27 @@ public class ExpressionTest { assertTrue("expression should match", Arrays.deepEquals(expected, actual)); } + @Test + public void testInString() throws Exception { + Object[] expected = new Object[] {"in", "one", "onetwo"}; + Object[] actual = in(literal("one"), literal("onetwo")).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + + @Test + public void testInNumber() throws Exception { + Object[] expected = new Object[] {"in", 1f, new Object[] {"literal", new Object[] {1f, 2f}}}; + Object[] actual = in(literal(1f), literal(new Object[] {1f, 2f})).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + + @Test + public void testInArray() throws Exception { + Object[] expected = new Object[] {"in", "one", new Object[] {"literal", new Object[] {"one", "two"}}}; + Object[] actual = in(literal("one"), 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", 3f, new Object[] {"literal", new Object[] {"one", "two"}}}; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index 1ae2499c6..b9c72288f 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -43,10 +43,12 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; import static com.mapbox.mapboxsdk.style.expressions.Expression.gte; +import static com.mapbox.mapboxsdk.style.expressions.Expression.in; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; import static com.mapbox.mapboxsdk.style.expressions.Expression.lt; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; +import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP; @@ -65,6 +67,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; /** @@ -198,6 +201,9 @@ public class RuntimeStyleActivity extends AppCompatActivity { case R.id.action_fill_filter: styleFillFilterLayer(); return true; + case R.id.action_textsize_filter: + styleTextSizeFilterLayer(); + return true; case R.id.action_line_filter: styleLineFilterLayer(); return true; @@ -524,6 +530,34 @@ public class RuntimeStyleActivity extends AppCompatActivity { }, 2000); } + private void styleTextSizeFilterLayer() { + mapboxMap.setStyle(new Style.Builder().fromUri("asset://fill_filter_style.json")); + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(31, -100), 3)); + + Handler handler = new Handler(getMainLooper()); + handler.postDelayed(() -> { + if (mapboxMap == null) { + return; + } + + Timber.d("Styling text size fill layer"); + SymbolLayer states = (SymbolLayer) mapboxMap.getStyle().getLayer("state-label-lg"); + + if (states != null) { + states.setProperties( + textSize(switchCase( + in(get("name"), literal("Texas")), literal(25.0f), + in(get("name"), literal(new Object[] {"California","Illinois"})), literal(25.0f), + literal(6.0f) // default value + ) + ) + ); + } else { + Toast.makeText(RuntimeStyleActivity.this, "No states layer in this style", Toast.LENGTH_SHORT).show(); + } + }, 2000); + } + private void styleLineFilterLayer() { mapboxMap.setStyle(new Style.Builder().fromUri("asset://line_filter_style.json")); mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(40, -97), 5)); diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml index e3d7c8cfa..b302568fa 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml @@ -58,6 +58,10 @@ android:id="@+id/action_fill_filter" android:title="@string/apply_filtered_fill" mapbox:showAsAction="never" /> + Change the water color on zoom Custom tiles Apply filtered fill + Apply text size fill Apply filtered line Apply numeric fill filter Bring water to front From 2e9f02140cec06ea6fd50389536df1caf9aa88aa Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 25 Feb 2020 09:24:04 +0800 Subject: [PATCH 079/185] Add runtime API for setting tile prefetch delta for Source class (#184) * Add runtime API for setting tile prefetch delta for Source class * Use Integer as param. * Update gl native submodule. --- .../mapboxsdk/style/sources/Source.java | 32 +++++++++++++++++++ .../testapp/style/CustomGeometrySourceTest.kt | 17 ++++++++++ vendor/mapbox-gl-native | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index 7d2c409b0..bc70cb70a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -2,6 +2,8 @@ package com.mapbox.mapboxsdk.style.sources; import androidx.annotation.Keep; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.utils.ThreadUtils; @@ -68,6 +70,28 @@ public abstract class Source { return nativeGetAttribution(); } + /** + * Retrieve current pre-fetching zoom delta. + * + * @return current zoom delta or null if not set. + */ + @Nullable + public Integer getPrefetchZoomDelta() { + return nativeGetPrefetchZoomDelta(); + } + + /** + * Set the tile pre-fetching zoom delta for current source. Pre-fetching makes sure that a low-resolution + * tile at the (current_zoom_level - delta) is rendered as soon as possible at the + * expense of a little bandwidth. + * If delta has not been set or set to null, it will use the value in MapboxMap instance. + * + * @param delta zoom delta + */ + public void setPrefetchZoomDelta(@Nullable Integer delta) { + nativeSetPrefetchZoomDelta(delta); + } + /** * Internal use * @@ -85,6 +109,14 @@ public abstract class Source { @Keep protected native String nativeGetAttribution(); + @NonNull + @Keep + protected native Integer nativeGetPrefetchZoomDelta(); + + @NonNull + @Keep + protected native void nativeSetPrefetchZoomDelta(Integer delta); + public void setDetached() { detached = true; } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index 359dc6469..cc4a04ecd 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -14,6 +14,7 @@ import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LA import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_SOURCE import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils import org.junit.Assert +import org.junit.Assert.* import org.junit.Test class CustomGeometrySourceTest : BaseTest() { @@ -66,4 +67,20 @@ class CustomGeometrySourceTest : BaseTest() { }.count() == THREAD_POOL_LIMIT) } } + + @Test + fun sourceZoomDeltaTest() { + validateTestSetup() + invoke(mapboxMap) { uiController, mapboxMap -> + mapboxMap.prefetchZoomDelta = 3 + mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let { + assertNull(it.prefetchZoomDelta) + it.prefetchZoomDelta = 5 + assertNotNull(it.prefetchZoomDelta) + assertEquals(5, it.prefetchZoomDelta!!) + it.prefetchZoomDelta = null + assertNull(it.prefetchZoomDelta) + } + } + } } \ No newline at end of file diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index a551f70c6..43c1aac7e 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit a551f70c6da8973f23e10cf19b630376553ab699 +Subproject commit 43c1aac7e800d5f1695fd08639a2db5c1e1dd1af From 65cf1d1cc7a0d63d9cccc3fc27825d7ee24b3d80 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 25 Feb 2020 09:25:18 +0800 Subject: [PATCH 080/185] Bump telemetry to 4.7.2 (#193) --- gradle/dependencies.gradle | 2 +- vendor/mapbox-events-android | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 6bccb5b05..65fffd5cb 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { versions = [ mapboxServices : '5.0.0', - mapboxTelemetry : '4.7.1', + mapboxTelemetry : '4.7.2', mapboxCore : '1.4.1', mapboxGestures : '0.6.0', mapboxAccounts : '0.7.0', diff --git a/vendor/mapbox-events-android b/vendor/mapbox-events-android index 24bb138ec..9b9ee5f01 160000 --- a/vendor/mapbox-events-android +++ b/vendor/mapbox-events-android @@ -1 +1 @@ -Subproject commit 24bb138eca7821d14932fffa1e7461f472212034 +Subproject commit 9b9ee5f0173db088071543e7fbb2b7dc7e0d6779 From 81189a98bc29416134fca351d8be75b21b11a718 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 28 Feb 2020 10:05:51 +0800 Subject: [PATCH 081/185] Add telemetry events classes to proguard (#195) --- MapboxGLAndroidSDK/proguard-rules.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MapboxGLAndroidSDK/proguard-rules.pro b/MapboxGLAndroidSDK/proguard-rules.pro index 1035bb01d..9367d296a 100644 --- a/MapboxGLAndroidSDK/proguard-rules.pro +++ b/MapboxGLAndroidSDK/proguard-rules.pro @@ -27,6 +27,9 @@ -keep class com.mapbox.geojson.** { *; } -dontwarn com.google.auto.value.** +# config for telemetry events +-keep class com.mapbox.mapboxsdk.module.telemetry.** + # config for additional notes -dontnote org.robolectric.Robolectric -dontnote libcore.io.Memory From 53f5015ca64290b3b891b40d5e3300b072396923 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 28 Feb 2020 14:53:45 +0800 Subject: [PATCH 082/185] Add telemetry events classes to proguard --- gradle/dependencies.gradle | 2 +- vendor/mapbox-events-android | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 65fffd5cb..daca6ecbc 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { versions = [ mapboxServices : '5.0.0', - mapboxTelemetry : '4.7.2', + mapboxTelemetry : '4.7.3', mapboxCore : '1.4.1', mapboxGestures : '0.6.0', mapboxAccounts : '0.7.0', diff --git a/vendor/mapbox-events-android b/vendor/mapbox-events-android index 9b9ee5f01..7945e61bc 160000 --- a/vendor/mapbox-events-android +++ b/vendor/mapbox-events-android @@ -1 +1 @@ -Subproject commit 9b9ee5f0173db088071543e7fbb2b7dc7e0d6779 +Subproject commit 7945e61bccc1df3b04ca2e80cb25459dfeea01dd From 17b19b3b4a04302ee50ea9044c46cebe1fb8756d Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 28 Feb 2020 18:17:08 +0800 Subject: [PATCH 083/185] Add min and max pitch options (#199) * Add min and max pitch options * Add min and max pitch into attrs * Update gl-native submodule --- .../mapboxsdk/constants/MapboxConstants.java | 10 +++ .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 60 ++++++++++++++++++ .../mapboxsdk/maps/MapboxMapOptions.java | 63 +++++++++++++++++++ .../com/mapbox/mapboxsdk/maps/NativeMap.java | 15 ++++- .../mapbox/mapboxsdk/maps/NativeMapView.java | 53 ++++++++++++++-- .../com/mapbox/mapboxsdk/maps/Transform.java | 26 ++++++++ .../src/main/res-public/values/public.xml | 4 ++ .../src/main/res/values/attrs.xml | 4 ++ .../mapboxsdk/maps/MapboxMapOptionsTest.java | 14 +++++ .../mapbox/mapboxsdk/maps/MapboxMapTest.kt | 12 ++++ .../mapbox/mapboxsdk/maps/TransformTest.kt | 14 +++++ .../mapboxsdk/maps/NativeMapViewTest.kt | 18 ++++++ vendor/mapbox-gl-native | 2 +- 13 files changed, 287 insertions(+), 8 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 42aa9206e..ce7a919f3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -144,6 +144,16 @@ public class MapboxConstants { */ public static final float MAXIMUM_ZOOM = 25.5f; + /** + * The currently supported minimum pitch level. + */ + public static final float MINIMUM_PITCH = 0.0f; + + /** + * The currently supported maximum pitch level. + */ + public static final float MAXIMUM_PITCH = 60.0f; + /** * The currently supported maximum tilt value. */ diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 970ea9801..286e48fe8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -365,6 +365,66 @@ public final class MapboxMap { return transform.getMaxZoom(); } + // + // MinPitch + // + + /** + *

    + * Sets the minimum Pitch the map can be displayed at. + *

    + * + *

    + * The default and lower bound for minPitch Pitch is 0. + *

    + * @param minPitch The new minimum Pitch. + */ + public void setMinPitchPreference( + @FloatRange(from = MapboxConstants.MINIMUM_PITCH, to = MapboxConstants.MAXIMUM_PITCH) double minPitch) { + transform.setMinPitch(minPitch); + } + + /** + *

    + * Gets the minimum Pitch the map can be displayed at. + *

    + * + * @return The minimum Pitch. + */ + public double getMinPitch() { + return transform.getMinPitch(); + } + + // + // MaxPitch + // + + /** + *

    + * Sets the maximum Pitch the map can be displayed at. + *

    + *

    + * The default and upper bound for maximum Pitch is 60. + *

    + * + * @param maxPitch The new maximum Pitch. + */ + public void setMaxPitchPreference(@FloatRange(from = MapboxConstants.MINIMUM_PITCH, + to = MapboxConstants.MAXIMUM_PITCH) double maxPitch) { + transform.setMaxPitch(maxPitch); + } + + /** + *

    + * Gets the maximum Pitch the map can be displayed at. + *

    + * + * @return The maximum Pitch. + */ + public double getMaxPitch() { + return transform.getMaxPitch(); + } + // // UiSettings // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 3a2040095..bb136bfbf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -64,6 +64,8 @@ public class MapboxMapOptions implements Parcelable { private double minZoom = MapboxConstants.MINIMUM_ZOOM; private double maxZoom = MapboxConstants.MAXIMUM_ZOOM; + private double minPitch = MapboxConstants.MINIMUM_PITCH; + private double maxPitch = MapboxConstants.MAXIMUM_PITCH; private boolean rotateGesturesEnabled = true; private boolean scrollGesturesEnabled = true; @@ -127,6 +129,8 @@ public class MapboxMapOptions implements Parcelable { minZoom = in.readDouble(); maxZoom = in.readDouble(); + minPitch = in.readDouble(); + maxPitch = in.readDouble(); rotateGesturesEnabled = in.readByte() != 0; scrollGesturesEnabled = in.readByte() != 0; @@ -210,6 +214,10 @@ public class MapboxMapOptions implements Parcelable { MapboxConstants.MAXIMUM_ZOOM)); mapboxMapOptions.minZoomPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoomMin, MapboxConstants.MINIMUM_ZOOM)); + mapboxMapOptions.maxPitchPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraPitchMax, + MapboxConstants.MAXIMUM_PITCH)); + mapboxMapOptions.minPitchPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraPitchMin, + MapboxConstants.MINIMUM_PITCH)); mapboxMapOptions.compassEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiCompass, true)); mapboxMapOptions.compassGravity(typedArray.getInt(R.styleable.mapbox_MapView_mapbox_uiCompassGravity, @@ -378,6 +386,31 @@ public class MapboxMapOptions implements Parcelable { return this; } + + /** + * Specifies the used minimum pitch for a map view. + * + * @param minPitch Pitch to be used + * @return This + */ + @NonNull + public MapboxMapOptions minPitchPreference(double minPitch) { + this.minPitch = minPitch; + return this; + } + + /** + * Specifies the used maximum pitch for a map view. + * + * @param maxPitch Pitch to be used + * @return This + */ + @NonNull + public MapboxMapOptions maxPitchPreference(double maxPitch) { + this.maxPitch = maxPitch; + return this; + } + /** * Specifies the visibility state of a mapbox_compass_icon for a map view. * @@ -854,6 +887,24 @@ public class MapboxMapOptions implements Parcelable { return maxZoom; } + /** + * Get the current configured min pitch for a map view. + * + * @return Mininum pitch to be used. + */ + public double getMinPitchPreference() { + return minPitch; + } + + /** + * Get the current configured maximum pitch for a map view. + * + * @return Maximum pitch to be used. + */ + public double getMaxPitchPreference() { + return maxPitch; + } + /** * Get the current configured visibility state for mapbox_compass_icon for a map view. * @@ -1132,6 +1183,8 @@ public class MapboxMapOptions implements Parcelable { dest.writeDouble(minZoom); dest.writeDouble(maxZoom); + dest.writeDouble(minPitch); + dest.writeDouble(maxPitch); dest.writeByte((byte) (rotateGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (scrollGesturesEnabled ? 1 : 0)); @@ -1204,6 +1257,12 @@ public class MapboxMapOptions implements Parcelable { if (Double.compare(options.maxZoom, maxZoom) != 0) { return false; } + if (Double.compare(options.minPitch, minPitch) != 0) { + return false; + } + if (Double.compare(options.maxPitch, maxPitch) != 0) { + return false; + } if (rotateGesturesEnabled != options.rotateGesturesEnabled) { return false; } @@ -1292,6 +1351,10 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(maxZoom); result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minPitch); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxPitch); + result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (rotateGesturesEnabled ? 1 : 0); result = 31 * result + (scrollGesturesEnabled ? 1 : 0); result = 31 * result + (horizontalScrollGesturesEnabled ? 1 : 0); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index a601096a6..81ff438c6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -3,9 +3,6 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; @@ -24,6 +21,10 @@ import com.mapbox.mapboxsdk.style.sources.Source; import java.util.List; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + interface NativeMap { // @@ -85,6 +86,14 @@ interface NativeMap { double getMaxZoom(); + void setMinPitch(double pitch); + + double getMinPitch(); + + void setMaxPitch(double pitch); + + double getMaxPitch(); + void resetZoom(); void rotateBy(double sx, double sy, double ex, double ey, long duration); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index dfeac768c..05ebf36d6 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -5,10 +5,6 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.os.Handler; -import androidx.annotation.IntRange; -import androidx.annotation.Keep; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.text.TextUtils; import com.mapbox.geojson.Feature; @@ -40,6 +36,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import androidx.annotation.IntRange; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + // Class that wraps the native methods for convenience final class NativeMapView implements NativeMap { @@ -370,6 +371,38 @@ final class NativeMapView implements NativeMap { return nativeGetMaxZoom(); } + @Override + public void setMinPitch(double pitch) { + if (checkState("setMinPitch")) { + return; + } + nativeSetMinPitch(pitch); + } + + @Override + public double getMinPitch() { + if (checkState("getMinPitch")) { + return 0; + } + return nativeGetMinPitch(); + } + + @Override + public void setMaxPitch(double pitch) { + if (checkState("setMaxPitch")) { + return; + } + nativeSetMaxPitch(pitch); + } + + @Override + public double getMaxPitch() { + if (checkState("getMaxPitch")) { + return 0; + } + return nativeGetMaxPitch(); + } + @Override public void rotateBy(double sx, double sy, double ex, double ey, long duration) { @@ -1205,6 +1238,18 @@ final class NativeMapView implements NativeMap { @Keep private native double nativeGetMaxZoom(); + @Keep + private native void nativeSetMinPitch(double pitch); + + @Keep + private native double nativeGetMinPitch(); + + @Keep + private native void nativeSetMaxPitch(double pitch); + + @Keep + private native double nativeGetMaxPitch(); + @Keep private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index 9e8fb8420..efd3efe8c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -61,6 +61,8 @@ public final class Transform implements MapView.OnCameraDidChangeListener { } setMinZoom(options.getMinZoomPreference()); setMaxZoom(options.getMaxZoomPreference()); + setMinPitch(options.getMinPitchPreference()); + setMaxPitch(options.getMaxPitchPreference()); } // @@ -338,4 +340,28 @@ public final class Transform implements MapView.OnCameraDidChangeListener { double getMaxZoom() { return nativeMap.getMaxZoom(); } + + void setMinPitch(double minPitch) { + if ((minPitch < MapboxConstants.MINIMUM_PITCH) || (minPitch > MapboxConstants.MAXIMUM_PITCH)) { + Logger.e(TAG, String.format("Not setting minPitchPreference, value is in unsupported range: %s", minPitch)); + return; + } + nativeMap.setMinPitch(minPitch); + } + + double getMinPitch() { + return nativeMap.getMinPitch(); + } + + void setMaxPitch(double maxPitch) { + if ((maxPitch < MapboxConstants.MINIMUM_PITCH) || (maxPitch > MapboxConstants.MAXIMUM_PITCH)) { + Logger.e(TAG, String.format("Not setting maxPitchPreference, value is in unsupported range: %s", maxPitch)); + return; + } + nativeMap.setMaxPitch(maxPitch); + } + + double getMaxPitch() { + return nativeMap.getMaxPitch(); + } } diff --git a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 83c25432d..b79a5494d 100644 --- a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -28,6 +28,10 @@ + + + + diff --git a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index a38f6e9fb..2b9022c96 100644 --- a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -23,6 +23,10 @@ + + + + diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index b72b34210..ae98ee256 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -121,6 +121,20 @@ public class MapboxMapOptionsTest { assertNotEquals(2.0f, new MapboxMapOptions().maxZoomPreference(5.0f).getMaxZoomPreference(), DELTA); } + @Test + public void testMinPitch() { + assertEquals(MapboxConstants.MINIMUM_PITCH, new MapboxMapOptions().getMinPitchPreference(), DELTA); + assertEquals(5.0f, new MapboxMapOptions().minPitchPreference(5.0f).getMinPitchPreference(), DELTA); + assertNotEquals(2.0f, new MapboxMapOptions().minPitchPreference(5.0f).getMinPitchPreference(), DELTA); + } + + @Test + public void testMaxPitch() { + assertEquals(MapboxConstants.MAXIMUM_PITCH, new MapboxMapOptions().getMaxPitchPreference(), DELTA); + assertEquals(5.0f, new MapboxMapOptions().maxPitchPreference(5.0f).getMaxPitchPreference(), DELTA); + assertNotEquals(2.0f, new MapboxMapOptions().maxPitchPreference(5.0f).getMaxPitchPreference(), DELTA); + } + @Test public void testTiltGesturesEnabled() { assertTrue(new MapboxMapOptions().getTiltGesturesEnabled()); diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt index 6647fe559..d78579223 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -113,6 +113,18 @@ class MapboxMapTest { verify { transform.maxZoom = 10.0 } } + @Test + fun testMinPitch() { + mapboxMap.setMinPitchPreference(10.0) + verify { transform.minPitch = 10.0 } + } + + @Test + fun testMaxPitch() { + mapboxMap.setMaxPitchPreference(10.0) + verify { transform.maxPitch = 10.0 } + } + @Test fun testFpsListener() { val fpsChangedListener = mockk() diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt index fddf7eeaf..d157687e0 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt @@ -30,6 +30,8 @@ class TransformTest { every { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) } answers {} every { nativeMapView.minZoom = any() } answers {} every { nativeMapView.maxZoom = any() } answers {} + every { nativeMapView.minPitch = any() } answers {} + every { nativeMapView.maxPitch = any() } answers {} } @Test @@ -157,6 +159,18 @@ class TransformTest { verify { nativeMapView.maxZoom = 10.0 } } + @Test + fun testMinPitch() { + transform.minPitch = 10.0 + verify { nativeMapView.minPitch = 10.0 } + } + + @Test + fun testMaxPitch() { + transform.maxPitch = 10.0 + verify { nativeMapView.maxPitch = 10.0 } + } + @Test fun testCancelNotInvokedFromOnFinish() { val slot = slot() diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt index fd4cb228d..cc614fbb9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt @@ -268,6 +268,24 @@ class NativeMapViewTest : AppCenter() { assertEquals("Max zoom should match", expected, actual) } + @Test + @UiThreadTest + fun testSetMinPitch() { + val expected = 60.0 + nativeMapView.minPitch = expected + val actual = nativeMapView.minPitch + assertEquals("Min Pitch should match", expected, actual, 0.01) + } + + @Test + @UiThreadTest + fun testSetMaxPitch() { + val expected = 60.0 + nativeMapView.maxPitch = expected + val actual = nativeMapView.maxPitch + assertEquals("Max Pitch should match", expected, actual, 0.01) + } + @Test @UiThreadTest fun testGetProjectedMetersAtLatitude() { diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 43c1aac7e..e0c2b3e77 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 43c1aac7e800d5f1695fd08639a2db5c1e1dd1af +Subproject commit e0c2b3e771bdd4a23bb7442240ccc3dbf1c1c57a From bf6f00fae65e5c3e34a0831f889271f9b6234302 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Fri, 28 Feb 2020 10:31:58 -0800 Subject: [PATCH 084/185] Bumped README snapshot to 9.1.0 (#167) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b3fb758e..cf4f1e7a0 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Instead of using the latest stable release of the Maps SDK for Android, you can ```java // Mapbox SDK dependency -implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.5.0-SNAPSHOT' +implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.1.0-SNAPSHOT' ``` You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies: From 0046be2e0573d457b3f2736b25ecdf959210ee3a Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 28 Feb 2020 11:04:34 +0100 Subject: [PATCH 085/185] [docs] updat changelog for v9.1.0-alpha.1 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18c0dcaab..c8f58422d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 9.1.0-alpha.1 - February 28, 2020 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.1.0-alpha.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): +### Features + - Introduce ability to set prefetching delta for sources, allows to control over tile prefetching on a per source basis [#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184) + - Introduce support for `in` expression, determines whether an item exists in an array or a substring exists in a string. [#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171) + - Introduce option to pass intermediate points for smooth location component animation [#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166) + +### Bug fixes + - Fix proguard configuration to prevent obfuscation of telemetry event classes [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) + - Fix offline region download freezing [#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230) + - Update mapbox-events-android to v4.7.3 [#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201) + ## 9.0.0 - February 13, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-beta.1...android-v9.0.0) since [Mapbox Maps SDK for Android v9.0.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-beta.1): ### Features From 60666fa75def9ef75d0e2b51323c75669549082d Mon Sep 17 00:00:00 2001 From: Chloe Krawczyk Date: Fri, 28 Feb 2020 08:02:00 -0800 Subject: [PATCH 086/185] add entry for min/max pitch option re-order entries by importance, tighten up some changelog entries, fix nits add additional entries from mapbox-gl-native changelog --- CHANGELOG.md | 58 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8f58422d..a1a1ca69e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,22 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## 9.1.0-alpha.1 - February 28, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.1.0-alpha.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): ### Features - - Introduce ability to set prefetching delta for sources, allows to control over tile prefetching on a per source basis [#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184) - - Introduce support for `in` expression, determines whether an item exists in an array or a substring exists in a string. [#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171) - - Introduce option to pass intermediate points for smooth location component animation [#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166) + - Introduce `in` expression for testing whether an item exists in an array or a substring exists in a string. ([#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171)) + - Introduce option to set the minimum and maximum pitch of a map. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) + - Introduce ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. ([#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184)) + - Introduce option to pass in intermediate points for a smooth `LocationComponent` animation. ([#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166)) + +### Performance improvements + - Improve the performance of loading a style that has many style images. ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) + - Fix a memory leak during zooming when `MapboxMapOptions.debugActive` is enabled. ([#15179](https://github.com/mapbox/mapbox-gl-native/issues/15179), fixed by [#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395)) ### Bug fixes - - Fix proguard configuration to prevent obfuscation of telemetry event classes [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) - - Fix offline region download freezing [#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230) - - Update mapbox-events-android to v4.7.3 [#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201) + - Fix issues that would cause an offline pack to stop downloading before completion. ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) + - Fix an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) + - Fix Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) + +### Other changes + - Update mapbox-events-android to v4.7.3. ([#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201)) ## 9.0.0 - February 13, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-beta.1...android-v9.0.0) since [Mapbox Maps SDK for Android v9.0.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-beta.1): @@ -159,7 +167,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Coalesce requests to the client for the same missing image [#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778) ## 8.4.0 - September 25, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): ### Bug fixes - Fixing a crash when `CameraPosition` padding is set when using `MapSnapshotter`. [#15699](https://github.com/mapbox/mapbox-gl-native/pull/15699) @@ -169,7 +177,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Migrate map feedback to GL JS–powered feedback form [#15623](https://github.com/mapbox/mapbox-gl-native/pull/15623) ## 8.4.0-beta.1 - September 19, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.2...android-v8.4.0-beta.1) since [Mapbox Maps SDK for Android v8.4.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.2): +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.2...android-v8.4.0-beta.1) since [Mapbox Maps SDK for Android v8.4.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.2): ### Bug fixes - Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. [#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581) @@ -193,7 +201,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Fixed a wrong variable assignment of `MapSnapshotter.Options.withApiBaseUri`. [#15642](https://github.com/mapbox/mapbox-gl-native/pull/15642) ## 8.4.0-alpha.2 - September 11, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1): +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1): ### Performance improvements - Newly loaded labels appear faster on the screen. [#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308) @@ -203,7 +211,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Other Changes - Bumped Java SDK dependency to 4.9.0-alpha.1 [#15570](https://github.com/mapbox/mapbox-gl-native/pull/15570) - + ## 8.4.0-alpha.1 - September 4, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.4.0-alpha.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): @@ -372,7 +380,7 @@ This release changes how offline tile requests are billed — they are now bille - Fix fill-extrusion layers always rendered above other layers [#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065) - Fix a bug where map panning would be blocked after a quick zoom gesture was attempted when quick zoom is set to be ignored by `UiSettings` preferences [#15093](https://github.com/mapbox/mapbox-gl-native/pull/15093) - Fix a bug where map panning would be blocked if double-tap is interrupted [#15103](https://github.com/mapbox/mapbox-gl-native/pull/15103) - + ### Minor features and improvements - Improve performance of queryRenderedFeatures by removing unnecessary iterations over vectors and unneeded layers [#14930](https://github.com/mapbox/mapbox-gl-native/pull/14930) - Decrease the minimum pixel distance between the current camera position and the target required to interpolate during camera animation [#15073](https://github.com/mapbox/mapbox-gl-native/pull/15073) @@ -380,7 +388,7 @@ This release changes how offline tile requests are billed — they are now bille - Throw configuration exception when accessing Mapbox services with an invalid token [#15081](https://github.com/mapbox/mapbox-gl-native/pull/15081) - Allow setting a null access token in the runtime [#15081](https://github.com/mapbox/mapbox-gl-native/pull/15081) - Ensure location shadow's gradient radius is greater than 0 [#15099](https://github.com/mapbox/mapbox-gl-native/pull/15099) - + ### Other Changes - Update okhttp to latest stable version that support pre lollipop (`3.12.3`) [#15087](https://github.com/mapbox/mapbox-gl-native/pull/15087) - Fix up "match" expressions docs with stop arguments [#15102](https://github.com/mapbox/mapbox-gl-native/pull/15102) @@ -393,10 +401,10 @@ This release changes how offline tile requests are billed — they are now bille ### Bug fixes - Fix style change transition regression caused by delayed setting of the updated layer properties [#15016](https://github.com/mapbox/mapbox-gl-native/pull/15016) - + ### Minor features and improvements - Include Hiragana and Katakana glyph ranges to LocalGlyphRasterizer [#15009](https://github.com/mapbox/mapbox-gl-native/pull/15009) - + ### Other Changes - Update CI image with NDK r20 [#15005](https://github.com/mapbox/mapbox-gl-native/pull/15005) @@ -404,7 +412,7 @@ This release changes how offline tile requests are billed — they are now bille [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.1.0...android-v8.2.0-alpha.1) since [Mapbox Maps SDK for Android v8.1.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.1.0): ### Bug fixes - - Fix `queryRenderedFeatues` bug caused by incorrect sort feature index calculation [#14884](https://github.com/mapbox/mapbox-gl-native/pull/14884) + - Fix `queryRenderedFeatues` bug caused by incorrect sort feature index calculation [#14884](https://github.com/mapbox/mapbox-gl-native/pull/14884) - Fix performance regression by switching back to a more compact line attributes layout [#14851](https://github.com/mapbox/mapbox-gl-native/pull/14851) - Fix a bug that restricted camera viewport after camera bounds were reset [#14882](https://github.com/mapbox/mapbox-gl-native/pull/14882) - Fix a bug that ignored floating point values during core to platform color conversion [#14954](https://github.com/mapbox/mapbox-gl-native/pull/14954) @@ -412,7 +420,7 @@ This release changes how offline tile requests are billed — they are now bille ### Minor features and improvements - Allow null updates to GeoJsonSource [#14898](https://github.com/mapbox/mapbox-gl-native/pull/14898) - + ### Other Changes - Add resource usage to HttpRequest, add offline query flag to HttpRequest [#14837](https://github.com/mapbox/mapbox-gl-native/pull/14837) @@ -497,21 +505,21 @@ Please see https://github.com/square/okhttp/issues/2679 for more information. ### Features - Option to provide custom values for location camera transition [#14606](https://github.com/mapbox/mapbox-gl-native/pull/14606) - + ### Bugs - Expose trackingGesturesManagement attribute [#14659](https://github.com/mapbox/mapbox-gl-native/pull/14659) - - Harden onLowMemory call, use atomic boolean for thread safe management of the render surface [#14622](https://github.com/mapbox/mapbox-gl-native/pull/14622) + - Harden onLowMemory call, use atomic boolean for thread safe management of the render surface [#14622](https://github.com/mapbox/mapbox-gl-native/pull/14622) - Normalize previous rotation values of the location animator [#14626](https://github.com/mapbox/mapbox-gl-native/pull/14626) ### Performance - Remove telemetry gesture event handling code [#14627](https://github.com/mapbox/mapbox-gl-native/pull/14627) - + ### Localisation - - Pull in Polish translation and updates to Czech and Hungarian [#14679](https://github.com/mapbox/mapbox-gl-native/pull/14679) + - Pull in Polish translation and updates to Czech and Hungarian [#14679](https://github.com/mapbox/mapbox-gl-native/pull/14679) ### Docs - Add javadoc to highlight incompatible onIdle event with snapshot api [#14621](https://github.com/mapbox/mapbox-gl-native/pull/14621) - + ## 7.4.0 - May 15, 2019 ### Features - Revert SKU token logic [#14594](https://github.com/mapbox/mapbox-gl-native/pull/14594) @@ -537,7 +545,7 @@ Please see https://github.com/square/okhttp/issues/2679 for more information. ### Build - Update mapbox java sdk to v4.7.0 [#14480](https://github.com/mapbox/mapbox-gl-native/pull/14480) - Update gestures library to v0.4.2 [#14524](https://github.com/mapbox/mapbox-gl-native/pull/14524) - + ### Docs - Clear up LocationComponent's z-index positioning docs [#14497](https://github.com/mapbox/mapbox-gl-native/pull/14497) @@ -566,19 +574,19 @@ Please see https://github.com/square/okhttp/issues/2679 for more information. - Introduce AccountsManager to support SKU tokens in API requests [#14404](https://github.com/mapbox/mapbox-gl-native/pull/14404) - Add MapEventFactory [#14309](https://github.com/mapbox/mapbox-gl-native/pull/14309) - Only perform thread checking in debug builds [#14293](https://github.com/mapbox/mapbox-gl-native/pull/14293) - + ### Build - Bump gestures library to v0.4.1 [#14435](https://github.com/mapbox/mapbox-gl-native/pull/14435) - Update mapbox java sdk to v4.6.0 [#14424](https://github.com/mapbox/mapbox-gl-native/pull/14424) - Bump telemetry to 4.4.1 [#14309](https://github.com/mapbox/mapbox-gl-native/pull/14309) - Program against NativeMap [#14412](https://github.com/mapbox/mapbox-gl-native/pull/14412) - + ## 7.3.2 - April 17, 2019 ## Bugs - Unify has surface state handling, allow querying after map resume [#14426](https://github.com/mapbox/mapbox-gl-native/pull/14426) ## 7.3.1 - April 12, 2019 -## Bugs +## Bugs - Harden renderer invocation when Activity is resumed [#14395](https://github.com/mapbox/mapbox-gl-native/pull/14395) - Check for Mapbox#INSTANCE when initializing the MapView [#14366](https://github.com/mapbox/mapbox-gl-native/pull/14366) - Disable binary programs shaders [#14298](https://github.com/mapbox/mapbox-gl-native/pull/14298) From c217a6117095e6eabdf4e9baeee734b72e3a65bf Mon Sep 17 00:00:00 2001 From: tobrun Date: Mon, 2 Mar 2020 11:33:33 +0100 Subject: [PATCH 087/185] [android] - update gl-native dependency to v1.3.1 release --- CHANGELOG.md | 20 ++++++++++---------- vendor/mapbox-gl-native | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1a1ca69e..840e7ce9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,22 +5,22 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## 9.1.0-alpha.1 - February 28, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.1.0-alpha.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): ### Features - - Introduce `in` expression for testing whether an item exists in an array or a substring exists in a string. ([#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171)) - - Introduce option to set the minimum and maximum pitch of a map. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) - - Introduce ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. ([#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184)) - - Introduce option to pass in intermediate points for a smooth `LocationComponent` animation. ([#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166)) + - Introduce `in` expression for testing whether an item exists in an array or a substring exists in a string. [#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171) + - Introduce option to set the minimum and maximum pitch of a map. [#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199) + - Introduce ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. [#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184) + - Introduce option to pass in intermediate points for a smooth `LocationComponent` animation. [#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166) ### Performance improvements - - Improve the performance of loading a style that has many style images. ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) - - Fix a memory leak during zooming when `MapboxMapOptions.debugActive` is enabled. ([#15179](https://github.com/mapbox/mapbox-gl-native/issues/15179), fixed by [#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395)) + - Improve the performance of loading a style that has many style images. [#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187) + - Fix a memory leak during zooming when `MapboxMapOptions.debugActive` is enabled. [#15179](https://github.com/mapbox/mapbox-gl-native/issues/15179), fixed by [#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395) ### Bug fixes - - Fix issues that would cause an offline pack to stop downloading before completion. ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) - - Fix an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) - - Fix Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) + - Fix issues that would cause an offline pack to stop downloading before completion. [#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240) + - Fix an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. [#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202) + - Fix Proguard configuration to prevent obfuscation of telemetry event classes. [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) ### Other changes - - Update mapbox-events-android to v4.7.3. ([#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201)) + - Update mapbox-events-android to v4.7.3. [#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201) ## 9.0.0 - February 13, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-beta.1...android-v9.0.0) since [Mapbox Maps SDK for Android v9.0.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-beta.1): diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index e0c2b3e77..94a91c7c1 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit e0c2b3e771bdd4a23bb7442240ccc3dbf1c1c57a +Subproject commit 94a91c7c1ccc2e640e8905fcbd7176cce393924f From b976545181eff9161d8067a41a486b5681daf875 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 4 Mar 2020 18:18:53 +0800 Subject: [PATCH 088/185] Add expression within (#198) * Add expression within * Update expression within and runtime demo * Update Runtime demo * Fix android check --- .../style/expressions/Expression.java | 31 +++++++++----- .../style/expressions/ExpressionTest.java | 28 ++++++++++++- .../activity/style/RuntimeStyleActivity.java | 40 ++++++++++++++++--- vendor/mapbox-gl-native | 2 +- 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 71775486f..9cc9554ca 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -1,10 +1,6 @@ package com.mapbox.mapboxsdk.style.expressions; import android.annotation.SuppressLint; -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.Size; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -12,6 +8,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.style.layers.PropertyValue; @@ -22,6 +19,11 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; + import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaArray; /** @@ -1539,8 +1541,8 @@ public class Expression { /** * Retrieves whether an item exists in an array or a substring exists in a string. * - * @param needle the item expression - * @param haystack the array or string expression + * @param needle the item expression + * @param haystack the array or string expression * @return true if exists. * @see Style specification */ @@ -1551,8 +1553,8 @@ public class Expression { /** * Retrieves whether an item exists in an array or a substring exists in a string. * - * @param needle the item expression - * @param haystack the array or string expression + * @param needle the item expression + * @param haystack the array or string expression * @return true if exists. * @see Style specification */ @@ -1563,8 +1565,8 @@ public class Expression { /** * Retrieves whether an item exists in an array or a substring exists in a string. * - * @param needle the item expression - * @param haystack the array or string expression + * @param needle the item expression + * @param haystack the array or string expression * @return true if exists. * @see Style specification */ @@ -1572,6 +1574,15 @@ public class Expression { return new Expression("in", literal(needle), haystack); } + public static Expression within(@NonNull Polygon polygon) { + Map map = new HashMap<>(); + + map.put("type", literal(polygon.type())); + map.put("json", literal(polygon.toJson())); + + return new Expression("within", new ExpressionMap(map)); + } + /** * Retrieves a property value from the current feature's properties, * or from another object if a second argument is provided. diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java index ca35c648e..62f3a71f0 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java @@ -2,6 +2,8 @@ package com.mapbox.mapboxsdk.style.expressions; import android.graphics.Color; +import com.mapbox.geojson.Point; +import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.style.layers.PropertyValue; import com.mapbox.mapboxsdk.utils.ColorUtils; @@ -10,7 +12,9 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; @@ -94,6 +98,7 @@ 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.within; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth; @@ -449,11 +454,32 @@ public class ExpressionTest { @Test public void testInString() throws Exception { - Object[] expected = new Object[] {"in", "one", "onetwo"}; + Object[] expected = new Object[] {"in", "one", "onetwo"}; Object[] actual = in(literal("one"), literal("onetwo")).toArray(); assertTrue("expression should match", Arrays.deepEquals(expected, actual)); } + @Test + public void testWithIn() throws Exception { + List> lngLats = Collections.singletonList( + Arrays.asList( + Point.fromLngLat(0, 0), + Point.fromLngLat(0, 5), + Point.fromLngLat(5, 5), + Point.fromLngLat(5, 0), + Point.fromLngLat(0, 0) + ) + ); + + Polygon polygon = Polygon.fromLngLats(lngLats); + HashMap map = new HashMap<>(); + map.put("type", "Polygon"); + map.put("json", polygon.toJson()); + Object[] expected = new Object[] {"within", map}; + Object[] actual = within(polygon).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + @Test public void testInNumber() throws Exception { Object[] expected = new Object[] {"in", 1f, new Object[] {"literal", new Object[] {1f, 2f}}}; diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index b9c72288f..63e9c9ca0 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -3,12 +3,14 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; -import androidx.appcompat.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; + import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Point; +import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; @@ -30,13 +32,16 @@ import com.mapbox.mapboxsdk.style.sources.TileSet; import com.mapbox.mapboxsdk.style.sources.VectorSource; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; -import timber.log.Timber; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import androidx.appcompat.app.AppCompatActivity; +import timber.log.Timber; + import static com.mapbox.mapboxsdk.style.expressions.Expression.all; import static com.mapbox.mapboxsdk.style.expressions.Expression.color; import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; @@ -50,6 +55,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.lt; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber; +import static com.mapbox.mapboxsdk.style.expressions.Expression.within; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP; import static com.mapbox.mapboxsdk.style.layers.Property.NONE; @@ -67,6 +73,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; @@ -79,6 +86,23 @@ public class RuntimeStyleActivity extends AppCompatActivity { private MapboxMap mapboxMap; private boolean styleLoaded; + List> lngLats = Collections.singletonList( + Arrays.asList( + Point.fromLngLat(-15.468749999999998, + 41.77131167976407), + Point.fromLngLat(15.468749999999998, + 41.77131167976407), + Point.fromLngLat(15.468749999999998, + 58.26328705248601), + Point.fromLngLat(-15.468749999999998, + 58.26328705248601), + Point.fromLngLat(-15.468749999999998, + 41.77131167976407) + ) + ); + + Polygon polygon = Polygon.fromLngLats(lngLats); + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -93,13 +117,19 @@ public class RuntimeStyleActivity extends AppCompatActivity { mapboxMap = map; // Center and Zoom (Amsterdam, zoomed to streets) - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14)); + mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 1)); mapboxMap.setStyle( new Style.Builder() .fromUri(Style.MAPBOX_STREETS) // set custom transition - .withTransition(new TransitionOptions(250, 50)), style -> styleLoaded = true + .withTransition(new TransitionOptions(250, 50)), style -> { + styleLoaded = true; + SymbolLayer laber = (SymbolLayer) style.getLayer("country-label"); + laber.setProperties( + textOpacity(switchCase(within(polygon), literal(1.0f), literal(0.5f))) + ); + } ); }); } @@ -547,7 +577,7 @@ public class RuntimeStyleActivity extends AppCompatActivity { states.setProperties( textSize(switchCase( in(get("name"), literal("Texas")), literal(25.0f), - in(get("name"), literal(new Object[] {"California","Illinois"})), literal(25.0f), + in(get("name"), literal(new Object[] {"California", "Illinois"})), literal(25.0f), literal(6.0f) // default value ) ) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 94a91c7c1..efc605bed 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 94a91c7c1ccc2e640e8905fcbd7176cce393924f +Subproject commit efc605bed6f2d8f54b7097af1b91416c3fa13e06 From 95f0a0bb44b36421bab0a627dfb2cc0c6617e6a7 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 5 Mar 2020 11:17:42 +0200 Subject: [PATCH 089/185] [ci] Add upstream trigger of binary size check. (#217) --- .circleci/config.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3afb5a441..6397d4003 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -179,7 +179,7 @@ commands: export VERSION_TAG=${CIRCLE_TAG} export GITHUB_TOKEN=${DANGER_GITHUB_API_TOKEN} export DOCS_REPO="android-docs" - bash scripts/trigger-maps-documentation-deploy-steps.sh + bash scripts/trigger-maps-documentation-deploy-steps.sh jobs: # ------------------------------------------------------------------------------ @@ -293,6 +293,14 @@ jobs: curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master fi fi + - run: + name: Trigger android binary size check + command: | + if [ -n "${MOBILE_METRICS_TOKEN}" ]; then + if [[ $CIRCLE_BRANCH == master ]]; then + curl -u ${MOBILE_METRICS_TOKEN}: -d build_parameters[CIRCLE_JOB]=android-binary-size-hydrogen https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + fi + fi - run: name: Generate Maven credentials command: | From 77b2ac8ef7d2291923e834ece6db848c93241714 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 5 Mar 2020 17:31:43 +0800 Subject: [PATCH 090/185] [doc] Update changelog for v8.6.3 (#219) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 840e7ce9c..fd2ae2ca6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 8.6.3 - March 5, 2020 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.2...android-v8.6.3) since [Mapbox Maps SDK for Android v8.6.2](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.2): +### Bug fixes + - Fix Proguard configuration to prevent obfuscation of telemetry event classes. [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) + ## 9.1.0-alpha.1 - February 28, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.1.0-alpha.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): ### Features From 04722fdefd9b7ebf43842d848e1c3b860840e757 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 6 Mar 2020 16:59:32 +0800 Subject: [PATCH 091/185] Update generate-style-code and add sort key api for LineLayer and FillLayer. (#209) --- .../style/layers/BackgroundLayer.java | 5 ++ .../mapboxsdk/style/layers/CircleLayer.java | 2 + .../style/layers/FillExtrusionLayer.java | 2 + .../mapboxsdk/style/layers/FillLayer.java | 18 +++++++ .../mapboxsdk/style/layers/HeatmapLayer.java | 2 + .../style/layers/HillshadeLayer.java | 5 ++ .../mapboxsdk/style/layers/LineLayer.java | 18 +++++++ .../style/layers/PropertyFactory.java | 48 +++++++++++++++++-- .../mapboxsdk/style/layers/RasterLayer.java | 7 +++ .../mapboxsdk/style/layers/SymbolLayer.java | 3 ++ .../mapboxsdk/style/layers/layer.java.ejs | 10 ++-- .../mapboxsdk/style/layers/property.java.ejs | 2 +- .../style/layers/property_factory.java.ejs | 2 +- .../mapboxsdk/style/light/light.java.ejs | 8 ++-- .../testapp/style/BackgroundLayerTest.java | 2 + .../testapp/style/FillLayerTest.java | 26 ++++++++++ .../testapp/style/HeatmapLayerTest.java | 1 + .../testapp/style/HillshadeLayerTest.java | 2 + .../testapp/style/LineLayerTest.java | 26 ++++++++++ .../testapp/style/RasterLayerTest.java | 3 ++ .../mapboxsdk/testapp/style/layer.junit.ejs | 2 +- .../mapboxsdk/testapp/style/light.junit.ejs | 10 ++-- package-lock.json | 6 +-- package.json | 2 +- scripts/generate-style-code.js | 15 +++++- vendor/mapbox-gl-native | 2 +- 26 files changed, 201 insertions(+), 28 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java index a3a537da9..3197b1a5b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java @@ -10,6 +10,11 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; + /** * The background color or pattern of the map. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index 9de4fa089..03f926ed5 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -10,8 +10,10 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A filled circle. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java index d36823df0..28d125565 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java @@ -10,8 +10,10 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * An extruded (3D) polygon. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java index 8cc6330b7..98b5f8feb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java @@ -10,8 +10,10 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A filled polygon with an optional stroked border. @@ -141,6 +143,18 @@ public class FillLayer extends Layer { // Property getters + /** + * Get the FillSortKey property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getFillSortKey() { + checkThread(); + return (PropertyValue) new PropertyValue("fill-sort-key", nativeGetFillSortKey()); + } + /** * Get the FillAntialias property * @@ -364,6 +378,10 @@ public class FillLayer extends Layer { nativeSetFillPatternTransition(options.getDuration(), options.getDelay()); } + @NonNull + @Keep + private native Object nativeGetFillSortKey(); + @NonNull @Keep private native Object nativeGetFillAntialias(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java index 3c652388f..5e5faed33 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java @@ -10,8 +10,10 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A heatmap. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java index 3efeffc1b..dae70ae36 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java @@ -10,6 +10,11 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; + /** * Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java index 0fdbaf7fe..cf1335269 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java @@ -10,8 +10,10 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; /** * A stroked line. @@ -189,6 +191,18 @@ public class LineLayer extends Layer { return (PropertyValue) new PropertyValue("line-round-limit", nativeGetLineRoundLimit()); } + /** + * Get the LineSortKey property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getLineSortKey() { + checkThread(); + return (PropertyValue) new PropertyValue("line-sort-key", nativeGetLineSortKey()); + } + /** * Get the LineOpacity property * @@ -560,6 +574,10 @@ public class LineLayer extends Layer { @Keep private native Object nativeGetLineRoundLimit(); + @NonNull + @Keep + private native Object nativeGetLineSortKey(); + @NonNull @Keep private native Object nativeGetLineOpacity(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 79c8ea128..b7a90c656 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -1645,6 +1645,26 @@ public class PropertyFactory { return new PaintPropertyValue<>("background-opacity", expression); } + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue fillSortKey(Float value) { + return new LayoutPropertyValue<>("fill-sort-key", value); + } + + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue fillSortKey(Expression value) { + return new LayoutPropertyValue<>("fill-sort-key", value); + } + /** * The display of line endings. * @@ -1725,6 +1745,26 @@ public class PropertyFactory { return new LayoutPropertyValue<>("line-round-limit", value); } + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue lineSortKey(Float value) { + return new LayoutPropertyValue<>("line-sort-key", value); + } + + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue lineSortKey(Expression value) { + return new LayoutPropertyValue<>("line-sort-key", value); + } + /** * Label placement relative to its geometry. * @@ -1766,7 +1806,7 @@ public class PropertyFactory { } /** - * 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. + * 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. When using a client that supports global collision detection, like Mapbox GL JS version 0.42.0 or greater, enabling this property is not needed to prevent clipped labels at tile boundaries. * * @param value a Boolean value * @return property wrapper around Boolean @@ -1776,7 +1816,7 @@ public class PropertyFactory { } /** - * 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. + * 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. When using a client that supports global collision detection, like Mapbox GL JS version 0.42.0 or greater, enabling this property is not needed to prevent clipped labels at tile boundaries. * * @param value a Boolean value * @return property wrapper around Boolean @@ -2316,7 +2356,7 @@ public class PropertyFactory { } /** - * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} or the two-dimensional {@link PropertyFactory#textOffset}. + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the renderer will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} or the two-dimensional {@link PropertyFactory#textOffset}. * * @param value a String[] value * @return property wrapper around String[] @@ -2326,7 +2366,7 @@ public class PropertyFactory { } /** - * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} or the two-dimensional {@link PropertyFactory#textOffset}. + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the renderer will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} or the two-dimensional {@link PropertyFactory#textOffset}. * * @param value a String[] value * @return property wrapper around String[] diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java index 1f4b844cb..9c0c73327 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java @@ -8,6 +8,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; +import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; + /** * Raster map textures such as satellite imagery. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java index 156e11126..06d488d6e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java @@ -10,9 +10,12 @@ import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; import com.mapbox.mapboxsdk.style.types.Formatted; +import com.mapbox.mapboxsdk.style.types.FormattedSection; /** * An icon or a text label. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs index e62c82e3b..3d2ccffba 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs @@ -7,11 +7,11 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs index aaab1fe9f..7d859893b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs @@ -5,7 +5,7 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.StringDef; +import androidx.annotation.StringDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs index f4b171489..0a8d5c3b2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs @@ -6,7 +6,7 @@ package com.mapbox.mapboxsdk.style.layers; -import android.support.annotation.ColorInt; +import androidx.annotation.ColorInt; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.types.Formatted; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs index e5d50b948..30a021195 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs @@ -6,10 +6,10 @@ package com.mapbox.mapboxsdk.style.light; -import android.support.annotation.ColorInt; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.UiThread; +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.UiThread; import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java index 8ec149874..c6fe2d62d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java @@ -10,11 +10,13 @@ import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; +import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.BackgroundLayer; import org.junit.Test; import org.junit.runner.RunWith; +import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java index d886f58cc..ef75a5e64 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java @@ -99,6 +99,32 @@ public class FillLayerTest extends BaseLayerTest { + @Test + @UiThreadTest + public void testFillSortKeyAsConstant() { + Timber.i("fill-sort-key"); + assertNotNull(layer); + assertNull(layer.getFillSortKey().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(fillSortKey(propertyValue)); + assertEquals(layer.getFillSortKey().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testFillSortKeyAsExpression() { + Timber.i("fill-sort-key-expression"); + assertNotNull(layer); + assertNull(layer.getFillSortKey().getExpression()); + + // Set and Get + Expression expression = number(Expression.get("undefined")); + layer.setProperties(fillSortKey(expression)); + assertEquals(layer.getFillSortKey().getExpression(), expression); + } + @Test @UiThreadTest public void testFillAntialiasAsConstant() { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java index 566dd7a70..79c244c45 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.testapp.style; +import android.graphics.Color; import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java index 60e977429..68943d19a 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java @@ -10,11 +10,13 @@ import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; +import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.HillshadeLayer; import org.junit.Test; import org.junit.runner.RunWith; +import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java index 18bb31da0..daeb41c1c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java @@ -164,6 +164,32 @@ public class LineLayerTest extends BaseLayerTest { assertEquals(layer.getLineRoundLimit().getValue(), propertyValue); } + @Test + @UiThreadTest + public void testLineSortKeyAsConstant() { + Timber.i("line-sort-key"); + assertNotNull(layer); + assertNull(layer.getLineSortKey().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(lineSortKey(propertyValue)); + assertEquals(layer.getLineSortKey().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testLineSortKeyAsExpression() { + Timber.i("line-sort-key-expression"); + assertNotNull(layer); + assertNull(layer.getLineSortKey().getExpression()); + + // Set and Get + Expression expression = number(Expression.get("undefined")); + layer.setProperties(lineSortKey(expression)); + assertEquals(layer.getLineSortKey().getExpression(), expression); + } + @Test @UiThreadTest public void testLineOpacityTransition() { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java index 55ffe97dd..56cf1e845 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.testapp.style; +import android.graphics.Color; import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -9,11 +10,13 @@ import com.mapbox.mapboxsdk.maps.BaseLayerTest; import org.junit.Before; import timber.log.Timber; +import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.RasterLayer; import org.junit.Test; import org.junit.runner.RunWith; +import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index c71ea0d37..dd18ad581 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -7,7 +7,7 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.annotation.UiThreadTest; +import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.mapbox.mapboxsdk.maps.BaseLayerTest; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs index e26ec2d6c..b98e788ce 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs @@ -4,8 +4,8 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.View; @@ -24,9 +24,9 @@ import org.hamcrest.Matcher; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase; diff --git a/package-lock.json b/package-lock.json index 27c044c32..fe0b7d470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "ejs": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", - "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", "dev": true }, "esm": { diff --git a/package.json b/package.json index 8d3f68473..e509e6530 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "license": "BSD-2-Clause", "dependencies": {}, "devDependencies": { - "ejs": "^2.5.7", + "ejs": "^2.7.4", "esm": "~3.1.0", "lodash": "^4.16.4", "pixelmatch": "^4.0.2" diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index fd9490445..bc3f67c9a 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -8,8 +8,8 @@ const _ = require('lodash'); // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 delete spec.layout_circle["circle-sort-key"] -delete spec.layout_line["line-sort-key"] -delete spec.layout_fill["fill-sort-key"] +//delete spec.layout_line["line-sort-key"] +//delete spec.layout_fill["fill-sort-key"] require('../vendor/mapbox-gl-native/scripts/style-code'); @@ -383,6 +383,17 @@ for (const layer of layers) { writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); } +// Jni +const layerHpp = ejs.compile(fs.readFileSync('vendor/mapbox-gl-native/platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); +const layerCpp = ejs.compile(fs.readFileSync('vendor/mapbox-gl-native/platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); + +for (const layer of layers) { + const layerFileName = layer.type.replace('-', '_'); + + writeIfModified(`vendor/mapbox-gl-native/platform/android/src/style/layers/${layerFileName}_layer.hpp`, layerHpp(layer)); + writeIfModified(`vendor/mapbox-gl-native/platform/android/src/style/layers/${layerFileName}_layer.cpp`, layerCpp(layer)); +} + // Java PropertyFactory const propertiesTemplate = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); writeIfModified( diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index efc605bed..fb0c7c93a 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit efc605bed6f2d8f54b7097af1b91416c3fa13e06 +Subproject commit fb0c7c93a0f82cae603edc29e7e9a56024ed2b39 From ea7bc213a2365991a71656630bd793d252bbcc95 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Mon, 9 Mar 2020 22:00:06 +0800 Subject: [PATCH 092/185] Enable ccache for android studio. (#269) --- MapboxGLAndroidSDK/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MapboxGLAndroidSDK/build.gradle b/MapboxGLAndroidSDK/build.gradle index 5ee3af61e..06700ad8a 100644 --- a/MapboxGLAndroidSDK/build.gradle +++ b/MapboxGLAndroidSDK/build.gradle @@ -34,6 +34,11 @@ android { buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"mapbox-maps-android/%s\"", project.VERSION_NAME) consumerProguardFiles 'proguard-rules.pro' + externalNativeBuild { + cmake { + arguments '-DANDROID_CCACHE=ccache' + } + } } // build native libraries From 1dedece852b209acb3c4a3f32ea74fbc5237ca13 Mon Sep 17 00:00:00 2001 From: Chloe Krawczyk Date: Tue, 10 Mar 2020 17:10:56 -0700 Subject: [PATCH 093/185] Add PR template for drafting changelogs (#270) --- .github/PULL_REQUEST_TEMPLATE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..bb590f175 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,10 @@ +`Replace text with suggested changelog entry for this PR.` + + + + + + + From d9bcd52a445564e25820176aea09f358aa67bc07 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 11 Mar 2020 17:56:18 +0800 Subject: [PATCH 094/185] [doc] Update changelog for v9.0.1 (#223) * [doc] Update changelog for v9.0.1 * Update CHANGELOG.md * Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd2ae2ca6..220079cb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 9.0.1 - March 11, 2020 +[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.0.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): +### Bug fixes + - Fix Proguard configuration to prevent obfuscation of telemetry event classes. [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) + ## 8.6.3 - March 5, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v8.6.2...android-v8.6.3) since [Mapbox Maps SDK for Android v8.6.2](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v8.6.2): ### Bug fixes From 5c7a432bd643a9b8c67e4042877b72c25d838868 Mon Sep 17 00:00:00 2001 From: Chloe Krawczyk Date: Wed, 11 Mar 2020 20:04:56 -0700 Subject: [PATCH 095/185] Add skip changelog label to PR template (#272) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bb590f175..f3681d858 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,4 @@ -`Replace text with suggested changelog entry for this PR.` +`Replace text with suggested changelog entry for this PR or add the 'skip changelog' label.` From c8108edc29493c25cd6e400c9966a66c0bf0bcd5 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 12 Mar 2020 19:03:08 +0800 Subject: [PATCH 096/185] Add test demo for filter with expression in (#218) * Add test demo for filter with expression in * Update gl-native --- .../src/main/assets/fill_color_style.json | 95 +++++++++++++++++++ .../activity/style/RuntimeStyleActivity.java | 9 +- .../src/main/res/menu/menu_runtime_style.xml | 5 + .../src/main/res/values/actions.xml | 1 + vendor/mapbox-gl-native | 2 +- 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/fill_color_style.json diff --git a/MapboxGLAndroidSDKTestApp/src/main/assets/fill_color_style.json b/MapboxGLAndroidSDKTestApp/src/main/assets/fill_color_style.json new file mode 100644 index 000000000..2282f181b --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/assets/fill_color_style.json @@ -0,0 +1,95 @@ +{ + "version": 8, + "zoom": 10, + "center": [0, 0], + "sources": { + "quadrants": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "ABC", + "color": "red" + }, + "geometry": { + "type": "Polygon", + "coordinates": [[ + [-180, -90], + [-180, 0], + [0, 0], + [0, -90], + [-180, -90] + ]] + } + }, + { + "type": "Feature", + "properties": { + "name": "DEF", + "color": "#00ff00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [[ + [-180, 90], + [-180, 0], + [0, 0], + [0, 90], + [-180, 90] + ]] + } + }, + { + "type": "Feature", + "properties": { + "name": "GHI", + "color": "#0000ff" + }, + "geometry": { + "type": "Polygon", + "coordinates": [[ + [180, -90], + [180, 0], + [0, 0], + [0, -90], + [180, -90] + ]] + } + }, + { + "type": "Feature", + "properties": { + "name": "GHI", + "color": "#ffff00" + }, + "geometry": { + "type": "Polygon", + "coordinates": [[ + [180, 90], + [180, 0], + [0, 0], + [0, 90], + [180, 90] + ]] + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "colors", + "type": "fill", + "source": "quadrants", + "filter": ["in", "#", ["get", "color"]], + "paint": { + "fill-color": ["get", "color"] + } + } + ] +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index 63e9c9ca0..8d23b0a0b 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -118,7 +118,6 @@ public class RuntimeStyleActivity extends AppCompatActivity { // Center and Zoom (Amsterdam, zoomed to streets) mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 1)); - mapboxMap.setStyle( new Style.Builder() .fromUri(Style.MAPBOX_STREETS) @@ -243,6 +242,9 @@ public class RuntimeStyleActivity extends AppCompatActivity { case R.id.action_bring_water_to_front: bringWaterToFront(); return true; + case R.id.action_fill_filter_color: + styleFillColorLayer(); + return true; default: return super.onOptionsItemSelected(item); } @@ -532,6 +534,11 @@ public class RuntimeStyleActivity extends AppCompatActivity { mapboxMap.getStyle().addLayer(lineLayer); } + private void styleFillColorLayer() { + mapboxMap.setStyle(new Style.Builder().fromUri("asset://fill_color_style.json")); + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(31, -100), 3)); + } + private void styleFillFilterLayer() { mapboxMap.setStyle(new Style.Builder().fromUri("asset://fill_filter_style.json")); mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(31, -100), 3)); diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml index b302568fa..6a21f640c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml @@ -58,6 +58,10 @@ android:id="@+id/action_fill_filter" android:title="@string/apply_filtered_fill" mapbox:showAsAction="never" /> + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml index 00ac9930c..09c67914e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -77,6 +77,7 @@ Change the water color on zoom Custom tiles Apply filtered fill + Apply filtered fill color Apply text size fill Apply filtered line Apply numeric fill filter diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index fb0c7c93a..639434b3e 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit fb0c7c93a0f82cae603edc29e7e9a56024ed2b39 +Subproject commit 639434b3efd144b465f2dd118cb3b9acce2b6b31 From 192f5d8008ebcaebaa86167a658a9fc9f59d1b55 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Mon, 16 Mar 2020 15:49:24 +0800 Subject: [PATCH 097/185] Bump gl-native to 1.4.0 (#276) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 639434b3e..09d307db1 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 639434b3efd144b465f2dd118cb3b9acce2b6b31 +Subproject commit 09d307db14514479a8f2fbbd6e6a98496b1f23c7 From c0dfb15890c15044c6e756b9b3e749197a95e625 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 17 Mar 2020 15:24:33 +0800 Subject: [PATCH 098/185] Bump gl-native to v1.4.1 (#279) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 09d307db1..a601f9474 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 09d307db14514479a8f2fbbd6e6a98496b1f23c7 +Subproject commit a601f94743eb812847fbb58944df7240b088f7e2 From 69b2d4c7657697c519506e1becefa062b79580ef Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 17 Mar 2020 15:51:24 +0800 Subject: [PATCH 099/185] Add change log for v9.1.0-beta.1 (#275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add change log for v9.1.0-bate.1 * improve existing entries, add gl-native entries * add known issue release note * fix link * this is what the beta release tag description should look like * make changes for changelog.md file * fix inconsistencies * minor fixup * Apply suggestions from code review Co-Authored-By: Minh Nguyễn * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * tighten up sort key entry * use android naming * add release note about snapshotter regression * fix nits * remove release note about regression waiting for GL Native 1.4.1 patch instead Co-authored-by: Chloe Krawczyk Co-authored-by: Minh Nguyễn --- CHANGELOG.md | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 220079cb4..10d736bf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,31 @@ # Changelog for the Mapbox Maps SDK for Android -Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +Mapbox welcomes participation and contributions from everyone. Please read [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) to get started. + +## 9.1.0 +This beta release includes a feature with a known issue: the `within` expression evaluates point features inconsistently across zoom levels if the point lies near the boundary of a GeoJSON object ([#16301](https://github.com/mapbox/mapbox-gl-native/issues/16301])). + +### Features + - Added `within` expression for testing whether an evaluated feature lies within a given GeoJSON object. `within` accepts `Feature`, `FeatureCollection`, `Polygon`, and `MultiPolygon` as valid GeoJSON objects. ([#198](https://github.com/mapbox/mapbox-gl-native-android/pull/198)) + - Added `in` expression for testing whether an item exists in an array or a substring exists in a string. ([#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171)) + - Added methods to set and get the sort key of features in a `FillLayer` and `LineLayer` at runtime. Features with a higher sort key will appear above features with a lower sort key. ([#209](https://github.com/mapbox/mapbox-gl-native-android/pull/209)) + - Introduced option to set the minimum and maximum pitch of a map. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) + - Introduced ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. ([#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184)) + +### Performance improvements + - Increased stability of label placement when the map is tilted. ([#16287](https://github.com/mapbox/mapbox-gl-native/pull/16287)) + - Improved the performance of loading a style that has many style images. ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) + - Fixed a memory leak during zooming when `MapboxMapOptions.debugActive` is enabled. ([#15179](https://github.com/mapbox/mapbox-gl-native/issues/15179), fixed by [#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395)) + +### Bug fixes + - Downloaded offline packs no longer reduce the storage space available for ambient caching of tiles and other resources. ([#15622](https://github.com/mapbox/mapbox-gl-native/pull/15622)) + - Fixed conversion of a `Map` object into a GeoJSON object. ([#16243](https://github.com/mapbox/mapbox-gl-native/pull/16243)) + - Fixed issues that would cause an offline region to stop downloading before completion. ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) + - Fixed an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) + - Fixed Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) + +### Other changes + - Updated mapbox-events-android to v4.7.3. ([#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201)) ## 9.0.1 - March 11, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.0.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): @@ -12,26 +37,6 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Bug fixes - Fix Proguard configuration to prevent obfuscation of telemetry event classes. [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) -## 9.1.0-alpha.1 - February 28, 2020 -[Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.1.0-alpha.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): -### Features - - Introduce `in` expression for testing whether an item exists in an array or a substring exists in a string. [#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171) - - Introduce option to set the minimum and maximum pitch of a map. [#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199) - - Introduce ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. [#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184) - - Introduce option to pass in intermediate points for a smooth `LocationComponent` animation. [#166](https://github.com/mapbox/mapbox-gl-native-android/pull/166) - -### Performance improvements - - Improve the performance of loading a style that has many style images. [#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187) - - Fix a memory leak during zooming when `MapboxMapOptions.debugActive` is enabled. [#15179](https://github.com/mapbox/mapbox-gl-native/issues/15179), fixed by [#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395) - -### Bug fixes - - Fix issues that would cause an offline pack to stop downloading before completion. [#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240) - - Fix an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. [#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202) - - Fix Proguard configuration to prevent obfuscation of telemetry event classes. [#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195) - -### Other changes - - Update mapbox-events-android to v4.7.3. [#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201) - ## 9.0.0 - February 13, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0-beta.1...android-v9.0.0) since [Mapbox Maps SDK for Android v9.0.0-beta.1](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0-beta.1): ### Features From 14eb8f038aa64bd41eb7e94c1ff3c63c37dfec0a Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 17 Mar 2020 10:12:38 +0100 Subject: [PATCH 100/185] [textureview] validate TextureView surface texture when creating egl window surface (#278) --- CHANGELOG.md | 1 + .../maps/renderer/textureview/TextureViewRenderThread.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10d736bf4..099994f71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This beta release includes a feature with a known issue: the `within` expression - Fixed issues that would cause an offline region to stop downloading before completion. ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) - Fixed an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) - Fixed Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) + - Fixed a crash that might occur during EGL window surface creation. ([#278](https://github.com/mapbox/mapbox-gl-native-android/pull/278)) ### Other changes - Updated mapbox-events-android to v4.7.3. ([#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201)) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java index 0604b3de4..9a4d72e03 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java @@ -1,9 +1,11 @@ package com.mapbox.mapboxsdk.maps.renderer.textureview; import android.graphics.SurfaceTexture; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; + import android.view.TextureView; import com.mapbox.mapboxsdk.log.Logger; @@ -390,7 +392,7 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu // Create an EGL surface we can render into. TextureView view = textureViewWeakRef.get(); - if (view != null) { + if (view != null && view.getSurfaceTexture() != null) { int[] surfaceAttribs = {EGL10.EGL_NONE}; eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, view.getSurfaceTexture(), surfaceAttribs); } else { From d8c919f1dde44f428b65a2ab7eca262f7398422a Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 23 Mar 2020 07:51:37 +0100 Subject: [PATCH 101/185] [mapview] expose queuEvent to schedule runnable to execut on thread of MapRenderer (#284) --- .../com/mapbox/mapboxsdk/maps/MapView.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 553a6a5f6..a57f56164 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -160,18 +160,18 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray); ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray); AnnotationManager annotationManager = new AnnotationManager(this, annotationsArray, iconManager, - annotations, markers, polygons, polylines, shapeAnnotations); + annotations, markers, polygons, polylines, shapeAnnotations); Transform transform = new Transform(this, nativeMapView, cameraDispatcher); // MapboxMap List developerAnimationListeners = new ArrayList<>(); mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, proj, registerTouchListener, cameraDispatcher, - developerAnimationListeners); + developerAnimationListeners); mapboxMap.injectAnnotationManager(annotationManager); // user input mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, - annotationManager, cameraDispatcher); + annotationManager, cameraDispatcher); mapKeyListener = new MapKeyListener(transform, uiSettings, mapGestureDetector); // LocationComponent @@ -245,7 +245,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } private MapboxMap.OnCompassAnimationListener createCompassAnimationListener(@NonNull final CameraChangeDispatcher - cameraChangeDispatcher) { + cameraChangeDispatcher) { return new MapboxMap.OnCompassAnimationListener() { @Override public void onCompassAnimation() { @@ -313,7 +313,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { TextureView textureView = new TextureView(getContext()); boolean translucentSurface = options.getTranslucentTextureSurface(); mapRenderer = new TextureViewMapRenderer(getContext(), - textureView, localFontFamily, translucentSurface) { + textureView, localFontFamily, translucentSurface) { @Override protected void onSurfaceCreated(GL10 gl, EGLConfig config) { MapView.this.onSurfaceCreated(); @@ -340,7 +340,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { boolean crossSourceCollisions = mapboxMapOptions.getCrossSourceCollisions(); nativeMapView = new NativeMapView( - getContext(), getPixelRatio(), crossSourceCollisions, this, mapChangeReceiver, mapRenderer + getContext(), getPixelRatio(), crossSourceCollisions, this, mapChangeReceiver, mapRenderer ); } @@ -466,6 +466,18 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } } + /** + * Queue a runnable to be executed on the map renderer thread. + * + * @param runnable the runnable to queue + */ + public void queueEvent(@NonNull Runnable runnable) { + if (mapRenderer == null) { + throw new IllegalStateException("Calling MapView#queueEvent before mapRenderer is created."); + } + mapRenderer.queueEvent(runnable); + } + /** * The maximum frame rate at which the map view is rendered, * but it can't excess the ability of device hardware. @@ -1249,7 +1261,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { public void setGesturesManager(AndroidGesturesManager gesturesManager, boolean attachDefaultListeners, boolean setDefaultMutuallyExclusives) { mapGestureDetector.setGesturesManager( - getContext(), gesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); + getContext(), gesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives); } @Override @@ -1259,8 +1271,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } private class MapCallback implements OnDidFinishLoadingStyleListener, - OnDidFinishRenderingFrameListener, OnDidFinishLoadingMapListener, - OnCameraIsChangingListener, OnCameraDidChangeListener, OnDidFailLoadingMapListener { + OnDidFinishRenderingFrameListener, OnDidFinishLoadingMapListener, + OnCameraIsChangingListener, OnCameraDidChangeListener, OnDidFailLoadingMapListener { private final List onMapReadyCallbackList = new ArrayList<>(); From 02b5e60f8678fbbc8c4bbf526b1c9092632cd603 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 24 Mar 2020 12:52:54 +0100 Subject: [PATCH 102/185] [testapp] - add example using within expression (#288) --- .../src/main/AndroidManifest.xml | 11 + .../activity/turf/WithinExpressionActivity.kt | 268 ++++++++++++++++++ .../res/layout/activity_within_expression.xml | 13 + .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/titles.xml | 1 + 5 files changed, 294 insertions(+) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/WithinExpressionActivity.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_within_expression.xml diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index ee239a6d5..cb9d37e4e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -998,6 +998,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" />
    + + + + + mapboxMap = map + + // Setup camera position above Georgetown + mapboxMap.cameraPosition = CameraPosition.Builder() + .target(LatLng(38.90628988399711, -77.06574689337494)) + .zoom(15.5) + .build() + + // Wait for the map to become idle before manipulating the style and camera of the map + mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener { + override fun onDidBecomeIdle() { + handler.postDelayed(runnable, 2500) + mapView.removeOnDidBecomeIdleListener(this) + } + }) + + // Load mapbox streets and add lines and circles + setupStyle() + } + } + + private fun setupStyle() { + // Assume the route is represented by an array of coordinates. + val coordinates = listOf( + Point.fromLngLat( + -77.06866264343262, + 38.90506061276737 + ), + Point.fromLngLat( + -77.06283688545227, + 38.905194197410545 + ), + Point.fromLngLat( + -77.06285834312439, + 38.906429843444094 + ), + Point.fromLngLat( + -77.0630407333374, + 38.90680554236621 + ) + ) + + // Convert to a LineString + val routeLineString = LineString.fromLngLats(coordinates) + + // Create buffer around linestring + val bufferedRouteGeometry = bufferLineStringGeometry(routeLineString) + + // Setup style with additional layers, + // using Style.MAPBOX_STREETS as a base style + mapboxMap.setStyle( + Style.Builder() + .fromUri(Style.MAPBOX_STREETS) + .withSources( + GeoJsonSource( + POINT_ID, LineString.fromLngLats(coordinates) + ), + GeoJsonSource( + FILL_ID, + FeatureCollection.fromFeature(Feature.fromGeometry(bufferedRouteGeometry)), + GeoJsonOptions().withBuffer(0).withTolerance(0.0f) + ) + ) + .withLayerBelow( + LineLayer(LINE_ID, POINT_ID) + .withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)), + "poi-label" + ) + .withLayerBelow( + CircleLayer(POINT_ID, POINT_ID) + .withProperties( + circleRadius(7.5f), + circleColor(Color.DKGRAY), + circleOpacity(0.75f) + ), "poi-label" + ) + ) + } + + private fun optimizeStyle() { + val style = mapboxMap.style!! + + // Add fill layer to represent buffered LineString + mapboxMap.style!!.addLayerBelow( + FillLayer(FILL_ID, FILL_ID) + .withProperties( + fillOpacity(0.12f), + fillColor(Color.YELLOW) + ), LINE_ID + ) + + // Move to a new camera position + mapboxMap.easeCamera( + CameraUpdateFactory.newCameraPosition( + CameraPosition.Builder() + .zoom(16.0) + .target(LatLng(38.905156245642814, -77.06535338052844)) + .bearing(80.68015859462369) + .tilt(55.0) + .build() + ), 1750 + ) + + // Show only POI labels inside geometry using within expression + val symbolLayer = style.getLayer("poi-label") as SymbolLayer + symbolLayer.setFilter( + within( + bufferLineStringGeometry() + ) + ) + + // Hide other types of labels to highlight POI labels + (style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE)) + (style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE)) + (style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE)) + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + override fun onDestroy() { + super.onDestroy() + handler.removeCallbacks(runnable) + mapView.onDestroy() + } + + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) + outState?.let { + mapView.onSaveInstanceState(it) + } + } + + private fun bufferLineStringGeometry(lineString: LineString? = null): Polygon { + // TODO replace static data by Turf#Buffer: mapbox-java/issues/987 + return FeatureCollection.fromJson( + """ + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -77.06867337226866, + 38.90467655551809 + ], + [ + -77.06233263015747, + 38.90479344272695 + ], + [ + -77.06234335899353, + 38.906463238984344 + ], + [ + -77.06290125846863, + 38.907206285691615 + ], + [ + -77.06364154815674, + 38.90684728656818 + ], + [ + -77.06326603889465, + 38.90637140121084 + ], + [ + -77.06321239471436, + 38.905561553883246 + ], + [ + -77.0691454410553, + 38.905436318935635 + ], + [ + -77.06912398338318, + 38.90466820642439 + ], + [ + -77.06867337226866, + 38.90467655551809 + ] + ] + ] + } + } + ] + } + """.trimIndent() + ).features()!![0].geometry() as Polygon + } + + companion object { + const val POINT_ID = "point" + const val FILL_ID = "fill" + const val LINE_ID = "line" + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_within_expression.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_within_expression.xml new file mode 100644 index 000000000..de8abb502 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_within_expression.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 075949be5..32ca4de17 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -19,6 +19,7 @@ Debug Mode Offline Map example Download an offline region. + Usage of the within expression on a buffered geometry Update metadata example Delete region example Change resources cache path example diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 0a0166945..0089648ff 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -87,4 +87,5 @@ Performance Measurement Physical Unit Circle Download region + Within expression \ No newline at end of file From da6d8a2b06e61bc9a5f72774a6ca5eeddd717329 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 25 Mar 2020 09:59:38 +0800 Subject: [PATCH 103/185] Add runtime styling APIs on MapSnapshotter (#268) * Add styleable snapshotter. * Add style API for snapshotter * Add observer interface to snapshotter * WIP Add styling to snapshotter activity * Update interface and implement addlayer functions. * Deprecate methods instead of removing * Implement addSource functions. * Implement addImage function * Still use the previous callback interface. * Expose onStyleDidloaded interface * Add setStyle method * Start native snapshotter from start method * Fix snapshotter test. * Fix check style * Keep the original interface * Update gl-native * Add demo for snapshotter heatmap layer * bump gl-native Co-authored-by: Alexander Shalamov --- .../java/com/mapbox/mapboxsdk/maps/Image.java | 2 +- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 20 +- .../com/mapbox/mapboxsdk/maps/NativeMap.java | 2 + .../mapbox/mapboxsdk/maps/NativeMapView.java | 8 + .../java/com/mapbox/mapboxsdk/maps/Style.java | 56 +++-- .../mapboxsdk/snapshotter/MapSnapshotter.java | 206 +++++++++++++++--- .../mapboxsdk/style/layers/CustomLayer.java | 17 +- .../snapshotter/MapSnapshotterTest.kt | 14 +- .../src/main/AndroidManifest.xml | 18 +- .../customlayer/CustomLayerActivity.java | 4 +- .../activity/render/RenderTestDefinition.java | 3 +- .../snapshot/MapSnapshotterActivity.java | 94 +++++++- ... MapSnapshotterBitMapOverlayActivity.java} | 17 +- .../MapSnapshotterHeatMapActivity.java | 174 +++++++++++++++ .../MapSnapshotterLocalStyleActivity.java | 3 +- .../snapshot/MapSnapshotterReuseActivity.java | 7 +- .../src/main/res/values/descriptions.xml | 3 +- .../src/main/res/values/titles.xml | 3 +- vendor/mapbox-gl-native | 2 +- 19 files changed, 565 insertions(+), 88 deletions(-) rename MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/{MapSnapshotterMarkerActivity.java => MapSnapshotterBitMapOverlayActivity.java} (92%) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterHeatMapActivity.java diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java index 73ead3bc0..380f78b07 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java @@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.maps; import androidx.annotation.Keep; @Keep -class Image { +public class Image { private final byte[] buffer; private final float pixelRatio; private final String name; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 286e48fe8..f50b1a394 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -5,12 +5,6 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; -import androidx.annotation.FloatRange; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.Size; -import androidx.annotation.UiThread; import android.text.TextUtils; import android.view.View; @@ -44,6 +38,13 @@ import com.mapbox.mapboxsdk.style.expressions.Expression; import java.util.ArrayList; import java.util.List; +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; +import androidx.annotation.UiThread; + /** * The general class to interact with in the Android Mapbox SDK. It exposes the entry point for all * methods related to the MapView. You cannot instantiate {@link MapboxMap} object directly, rather, @@ -93,6 +94,13 @@ public final class MapboxMap { this.developerAnimationStartedListeners = developerAnimationStartedListeners; } + /** + * Trigger the mapview to repaint. + */ + public void triggerRepaint() { + nativeMapView.triggerRepaint(); + } + void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) { transform.initialise(this, options); uiSettings.initialise(context, options); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 81ff438c6..2b93fa8c6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -237,6 +237,8 @@ interface NativeMap { float getPixelRatio(); + void triggerRepaint(); + // // Deprecated Annotations API // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 05ebf36d6..8ff484f10 100755 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -1003,6 +1003,11 @@ final class NativeMapView implements NativeMap { return pixelRatio; } + @Override + public void triggerRepaint() { + nativeTriggerRepaint(); + } + @NonNull @Override public RectF getDensityDependantRectangle(final RectF rectangle) { @@ -1476,6 +1481,9 @@ final class NativeMapView implements NativeMap { return nativePtr; } + @Keep + private native void nativeTriggerRepaint(); + // // Snapshot // diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index 31c1ae982..fe88e081a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -340,7 +340,7 @@ public class Style { */ public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { validateState("addImage"); - nativeMap.addImages(new Image[]{toImage(new Builder.ImageWrapper(name, bitmap, sdf))}); + nativeMap.addImages(new Image[] {toImage(new Builder.ImageWrapper(name, bitmap, sdf))}); } /** @@ -932,23 +932,23 @@ public class Style { return this; } - String getUri() { + public String getUri() { return styleUri; } - String getJson() { + public String getJson() { return styleJson; } - List getSources() { + public List getSources() { return sources; } - List getLayers() { + public List getLayers() { return layers; } - List getImages() { + public List getImages() { return images; } @@ -963,18 +963,30 @@ public class Style { return new Style(this, nativeMap); } - static class ImageWrapper { + public static class ImageWrapper { Bitmap bitmap; String id; boolean sdf; - ImageWrapper(String id, Bitmap bitmap, boolean sdf) { + public ImageWrapper(String id, Bitmap bitmap, boolean sdf) { this.id = id; this.bitmap = bitmap; this.sdf = sdf; } - static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf) { + public Bitmap getBitmap() { + return bitmap; + } + + public String getId() { + return id; + } + + public boolean isSdf() { + return sdf; + } + + public static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf) { ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()]; List keyList = new ArrayList<>(bitmapHashMap.keySet()); for (int i = 0; i < bitmapHashMap.size(); i++) { @@ -985,43 +997,59 @@ public class Style { } } - class LayerWrapper { + public class LayerWrapper { Layer layer; LayerWrapper(Layer layer) { this.layer = layer; } + + public Layer getLayer() { + return layer; + } } - class LayerAboveWrapper extends LayerWrapper { + public class LayerAboveWrapper extends LayerWrapper { String aboveLayer; LayerAboveWrapper(Layer layer, String aboveLayer) { super(layer); this.aboveLayer = aboveLayer; } + + public String getAboveLayer() { + return aboveLayer; + } } - class LayerBelowWrapper extends LayerWrapper { + public class LayerBelowWrapper extends LayerWrapper { String belowLayer; LayerBelowWrapper(Layer layer, String belowLayer) { super(layer); this.belowLayer = belowLayer; } + + public String getBelowLayer() { + return belowLayer; + } } - class LayerAtWrapper extends LayerWrapper { + public class LayerAtWrapper extends LayerWrapper { int index; LayerAtWrapper(Layer layer, int index) { super(layer); this.index = index; } + + public int getIndex() { + return index; + } } } - private static Image toImage(Builder.ImageWrapper imageWrapper) { + public static Image toImage(Builder.ImageWrapper imageWrapper) { Bitmap bitmap = imageWrapper.bitmap; if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) { bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index c5e2b0164..26af5157a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -7,11 +7,6 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Handler; -import androidx.annotation.Keep; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.UiThread; -import androidx.core.content.res.ResourcesCompat; import android.text.Html; import android.text.TextUtils; import android.util.DisplayMetrics; @@ -28,12 +23,23 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.log.Logger; +import com.mapbox.mapboxsdk.maps.Image; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.TelemetryDefinition; import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.utils.FontUtils; import com.mapbox.mapboxsdk.utils.ThreadUtils; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.core.content.res.ResourcesCompat; + +import static com.mapbox.mapboxsdk.maps.Style.toImage; + /** * The map snapshotter creates a large of the map, rendered * off the UI thread. The snapshotter itself must be used on @@ -44,6 +50,21 @@ public class MapSnapshotter { private static final String TAG = "Mbgl-MapSnapshotter"; + private static final int LOGO_MARGIN_DP = 4; + + // Holds the pointer to JNI NativeMapView + @Keep + private long nativePtr = 0; + + private final Context context; + private boolean fullyLoaded = false; + private Options options; + + @Nullable + private SnapshotReadyCallback callback; + @Nullable + private ErrorHandler errorHandler; + /** * Get notified on snapshot completion. * @@ -57,7 +78,6 @@ public class MapSnapshotter { * @param snapshot the snapshot */ void onSnapshotReady(MapSnapshot snapshot); - } /** @@ -77,18 +97,6 @@ public class MapSnapshotter { void onError(String error); } - private static final int LOGO_MARGIN_DP = 4; - - // Holds the pointer to JNI NativeMapView - @Keep - private long nativePtr = 0; - - private final Context context; - @Nullable - private SnapshotReadyCallback callback; - @Nullable - private ErrorHandler errorHandler; - /** * MapSnapshotter options */ @@ -96,13 +104,12 @@ public class MapSnapshotter { private float pixelRatio = 1; private int width; private int height; - private String styleUri = Style.MAPBOX_STREETS; - private String styleJson; private LatLngBounds region; private CameraPosition cameraPosition; private boolean showLogo = true; private String localIdeographFontFamily = MapboxConstants.DEFAULT_FONT; private String apiBaseUrl; + private Style.Builder builder; /** * @param width the width of the image @@ -117,22 +124,41 @@ public class MapSnapshotter { } /** - * @param uri The style URI to use + * Set a style builder to snapshotter, the contents in builder like layers/sources/images will be applied + * to snapshotter. + * + * @param builder The builder will applied to snapshotter * @return the mutated {@link Options} */ @NonNull + public Options withStyleBuilder(Style.Builder builder) { + this.builder = builder; + return this; + } + + public Style.Builder getBuilder() { + return builder; + } + + /** + * @param uri The style URI to use + * @return the mutated {@link Options} + * @deprecated use {@link #withStyleBuilder(Style.Builder)} instead + */ + @NonNull public Options withStyle(String uri) { - this.styleUri = uri; + withStyleBuilder(new Style.Builder().fromUri(uri)); return this; } /** * @param styleJson The style json to use * @return the mutated {@link Options} + * @deprecated use {@link #withStyleBuilder(Style.Builder)} instead */ @NonNull public Options withStyleJson(String styleJson) { - this.styleJson = styleJson; + withStyleBuilder(new Style.Builder().fromJson(styleJson)); return this; } @@ -187,6 +213,7 @@ public class MapSnapshotter { * Default system fonts are defined in '/system/etc/fonts.xml' * Default font for local ideograph font family is {@link MapboxConstants#DEFAULT_FONT}. *

    + * * @param fontFamily font family for local ideograph generation. * @return the mutated {@link Options} */ @@ -204,6 +231,7 @@ public class MapSnapshotter { * '/system/etc/fonts.xml'. Default font for local ideograph font family is * {@link MapboxConstants#DEFAULT_FONT}. *

    + * * @param fontFamilies font families for local ideograph generation. * @return the mutated {@link Options} */ @@ -274,14 +302,22 @@ public class MapSnapshotter { */ @Deprecated public String getStyleUrl() { - return styleUri; + return builder == null ? Style.MAPBOX_STREETS : builder.getUri(); } /** * @return the style uri */ public String getStyleUri() { - return styleUri; + return builder == null ? Style.MAPBOX_STREETS : builder.getUri(); + } + + /** + * @return the style json + */ + @Nullable + public String getStyleJson() { + return builder == null ? null : builder.getJson(); } /** @@ -329,6 +365,7 @@ public class MapSnapshotter { public MapSnapshotter(@NonNull Context context, @NonNull Options options) { checkThread(); this.context = context.getApplicationContext(); + this.options = options; TelemetryDefinition telemetry = Mapbox.getTelemetry(); if (telemetry != null) { telemetry.onAppUserTurnstileEvent(); @@ -340,10 +377,11 @@ public class MapSnapshotter { } nativeInitialize(this, fileSource, options.pixelRatio, options.width, - options.height, options.styleUri, options.styleJson, options.region, options.cameraPosition, + options.height, options.getStyleUri(), options.getStyleJson(), options.region, options.cameraPosition, options.showLogo, options.localIdeographFontFamily); } + /** * Starts loading and rendering the snapshot. The callback will be fired * on the calling thread. @@ -412,6 +450,57 @@ public class MapSnapshotter { @Keep public native void setStyleJson(String styleJson); + /** + * Adds the layer to the map. The layer must be newly created and not added to the snapshotter before + * + * @param layer the layer to add + * @param below the layer id to add this layer before + */ + private void addLayerBelow(Layer layer, String below) { + nativeAddLayerBelow(layer.getNativePtr(), below); + } + + /** + * Adds the layer to the map. The layer must be newly created and not added to the snapshotter before + * + * @param layer the layer to add + * @param above the layer id to add this layer above + */ + private void addLayerAbove(@NonNull Layer layer, @NonNull String above) { + nativeAddLayerAbove(layer.getNativePtr(), above); + } + + /** + * Adds the layer to the snapshotter at the specified index. The layer must be newly + * created and not added to the snapshotter before + * + * @param layer the layer to add + * @param index the index to insert the layer at + */ + private void addLayerAt(Layer layer, int index) { + nativeAddLayerAt(layer.getNativePtr(), index); + } + + /** + * Adds the source to the map. The source must be newly created and not added to the map before + * + * @param source the source to add + */ + private void addSource(Source source) { + nativeAddSource(source, source.getNativePtr()); + } + + /** + * Adds an image to be used in the snapshotter's style + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + */ + private void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { + nativeAddImages(new Image[] {toImage(new Style.Builder.ImageWrapper(name, bitmap, sdf))}); + } + /** * Must be called in on the thread * the object was created on. @@ -609,6 +698,54 @@ public class MapSnapshotter { } } + /** + * Called by JNI peer when snapshot style is ready. + */ + @Keep + protected void onDidFailLoadingStyle(String reason) { + onSnapshotFailed(reason); + } + + /** + * Called by JNI peer when snapshot style is loaded. + */ + @Keep + protected void onDidFinishLoadingStyle() { + if (!fullyLoaded) { + fullyLoaded = true; + Style.Builder builder = options.getBuilder(); + if (builder != null) { + for (Source source : builder.getSources()) { + nativeAddSource(source, source.getNativePtr()); + } + + for (Style.Builder.LayerWrapper layerWrapper : builder.getLayers()) { + if (layerWrapper instanceof Style.Builder.LayerAtWrapper) { + addLayerAt(layerWrapper.getLayer(), ((Style.Builder.LayerAtWrapper) layerWrapper).getIndex()); + } else if (layerWrapper instanceof Style.Builder.LayerAboveWrapper) { + addLayerAbove(layerWrapper.getLayer(), ((Style.Builder.LayerAboveWrapper) layerWrapper).getAboveLayer()); + } else if (layerWrapper instanceof Style.Builder.LayerBelowWrapper) { + addLayerBelow(layerWrapper.getLayer(), ((Style.Builder.LayerBelowWrapper) layerWrapper).getBelowLayer()); + } else { + addLayerBelow(layerWrapper.getLayer(), MapboxConstants.LAYER_ID_ANNOTATIONS); + } + } + + for (Style.Builder.ImageWrapper image : builder.getImages()) { + addImage(image.getId(), image.getBitmap(), image.isSdf()); + } + } + } + } + + /** + * Called by JNI peer when snapshot style image is missing. + */ + @Keep + protected void onStyleImageMissing(String imageName) { + onSnapshotFailed("style image is missing: " + imageName); + } + private void checkThread() { ThreadUtils.checkThread(TAG); } @@ -631,6 +768,21 @@ public class MapSnapshotter { @Keep protected native void nativeCancel(); + @Keep + private native void nativeAddLayerBelow(long layerPtr, String below); + + @Keep + private native void nativeAddLayerAbove(long layerPtr, String above); + + @Keep + private native void nativeAddLayerAt(long layerPtr, int index); + + @Keep + private native void nativeAddSource(Source source, long sourcePtr); + + @Keep + private native void nativeAddImages(Image[] images); + @Override @Keep protected native void finalize() throws Throwable; @@ -640,7 +792,7 @@ public class MapSnapshotter { private Bitmap small; private float scale; - public Logo(Bitmap large, Bitmap small, float scale) { + Logo(Bitmap large, Bitmap small, float scale) { this.large = large; this.small = small; this.scale = scale; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java index 0dd0df0b2..1e5669f59 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java @@ -15,21 +15,24 @@ public class CustomLayer extends Layer { initialize(id, host); } + /** + * Triggers map re-paint. + * + * @deprecated Use {@link MapboxMap#triggerRepaint()} instead. + */ + @Deprecated + @Keep + public void update() { + } + @Keep CustomLayer(long nativePtr) { super(nativePtr); } - public void update() { - nativeUpdate(); - } - @Keep protected native void initialize(String id, long host); - @Keep - protected native void nativeUpdate(); - @Override @Keep protected native void finalize() throws Throwable; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt index 167656610..b87cc4b6f 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt @@ -5,13 +5,14 @@ import androidx.test.rule.ActivityTestRule import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.style.layers.BackgroundLayer +import com.mapbox.mapboxsdk.style.layers.PropertyFactory import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException import junit.framework.Assert.assertNotNull import org.junit.Assert -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -20,7 +21,6 @@ import org.junit.runner.RunWith * Integration test that validates if a snapshotter creation */ @RunWith(AndroidJUnit4::class) -@Ignore("Ignored until https://github.com/mapbox/mapbox-gl-native/issues/11669 is resolved.") class MapSnapshotterTest { @Rule @@ -31,18 +31,22 @@ class MapSnapshotterTest { @Test fun mapSnapshotter() { + var mapSnapshotter: MapSnapshotter? rule.activity.runOnUiThread { + val bg = BackgroundLayer("rand_tint") + bg.setProperties(PropertyFactory.backgroundColor("rgba(255,128,0,0.7)")) val options = MapSnapshotter.Options(512, 512) .withPixelRatio(1.0f) - .withStyle(Style.SATELLITE_STREETS) + .withStyleBuilder(Style.Builder().fromUri(Style.SATELLITE_STREETS) + .withLayerAbove(bg, "country-label")) .withCameraPosition( CameraPosition.Builder() .zoom(12.0) .target(LatLng(51.145495, 5.742234)) .build() ) - val mapSnapshotter = MapSnapshotter(rule.activity, options) - mapSnapshotter.start({ + mapSnapshotter = MapSnapshotter(rule.activity, options) + mapSnapshotter!!.start({ assertNotNull(it) assertNotNull(it.bitmap) countDownLatch.countDown() diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index cb9d37e4e..3538be8af 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -363,9 +363,21 @@ android:value=".activity.FeatureOverviewActivity" />
    + android:name=".activity.snapshot.MapSnapshotterBitMapOverlayActivity" + android:description="@string/description_map_snapshotter_bitmap_overlay" + android:label="@string/activity_map_snapshotter_bitmap_overlay"> + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java index 514d362c2..92ee75c20 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java @@ -68,8 +68,8 @@ public class CustomLayerActivity extends AppCompatActivity { } private void updateLayer() { - if (customLayer != null) { - customLayer.update(); + if (mapboxMap != null) { + mapboxMap.triggerRepaint(); } } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestDefinition.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestDefinition.java index 3cff4cad5..fbd8251be 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestDefinition.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestDefinition.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.testapp.activity.render; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; public class RenderTestDefinition { @@ -75,7 +76,7 @@ public class RenderTestDefinition { public MapSnapshotter.Options toOptions() { return new MapSnapshotter .Options(getWidth(), getHeight()) - .withStyleJson(styleJson) + .withStyleBuilder(new Style.Builder().fromJson(styleJson)) .withPixelRatio(getPixelRatio()) .withLogo(false); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java index c15cf4f25..c01254862 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java @@ -1,31 +1,64 @@ package com.mapbox.mapboxsdk.testapp.activity.snapshot; +import android.graphics.Bitmap; +import android.graphics.Color; import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; import android.view.ViewTreeObserver; import android.widget.GridLayout; import android.widget.ImageView; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; +import com.mapbox.mapboxsdk.style.layers.Property; +import com.mapbox.mapboxsdk.style.layers.RasterLayer; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; +import com.mapbox.mapboxsdk.style.sources.RasterSource; +import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.utils.BitmapUtils; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Random; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import timber.log.Timber; +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; +import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; +import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; +import static com.mapbox.mapboxsdk.style.expressions.Expression.toBool; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAnchor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; + /** * Test activity showing how to use a the {@link com.mapbox.mapboxsdk.snapshotter.MapSnapshotter} */ public class MapSnapshotterActivity extends AppCompatActivity { + private static final String ID_FEATURE_PROPERTY = "id"; + private static final String SELECTED_FEATURE_PROPERTY = "selected"; + private static final String TITLE_FEATURE_PROPERTY = "title"; + // layer & source constants + private static final String MARKER_SOURCE = "marker-source"; + private static final String MARKER_LAYER = "marker-layer"; - private GridLayout grid; + public GridLayout grid; private List snapshotters = new ArrayList<>(); @Override @@ -58,6 +91,9 @@ public class MapSnapshotterActivity extends AppCompatActivity { } private void startSnapShot(final int row, final int column) { + // Optionally the style + Style.Builder builder = new Style.Builder() + .fromUri((column + row) % 2 == 0 ? Style.MAPBOX_STREETS : Style.DARK); // Define the dimensions MapSnapshotter.Options options = new MapSnapshotter.Options( @@ -66,9 +102,6 @@ public class MapSnapshotterActivity extends AppCompatActivity { ) // Optionally the pixel ratio .withPixelRatio(1) - - // Optionally the style - .withStyle((column + row) % 2 == 0 ? Style.MAPBOX_STREETS : Style.DARK) .withLocalIdeographFontFamily(MapboxConstants.DEFAULT_FONT); // Optionally the visible region @@ -88,14 +121,52 @@ public class MapSnapshotterActivity extends AppCompatActivity { : new LatLng(randomInRange(-80, 80), randomInRange(-160, 160))) .bearing(randomInRange(0, 360)) .tilt(randomInRange(0, 60)) - .zoom(randomInRange(0, 20)) + .zoom(randomInRange(0, 10)) + .padding(1, 1, 1, 1) + .build() + ); + } + if (row == 0 && column == 0) { + // Add a source + Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite", 512); + builder.withLayerAbove(new RasterLayer("satellite-layer", "my-raster-source"), "country-label"); + builder.withSource(source); + } else if (row == 0 && column == 2) { + + Bitmap carBitmap = BitmapUtils.getBitmapFromDrawable( + getResources().getDrawable(R.drawable.ic_directions_car_black)); + + // marker source + FeatureCollection markerCollection = FeatureCollection.fromFeatures(new Feature[] { + Feature.fromGeometry(Point.fromLngLat(4.91638, 52.34673), featureProperties("2", "Car")) + }); + Source markerSource = new GeoJsonSource(MARKER_SOURCE, markerCollection); + + // marker layer + SymbolLayer markerSymbolLayer = new SymbolLayer(MARKER_LAYER, MARKER_SOURCE) + .withProperties( + iconImage(get(TITLE_FEATURE_PROPERTY)), + iconIgnorePlacement(true), + iconAllowOverlap(true), + iconSize(switchCase(toBool(get(SELECTED_FEATURE_PROPERTY)), literal(1.5f), literal(1.0f))), + iconAnchor(Property.ICON_ANCHOR_BOTTOM), + iconColor(Color.BLUE) + ); + + builder.withImage("Car", Objects.requireNonNull(carBitmap), false) + .withSources(markerSource) + .withLayers(markerSymbolLayer); + options.withCameraPosition(new CameraPosition.Builder() + .target(new LatLng(5.537109374999999, + 52.07950600379697)) + .zoom(1) .padding(1, 1, 1, 1) .build() ); } + options.withStyleBuilder(builder); MapSnapshotter snapshotter = new MapSnapshotter(MapSnapshotterActivity.this, options); - snapshotter.start(snapshot -> { Timber.i("Got the snapshot"); ImageView imageView = new ImageView(MapSnapshotterActivity.this); @@ -125,4 +196,11 @@ public class MapSnapshotterActivity extends AppCompatActivity { return (random.nextFloat() * (max - min)) + min; } + private JsonObject featureProperties(@NonNull String id, @NonNull String title) { + JsonObject object = new JsonObject(); + object.add(ID_FEATURE_PROPERTY, new JsonPrimitive(id)); + object.add(TITLE_FEATURE_PROPERTY, new JsonPrimitive(title)); + object.add(SELECTED_FEATURE_PROPERTY, new JsonPrimitive(false)); + return object; + } } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterBitMapOverlayActivity.java similarity index 92% rename from MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java rename to MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterBitMapOverlayActivity.java index 5190bce90..d2ab581a9 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterMarkerActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterBitMapOverlayActivity.java @@ -6,26 +6,29 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.PointF; import android.os.Bundle; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import androidx.appcompat.app.AppCompatActivity; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; + import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.snapshotter.MapSnapshot; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; import com.mapbox.mapboxsdk.testapp.R; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AppCompatActivity; import timber.log.Timber; /** * Test activity showing how to use a the {@link MapSnapshotter} and overlay * {@link android.graphics.Bitmap}s on top. */ -public class MapSnapshotterMarkerActivity extends AppCompatActivity implements MapSnapshotter.SnapshotReadyCallback { +public class MapSnapshotterBitMapOverlayActivity extends AppCompatActivity + implements MapSnapshotter.SnapshotReadyCallback { private MapSnapshotter mapSnapshotter; private MapSnapshot mapSnapshot; @@ -49,10 +52,10 @@ public class MapSnapshotterMarkerActivity extends AppCompatActivity implements M getApplicationContext(), new MapSnapshotter .Options(Math.min(container.getMeasuredWidth(), 1024), Math.min(container.getMeasuredHeight(), 1024)) - .withStyle(Style.OUTDOORS) + .withStyleBuilder(new Style.Builder().fromUri(Style.OUTDOORS)) .withCameraPosition(new CameraPosition.Builder().target(new LatLng(52.090737, 5.121420)).zoom(15).build()) ); - mapSnapshotter.start(MapSnapshotterMarkerActivity.this); + mapSnapshotter.start(MapSnapshotterBitMapOverlayActivity.this); } }); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterHeatMapActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterHeatMapActivity.java new file mode 100644 index 000000000..77e698b02 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterHeatMapActivity.java @@ -0,0 +1,174 @@ +package com.mapbox.mapboxsdk.testapp.activity.snapshot; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.ImageView; + +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.snapshotter.MapSnapshot; +import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; +import com.mapbox.mapboxsdk.style.layers.HeatmapLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; +import com.mapbox.mapboxsdk.style.sources.Source; +import com.mapbox.mapboxsdk.testapp.R; + +import org.jetbrains.annotations.NotNull; + +import java.net.URI; +import java.net.URISyntaxException; + +import androidx.appcompat.app.AppCompatActivity; +import timber.log.Timber; + +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; +import static com.mapbox.mapboxsdk.style.expressions.Expression.heatmapDensity; +import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; +import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; +import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; +import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb; +import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba; +import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; +import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapIntensity; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapOpacity; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapRadius; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapWeight; + +/** + * Test activity showing how to use a the {@link MapSnapshotter} and heatmap layer on it. + */ +public class MapSnapshotterHeatMapActivity extends AppCompatActivity implements MapSnapshotter.SnapshotReadyCallback { + private static final String EARTHQUAKE_SOURCE_URL = "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"; + private static final String EARTHQUAKE_SOURCE_ID = "earthquakes"; + private static final String HEATMAP_LAYER_ID = "earthquakes-heat"; + private static final String HEATMAP_LAYER_SOURCE = "earthquakes"; + private MapSnapshotter mapSnapshotter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_map_snapshotter_marker); + + final View container = findViewById(R.id.container); + container.getViewTreeObserver() + .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + //noinspection deprecation + container.getViewTreeObserver().removeGlobalOnLayoutListener(this); + + Timber.i("Starting snapshot"); + + Style.Builder builder = new Style.Builder().fromUri(Style.OUTDOORS) + .withSource(getEarthquakeSource()) + .withLayerAbove(getHeatmapLayer(), "waterway-label"); + + mapSnapshotter = new MapSnapshotter( + getApplicationContext(), + new MapSnapshotter + .Options(container.getMeasuredWidth(), container.getMeasuredHeight()) + .withStyleBuilder(builder) + .withCameraPosition(new CameraPosition.Builder() + .target(new LatLng(15, -94)) + .zoom(5) + .padding(1, 1, 1, 1) + .build() + ) + ); + mapSnapshotter.start(MapSnapshotterHeatMapActivity.this); + } + }); + } + + @NotNull + private HeatmapLayer getHeatmapLayer() { + HeatmapLayer layer = new HeatmapLayer(HEATMAP_LAYER_ID, EARTHQUAKE_SOURCE_ID); + layer.setMaxZoom(9); + layer.setSourceLayer(HEATMAP_LAYER_SOURCE); + layer.setProperties( + + // Color ramp for heatmap. Domain is 0 (low) to 1 (high). + // Begin color ramp at 0-stop with a 0-transparency color + // to create a blur-like effect. + heatmapColor( + interpolate( + linear(), heatmapDensity(), + literal(0), rgba(33, 102, 172, 0), + literal(0.2), rgb(103, 169, 207), + literal(0.4), rgb(209, 229, 240), + literal(0.6), rgb(253, 219, 199), + literal(0.8), rgb(239, 138, 98), + literal(1), rgb(178, 24, 43) + ) + ), + + // Increase the heatmap weight based on frequency and property magnitude + heatmapWeight( + interpolate( + linear(), get("mag"), + stop(0, 0), + stop(6, 1) + ) + ), + + // Increase the heatmap color weight weight by zoom level + // heatmap-intensity is a multiplier on top of heatmap-weight + heatmapIntensity( + interpolate( + linear(), zoom(), + stop(0, 1), + stop(9, 3) + ) + ), + + // Adjust the heatmap radius by zoom level + heatmapRadius( + interpolate( + linear(), zoom(), + stop(0, 2), + stop(9, 20) + ) + ), + + // Transition from heatmap to circle layer by zoom level + heatmapOpacity( + interpolate( + linear(), zoom(), + stop(7, 1), + stop(9, 0) + ) + ) + ); + return layer; + } + + @Override + protected void onStop() { + super.onStop(); + mapSnapshotter.cancel(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public void onSnapshotReady(MapSnapshot snapshot) { + Timber.i("Snapshot ready"); + ImageView imageView = findViewById(R.id.snapshot_image); + imageView.setImageBitmap(snapshot.getBitmap()); + } + + private Source getEarthquakeSource() { + Source source = null; + try { + source = new GeoJsonSource(EARTHQUAKE_SOURCE_ID, new URI(EARTHQUAKE_SOURCE_URL)); + } catch (URISyntaxException uriSyntaxException) { + Timber.e(uriSyntaxException, "That's not an url... "); + } + return source; + } + +} diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java index 1dda9f655..3b8c9ae72 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java @@ -7,6 +7,7 @@ import android.view.ViewTreeObserver; import android.widget.ImageView; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.snapshotter.MapSnapshot; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; import com.mapbox.mapboxsdk.testapp.R; @@ -48,7 +49,7 @@ public class MapSnapshotterLocalStyleActivity extends AppCompatActivity getApplicationContext(), new MapSnapshotter .Options(Math.min(container.getMeasuredWidth(), 1024), Math.min(container.getMeasuredHeight(), 1024)) - .withStyleJson(styleJson) + .withStyleBuilder(new Style.Builder().fromJson(styleJson)) .withCameraPosition(new CameraPosition.Builder().target(new LatLng(52.090737, 5.121420)).zoom(18).build()) ); mapSnapshotter.start(MapSnapshotterLocalStyleActivity.this, error -> Timber.e(error)); diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java index 6b54ff9d5..198727277 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterReuseActivity.java @@ -1,20 +1,21 @@ package com.mapbox.mapboxsdk.testapp.activity.snapshot; import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.snapshotter.MapSnapshot; import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter; import com.mapbox.mapboxsdk.testapp.R; import java.util.Random; +import androidx.appcompat.app.AppCompatActivity; + /** * Test activity showing how to use a the {@link MapSnapshotter} */ @@ -49,7 +50,7 @@ public class MapSnapshotterReuseActivity extends AppCompatActivity implements Ma mapSnapshotter = new MapSnapshotter( getApplicationContext(), - new MapSnapshotter.Options(512, 512) + new MapSnapshotter.Options(512, 512).withStyleBuilder(new Style.Builder().fromUri(getRandomStyle())) ); mapSnapshotter.start(MapSnapshotterReuseActivity.this); diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 32ca4de17..c49c93fb7 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -61,7 +61,8 @@ Show 2 MapView on screen with a bottom sheet Show a static bitmap taken with the MapSnapshotter Show how to reuse a MapSnapshotter instance - Show how to add a marker to a Snapshot + Show how to add a bitmap overlay to a Snapshot + Show how to add a heatmap layer to a Snapshot Show how to load a local style with a Snapshot Use Android SDK Animators to animate camera position changes Use Android SDK Views as symbols diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 0089648ff..91f487ee2 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -59,7 +59,8 @@ Bottom sheet Map Snapshotter Map Snapshotter Reuse - Map Snapshot with marker + Map Snapshot with bitmap overlay + Map Snapshot with heatmap layer Map Snapshot with local style Animator animation SymbolGenerator diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index a601f9474..3f45b0a24 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit a601f94743eb812847fbb58944df7240b088f7e2 +Subproject commit 3f45b0a24b5b608dfa75c84308d1ab0deb6159ee From 6984dbf155c6a1f26388481a2d8ab0979978dfa6 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Wed, 25 Mar 2020 07:42:23 -0400 Subject: [PATCH 104/185] Add getLayer and getSource snapshotter methods (#292) * Expose snapshotter layer and source objects * Add example snapshotter + within activity * Bump vendor/mapbox-gl-native --- .../mapboxsdk/snapshotter/MapSnapshotter.java | 62 ++++ .../src/main/AndroidManifest.xml | 11 + .../turf/MapSnapshotterWithinExpression.kt | 274 ++++++++++++++++++ ...ivity_mapsnapshotter_within_expression.xml | 30 ++ .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/titles.xml | 1 + vendor/mapbox-gl-native | 2 +- 7 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/MapSnapshotterWithinExpression.kt create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapsnapshotter_within_expression.xml diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 26af5157a..dcbcb22b9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -64,6 +64,8 @@ public class MapSnapshotter { private SnapshotReadyCallback callback; @Nullable private ErrorHandler errorHandler; + @Nullable + private Observer observer; /** * Get notified on snapshot completion. @@ -97,6 +99,20 @@ public class MapSnapshotter { void onError(String error); } + /** + * Can be used to get notified on snapshotter style loading + * completion. + * + * @see MapSnapshotter#setObserver(Observer) + */ + public interface Observer { + + /** + * Called when snapshotter finishes loading it's style. + */ + void onDidFinishLoadingStyle(); + } + /** * MapSnapshotter options */ @@ -511,6 +527,16 @@ public class MapSnapshotter { nativeCancel(); } + /** + * Sets observer for a snapshotter + * + * @param observer an Observer object + */ + public void setObserver(@Nullable Observer observer) { + checkThread(); + this.observer = observer; + } + /** * Draw an overlay on the map snapshot. * @@ -736,6 +762,34 @@ public class MapSnapshotter { } } } + + if (observer != null) { + observer.onDidFinishLoadingStyle(); + } + } + + /** + * Returns Layer of a style that is used by a snapshotter + * + * @param layerId the id of a Layer + * @return the Layer object if Layer with layerId exists, null otherwise + */ + @Nullable + public Layer getLayer(@NonNull String layerId) { + checkThread(); + return fullyLoaded ? nativeGetLayer(layerId) : null; + } + + /** + * Returns Source of a style that is used by a snapshotter + * + * @param sourceId the id of a Source + * @return the Source object if a Source with sourceId exists, null otherwise + */ + @Nullable + public Source getSource(@NonNull String sourceId) { + checkThread(); + return fullyLoaded ? nativeGetSource(sourceId) : null; } /** @@ -783,6 +837,14 @@ public class MapSnapshotter { @Keep private native void nativeAddImages(Image[] images); + @NonNull + @Keep + private native Layer nativeGetLayer(String layerId); + + @NonNull + @Keep + private native Source nativeGetSource(String sourceId); + @Override @Keep protected native void finalize() throws Throwable; diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 3538be8af..66435115e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -396,6 +396,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + + mapboxMap = map + + // Setup camera position above Georgetown + mapboxMap.cameraPosition = CameraPosition.Builder() + .target(LatLng(38.90628988399711, -77.06574689337494)) + .zoom(15.5) + .build() + + // Wait for the map to become idle before manipulating the style and camera of the map + mapView.addOnDidBecomeIdleListener(object : MapView.OnDidBecomeIdleListener { + override fun onDidBecomeIdle() { + mapboxMap.easeCamera( + CameraUpdateFactory.newCameraPosition( + CameraPosition.Builder() + .zoom(16.0) + .target(LatLng(38.905156245642814, -77.06535338052844)) + .bearing(80.68015859462369) + .tilt(55.0) + .build() + ), 1000 + ) + mapView.removeOnDidBecomeIdleListener(this) + } + }) + // Load mapbox streets and add lines and circles + setupStyle() + } + } + + private fun setupStyle() { + // Assume the route is represented by an array of coordinates. + val coordinates = listOf( + Point.fromLngLat( + -77.06866264343262, + 38.90506061276737 + ), + Point.fromLngLat( + -77.06283688545227, + 38.905194197410545 + ), + Point.fromLngLat( + -77.06285834312439, + 38.906429843444094 + ), + Point.fromLngLat( + -77.0630407333374, + 38.90680554236621 + ) + ) + + // Setup style with additional layers, + // using Style.MAPBOX_STREETS as a base style + mapboxMap.setStyle( + Style.Builder() + .fromUri(Style.MAPBOX_STREETS) + ) { + mapView.addOnCameraDidChangeListener(cameraListener) + } + + val options = MapSnapshotter.Options(imageView.measuredWidth / 2, imageView.measuredHeight / 2) + .withCameraPosition(mapboxMap.cameraPosition) + .withPixelRatio(2.0f) + .withStyleBuilder(Style.Builder() + .fromUri(Style.MAPBOX_STREETS) + .withSources( + GeoJsonSource( + POINT_ID, LineString.fromLngLats(coordinates) + ), + GeoJsonSource( + FILL_ID, + FeatureCollection.fromFeature(Feature.fromGeometry(bufferLineStringGeometry())), + GeoJsonOptions().withBuffer(0).withTolerance(0.0f) + ) + ) + .withLayerBelow( + LineLayer(LINE_ID, POINT_ID) + .withProperties(lineWidth(7.5f), lineColor(Color.LTGRAY)), + "poi-label" + ) + .withLayerBelow( + CircleLayer(POINT_ID, POINT_ID) + .withProperties( + circleRadius(7.5f), + circleColor(Color.DKGRAY), + circleOpacity(0.75f) + ), "poi-label" + ).withLayerBelow( + FillLayer(FILL_ID, FILL_ID) + .withProperties( + fillOpacity(0.12f), + fillColor(Color.YELLOW) + ), LINE_ID + )) + snapshotter = MapSnapshotter(this, options) + snapshotter.setObserver(snapshotterObserver) + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + override fun onDestroy() { + super.onDestroy() + mapView.onDestroy() + } + + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) + outState?.let { + mapView.onSaveInstanceState(it) + } + } + + private fun bufferLineStringGeometry(): Polygon { + // TODO replace static data by Turf#Buffer: mapbox-java/issues/987 + return FeatureCollection.fromJson( + """ + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -77.06867337226866, + 38.90467655551809 + ], + [ + -77.06233263015747, + 38.90479344272695 + ], + [ + -77.06234335899353, + 38.906463238984344 + ], + [ + -77.06290125846863, + 38.907206285691615 + ], + [ + -77.06364154815674, + 38.90684728656818 + ], + [ + -77.06326603889465, + 38.90637140121084 + ], + [ + -77.06321239471436, + 38.905561553883246 + ], + [ + -77.0691454410553, + 38.905436318935635 + ], + [ + -77.06912398338318, + 38.90466820642439 + ], + [ + -77.06867337226866, + 38.90467655551809 + ] + ] + ] + } + } + ] + } + """.trimIndent() + ).features()!![0].geometry() as Polygon + } + + companion object { + const val POINT_ID = "point" + const val FILL_ID = "fill" + const val LINE_ID = "line" + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapsnapshotter_within_expression.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapsnapshotter_within_expression.xml new file mode 100644 index 000000000..121af0e14 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapsnapshotter_within_expression.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index c49c93fb7..f90653ffe 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -28,6 +28,7 @@ Add a polygon to a map Scroll with pixels in x,y direction Example to make a snapshot of the map + Example of snapshotter with within expression 2 maps in a view hierarchy Learn how to create a dynamic custom InfoWindow Use SupportMapFragments in a ViewPager diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 91f487ee2..637d3b774 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -21,6 +21,7 @@ Scroll By Method Double Map Activity Snapshot Activity + Snapshot with within expression Custom Layer Map Padding Debug Mode diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 3f45b0a24..fd1f8703c 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 3f45b0a24b5b608dfa75c84308d1ab0deb6159ee +Subproject commit fd1f8703cdd73420f23cb8617ffb6f5c42f8a32d From 4b0cd4025f88423ddc615314ab947b29b6db5dea Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 25 Mar 2020 14:58:59 +0100 Subject: [PATCH 105/185] [glyph] rework local glyph generation to use RGB values vs alpha (#289) --- .../java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java | 3 +-- vendor/mapbox-gl-native | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java index d698fb181..7d83884cc 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java @@ -4,7 +4,6 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Bitmap; -import android.graphics.PorterDuff; import android.graphics.Typeface; import androidx.annotation.Keep; import androidx.annotation.NonNull; @@ -52,7 +51,7 @@ public class LocalGlyphRasterizer { @WorkerThread protected Bitmap drawGlyphBitmap(String fontFamily, boolean bold, char glyphID) { paint.setTypeface(Typeface.create(fontFamily, bold ? Typeface.BOLD : Typeface.NORMAL)); - canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + canvas.drawColor(Color.WHITE); canvas.drawText(String.valueOf(glyphID), 0, 20, paint); return bitmap; } diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index fd1f8703c..d4db3b112 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit fd1f8703cdd73420f23cb8617ffb6f5c42f8a32d +Subproject commit d4db3b11267d9ac22fc53991a383f95f95e607ea From fbea14a8bc7253f448c3346e7019d4a9f0e54779 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 26 Mar 2020 16:24:55 +0800 Subject: [PATCH 106/185] bump telemetry to 5.0.0, core to 2.0.0 (#293) --- gradle/dependencies.gradle | 4 ++-- vendor/mapbox-events-android | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index daca6ecbc..f82887222 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,8 +8,8 @@ ext { versions = [ mapboxServices : '5.0.0', - mapboxTelemetry : '4.7.3', - mapboxCore : '1.4.1', + mapboxTelemetry : '5.0.0', + mapboxCore : '2.0.0', mapboxGestures : '0.6.0', mapboxAccounts : '0.7.0', appCompat : '1.0.0', diff --git a/vendor/mapbox-events-android b/vendor/mapbox-events-android index 7945e61bc..0b46d29ef 160000 --- a/vendor/mapbox-events-android +++ b/vendor/mapbox-events-android @@ -1 +1 @@ -Subproject commit 7945e61bccc1df3b04ca2e80cb25459dfeea01dd +Subproject commit 0b46d29efd23d870e1f084f0591091a16169c800 From 585253ed0dbd321e02dda7d27c91c2036c17f9a8 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 27 Mar 2020 12:54:53 +0800 Subject: [PATCH 107/185] Bump gl-native to 1.5.0 (#296) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index d4db3b112..77466d23d 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit d4db3b11267d9ac22fc53991a383f95f95e607ea +Subproject commit 77466d23d6b2f524c104373d546ac458035b0ec0 From ab1aed9b04eb2b26c6d6090e841abb2468d18cb2 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 27 Mar 2020 12:58:44 +0800 Subject: [PATCH 108/185] Update change log for 9.1.0-beta.2 (#295) * Update change log for 9.1.0-beta.2 * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Chloe Krawczyk --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 099994f71..23b488193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,11 @@ Mapbox welcomes participation and contributions from everyone. Please read [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) to get started. ## 9.1.0 -This beta release includes a feature with a known issue: the `within` expression evaluates point features inconsistently across zoom levels if the point lies near the boundary of a GeoJSON object ([#16301](https://github.com/mapbox/mapbox-gl-native/issues/16301])). ### Features - Added `within` expression for testing whether an evaluated feature lies within a given GeoJSON object. `within` accepts `Feature`, `FeatureCollection`, `Polygon`, and `MultiPolygon` as valid GeoJSON objects. ([#198](https://github.com/mapbox/mapbox-gl-native-android/pull/198)) - Added `in` expression for testing whether an item exists in an array or a substring exists in a string. ([#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171)) + - Introduced APIs and callbacks for customizing the style used in a `MapSnapshotter` snapshotter with runtime styling methods. ([#268](https://www.github.com/mapbox/mapbox-gl-native-android/pull/268), [#292](https://www.github.com/mapbox/mapbox-gl-native-android/pull/292)) - Added methods to set and get the sort key of features in a `FillLayer` and `LineLayer` at runtime. Features with a higher sort key will appear above features with a lower sort key. ([#209](https://github.com/mapbox/mapbox-gl-native-android/pull/209)) - Introduced option to set the minimum and maximum pitch of a map. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) - Introduced ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. ([#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184)) @@ -24,9 +24,10 @@ This beta release includes a feature with a known issue: the `within` expression - Fixed an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) - Fixed Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) - Fixed a crash that might occur during EGL window surface creation. ([#278](https://github.com/mapbox/mapbox-gl-native-android/pull/278)) + - Fixed a bug that would cause local CJK glyphs to be rendered incorrectly when generated on a device with the high-contrast accessibility setting enabled. ([#289](https://github.com/mapbox/mapbox-gl-native-android/pull/289)) ### Other changes - - Updated mapbox-events-android to v4.7.3. ([#201](https://github.com/mapbox/mapbox-gl-native-android/pull/201)) + - Updated mapbox-events-android to v5.0.0. ([#294](https://github.com/mapbox/mapbox-gl-native-android/pull/294)) ## 9.0.1 - March 11, 2020 [Changes](https://github.com/mapbox/mapbox-gl-native-android/compare/android-v9.0.0...android-v9.0.1) since [Mapbox Maps SDK for Android v9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0): From dbace6a779b387f49266ba6cd5085e78190b004f Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 27 Mar 2020 16:38:47 +0800 Subject: [PATCH 109/185] Update change log for 9.1.0-beta.2 (#295) (#297) * Update change log for 9.1.0-beta.2 * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md * Update CHANGELOG.md Co-Authored-By: Chloe Krawczyk * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Chloe Krawczyk (cherry picked from commit ab1aed9b04eb2b26c6d6090e841abb2468d18cb2) From dbdc053db19a3efff1a9458cdbe53fdfb83b78c6 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Mon, 30 Mar 2020 21:29:03 +0800 Subject: [PATCH 110/185] Update ccache config (#298) --- MapboxGLAndroidSDK/build.gradle | 5 ----- gradle/native-build.gradle | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/build.gradle b/MapboxGLAndroidSDK/build.gradle index 06700ad8a..5ee3af61e 100644 --- a/MapboxGLAndroidSDK/build.gradle +++ b/MapboxGLAndroidSDK/build.gradle @@ -34,11 +34,6 @@ android { buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"mapbox-maps-android/%s\"", project.VERSION_NAME) consumerProguardFiles 'proguard-rules.pro' - externalNativeBuild { - cmake { - arguments '-DANDROID_CCACHE=ccache' - } - } } // build native libraries diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index 48d430fda..31813cbe2 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -44,6 +44,8 @@ ext.nativeBuild = { nativeTargets -> // Enable ccache if the user has installed it. if (file("/usr/bin/ccache").exists()) { arguments "-DANDROID_CCACHE=/usr/bin/ccache" + } else if (file("/usr/local/bin/ccache").exists()) { + arguments "-DANDROID_CCACHE=/usr/local/bin/ccache" } cFlags "-Qunused-arguments" From dceba083117f32721bd36dc31eec7f9b5aeebce1 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 1 Apr 2020 18:09:15 +0800 Subject: [PATCH 111/185] Fix Expression can't convert `within` json error (#305) --- .../com/mapbox/mapboxsdk/style/expressions/Expression.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 9cc9554ca..f27a4f738 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -4746,7 +4746,9 @@ public class Expression { final String operator = jsonArray.get(0).getAsString(); final List arguments = new ArrayList<>(); - + if (operator.equals("within")) { + return within(Polygon.fromJson(jsonArray.get(1).toString())); + } for (int i = 1; i < jsonArray.size(); i++) { JsonElement jsonElement = jsonArray.get(i); if (operator.equals("literal") && jsonElement instanceof JsonArray) { From 620bda356cf082bc56f8bf82b071dd79ee5ace39 Mon Sep 17 00:00:00 2001 From: Pablo Guardiola Date: Thu, 2 Apr 2020 09:33:55 -0400 Subject: [PATCH 112/185] fix proguard telemetry events rule (#306) --- MapboxGLAndroidSDK/proguard-rules.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/proguard-rules.pro b/MapboxGLAndroidSDK/proguard-rules.pro index 9367d296a..864910617 100644 --- a/MapboxGLAndroidSDK/proguard-rules.pro +++ b/MapboxGLAndroidSDK/proguard-rules.pro @@ -28,7 +28,7 @@ -dontwarn com.google.auto.value.** # config for telemetry events --keep class com.mapbox.mapboxsdk.module.telemetry.** +-keep class com.mapbox.mapboxsdk.module.telemetry.** { *; } # config for additional notes -dontnote org.robolectric.Robolectric From daecbed823b3e02044d7e91f689a0ea3e01bf25a Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Thu, 2 Apr 2020 19:45:56 +0300 Subject: [PATCH 113/185] Move JNI bindings code from mapbox-gl-native to this repo. (#301) --- MapboxGLAndroidSDK/src/cpp/CMakeLists.txt | 206 +++ .../src/cpp/android_renderer_backend.cpp | 67 + .../src/cpp/android_renderer_backend.hpp | 43 + .../src/cpp/android_renderer_frontend.cpp | 143 ++ .../src/cpp/android_renderer_frontend.hpp | 68 + .../src/cpp/annotation/marker.cpp | 23 + .../src/cpp/annotation/marker.hpp | 28 + .../src/cpp/annotation/multi_point.hpp | 34 + .../src/cpp/annotation/polygon.cpp | 40 + .../src/cpp/annotation/polygon.hpp | 21 + .../src/cpp/annotation/polyline.cpp | 31 + .../src/cpp/annotation/polyline.hpp | 21 + MapboxGLAndroidSDK/src/cpp/asset_manager.hpp | 14 + .../src/cpp/asset_manager_file_source.cpp | 65 + .../src/cpp/asset_manager_file_source.hpp | 30 + .../src/cpp/connectivity_listener.cpp | 41 + .../src/cpp/connectivity_listener.hpp | 29 + .../src/cpp/conversion/collection.cpp | 32 + .../src/cpp/conversion/collection.hpp | 18 + .../src/cpp/conversion/color.cpp | 17 + .../src/cpp/conversion/color.hpp | 18 + .../src/cpp/conversion/constant.cpp | 62 + .../src/cpp/conversion/constant.hpp | 110 ++ .../src/cpp/conversion/conversion.hpp | 50 + MapboxGLAndroidSDK/src/cpp/file_source.cpp | 252 ++++ MapboxGLAndroidSDK/src/cpp/file_source.hpp | 83 ++ .../src/cpp/geojson/feature.cpp | 88 ++ .../src/cpp/geojson/feature.hpp | 24 + .../src/cpp/geojson/feature_collection.cpp | 37 + .../src/cpp/geojson/feature_collection.hpp | 26 + .../src/cpp/geojson/geometry.cpp | 97 ++ .../src/cpp/geojson/geometry.hpp | 28 + .../src/cpp/geojson/geometry_collection.cpp | 47 + .../src/cpp/geojson/geometry_collection.hpp | 26 + .../src/cpp/geojson/line_string.cpp | 55 + .../src/cpp/geojson/line_string.hpp | 36 + .../src/cpp/geojson/multi_line_string.cpp | 56 + .../src/cpp/geojson/multi_line_string.hpp | 34 + .../src/cpp/geojson/multi_point.cpp | 41 + .../src/cpp/geojson/multi_point.hpp | 33 + .../src/cpp/geojson/multi_polygon.cpp | 53 + .../src/cpp/geojson/multi_polygon.hpp | 32 + MapboxGLAndroidSDK/src/cpp/geojson/point.cpp | 34 + MapboxGLAndroidSDK/src/cpp/geojson/point.hpp | 27 + .../src/cpp/geojson/polygon.cpp | 55 + .../src/cpp/geojson/polygon.hpp | 35 + MapboxGLAndroidSDK/src/cpp/geojson/util.hpp | 52 + .../src/cpp/geometry/lat_lng.cpp | 29 + .../src/cpp/geometry/lat_lng.hpp | 29 + .../src/cpp/geometry/lat_lng_bounds.cpp | 30 + .../src/cpp/geometry/lat_lng_bounds.hpp | 26 + .../src/cpp/geometry/lat_lng_quad.cpp | 37 + .../src/cpp/geometry/lat_lng_quad.hpp | 27 + .../src/cpp/geometry/projected_meters.cpp | 17 + .../src/cpp/geometry/projected_meters.hpp | 21 + .../src/cpp/graphics/pointf.cpp | 25 + .../src/cpp/graphics/pointf.hpp | 24 + MapboxGLAndroidSDK/src/cpp/graphics/rectf.cpp | 35 + MapboxGLAndroidSDK/src/cpp/graphics/rectf.hpp | 28 + .../src/cpp/gson/json_array.cpp | 50 + .../src/cpp/gson/json_array.hpp | 24 + .../src/cpp/gson/json_element.cpp | 88 ++ .../src/cpp/gson/json_element.hpp | 24 + .../src/cpp/gson/json_object.cpp | 65 + .../src/cpp/gson/json_object.hpp | 24 + .../src/cpp/gson/json_primitive.cpp | 13 + .../src/cpp/gson/json_primitive.hpp | 21 + .../src/cpp/http_file_source.cpp | 195 +++ MapboxGLAndroidSDK/src/cpp/i18n/collator.cpp | 192 +++ .../src/cpp/i18n/collator_jni.hpp | 62 + .../src/cpp/i18n/number_format.cpp | 80 ++ .../src/cpp/i18n/number_format_jni.hpp | 29 + MapboxGLAndroidSDK/src/cpp/java/util.cpp | 19 + MapboxGLAndroidSDK/src/cpp/java/util.hpp | 81 ++ MapboxGLAndroidSDK/src/cpp/java_types.cpp | 49 + MapboxGLAndroidSDK/src/cpp/java_types.hpp | 43 + MapboxGLAndroidSDK/src/cpp/jni_native.cpp | 168 +++ MapboxGLAndroidSDK/src/cpp/jni_native.hpp | 13 + MapboxGLAndroidSDK/src/cpp/logger.cpp | 34 + MapboxGLAndroidSDK/src/cpp/logger.hpp | 21 + .../src/cpp/logging_android.cpp | 13 + MapboxGLAndroidSDK/src/cpp/main.cpp | 9 + .../src/cpp/map/camera_position.cpp | 69 + .../src/cpp/map/camera_position.hpp | 23 + MapboxGLAndroidSDK/src/cpp/map/image.cpp | 41 + MapboxGLAndroidSDK/src/cpp/map/image.hpp | 21 + MapboxGLAndroidSDK/src/cpp/map_renderer.cpp | 247 ++++ MapboxGLAndroidSDK/src/cpp/map_renderer.hpp | 138 ++ .../src/cpp/map_renderer_runnable.cpp | 49 + .../src/cpp/map_renderer_runnable.hpp | 47 + MapboxGLAndroidSDK/src/cpp/mapbox.cpp | 23 + MapboxGLAndroidSDK/src/cpp/mapbox.hpp | 19 + .../src/cpp/native_map_view.cpp | 1263 +++++++++++++++++ .../src/cpp/native_map_view.hpp | 279 ++++ .../src/cpp/offline/offline_manager.cpp | 335 +++++ .../src/cpp/offline/offline_manager.hpp | 111 ++ .../src/cpp/offline/offline_region.cpp | 314 ++++ .../src/cpp/offline/offline_region.hpp | 92 ++ .../cpp/offline/offline_region_definition.cpp | 107 ++ .../cpp/offline/offline_region_definition.hpp | 43 + .../src/cpp/offline/offline_region_error.cpp | 44 + .../src/cpp/offline/offline_region_error.hpp | 19 + .../src/cpp/offline/offline_region_status.cpp | 38 + .../src/cpp/offline/offline_region_status.hpp | 19 + .../src/cpp/snapshotter/map_snapshot.cpp | 65 + .../src/cpp/snapshotter/map_snapshot.hpp | 48 + .../src/cpp/snapshotter/map_snapshotter.cpp | 353 +++++ .../src/cpp/snapshotter/map_snapshotter.hpp | 87 ++ .../src/cpp/style/android_conversion.hpp | 148 ++ .../src/cpp/style/conversion/filter.cpp | 26 + .../src/cpp/style/conversion/filter.hpp | 16 + .../src/cpp/style/conversion/position.cpp | 24 + .../src/cpp/style/conversion/position.hpp | 25 + .../style/conversion/property_expression.hpp | 23 + .../cpp/style/conversion/property_value.hpp | 62 + .../style/conversion/transition_options.cpp | 17 + .../style/conversion/transition_options.hpp | 21 + .../cpp/style/conversion/url_or_tileset.cpp | 30 + .../cpp/style/conversion/url_or_tileset.hpp | 16 + .../src/cpp/style/formatted.cpp | 54 + .../src/cpp/style/formatted.hpp | 23 + .../src/cpp/style/formatted_section.cpp | 11 + .../src/cpp/style/formatted_section.hpp | 18 + .../src/cpp/style/layers/background_layer.cpp | 148 ++ .../src/cpp/style/layers/background_layer.hpp | 58 + .../src/cpp/style/layers/circle_layer.cpp | 270 ++++ .../src/cpp/style/layers/circle_layer.hpp | 84 ++ .../src/cpp/style/layers/custom_layer.cpp | 61 + .../src/cpp/style/layers/custom_layer.hpp | 41 + .../cpp/style/layers/fill_extrusion_layer.cpp | 225 +++ .../cpp/style/layers/fill_extrusion_layer.hpp | 74 + .../src/cpp/style/layers/fill_layer.cpp | 207 +++ .../src/cpp/style/layers/fill_layer.hpp | 72 + .../src/cpp/style/layers/heatmap_layer.cpp | 163 +++ .../src/cpp/style/layers/heatmap_layer.hpp | 62 + .../src/cpp/style/layers/hillshade_layer.cpp | 181 +++ .../src/cpp/style/layers/hillshade_layer.hpp | 66 + .../src/cpp/style/layers/layer.cpp | 178 +++ .../src/cpp/style/layers/layer.cpp.ejs | 139 ++ .../src/cpp/style/layers/layer.hpp | 117 ++ .../src/cpp/style/layers/layer.hpp.ejs | 62 + .../src/cpp/style/layers/layer_manager.cpp | 173 +++ .../src/cpp/style/layers/layer_manager.hpp | 57 + .../src/cpp/style/layers/line_layer.cpp | 315 ++++ .../src/cpp/style/layers/line_layer.hpp | 96 ++ .../src/cpp/style/layers/raster_layer.cpp | 222 +++ .../src/cpp/style/layers/raster_layer.hpp | 74 + .../src/cpp/style/layers/symbol_layer.cpp | 594 ++++++++ .../src/cpp/style/layers/symbol_layer.hpp | 180 +++ MapboxGLAndroidSDK/src/cpp/style/light.cpp | 143 ++ MapboxGLAndroidSDK/src/cpp/style/light.hpp | 53 + MapboxGLAndroidSDK/src/cpp/style/position.cpp | 35 + MapboxGLAndroidSDK/src/cpp/style/position.hpp | 24 + .../style/sources/custom_geometry_source.cpp | 209 +++ .../style/sources/custom_geometry_source.hpp | 50 + .../src/cpp/style/sources/geojson_source.cpp | 259 ++++ .../src/cpp/style/sources/geojson_source.hpp | 79 ++ .../src/cpp/style/sources/image_source.cpp | 76 + .../src/cpp/style/sources/image_source.hpp | 39 + .../cpp/style/sources/raster_dem_source.cpp | 61 + .../cpp/style/sources/raster_dem_source.hpp | 29 + .../src/cpp/style/sources/raster_source.cpp | 58 + .../src/cpp/style/sources/raster_source.hpp | 29 + .../src/cpp/style/sources/source.cpp | 230 +++ .../src/cpp/style/sources/source.hpp | 72 + .../src/cpp/style/sources/unknown_source.cpp | 40 + .../src/cpp/style/sources/unknown_source.hpp | 27 + .../src/cpp/style/sources/vector_source.cpp | 81 ++ .../src/cpp/style/sources/vector_source.hpp | 33 + .../src/cpp/style/transition_options.cpp | 35 + .../src/cpp/style/transition_options.hpp | 26 + MapboxGLAndroidSDK/src/cpp/style/value.cpp | 83 ++ MapboxGLAndroidSDK/src/cpp/style/value.hpp | 43 + .../src/cpp/text/local_glyph_rasterizer.cpp | 131 ++ .../cpp/text/local_glyph_rasterizer_jni.hpp | 33 + .../mapboxsdk/style/sources/Source.java | 8 + gradle/native-build.gradle | 2 +- vendor/mapbox-gl-native | 2 +- 178 files changed, 14422 insertions(+), 2 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/cpp/CMakeLists.txt create mode 100755 MapboxGLAndroidSDK/src/cpp/android_renderer_backend.cpp create mode 100755 MapboxGLAndroidSDK/src/cpp/android_renderer_backend.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/marker.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/marker.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/multi_point.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/polygon.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/polygon.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/polyline.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/annotation/polyline.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/asset_manager.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/connectivity_listener.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/connectivity_listener.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/collection.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/collection.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/color.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/color.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/conversion/conversion.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/file_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/file_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/feature.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/feature.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/geometry.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/geometry.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/line_string.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/line_string.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_point.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_point.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/point.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/point.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/polygon.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/polygon.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geojson/util.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/graphics/pointf.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/graphics/pointf.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/graphics/rectf.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/graphics/rectf.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_array.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_array.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_element.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_element.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_object.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_object.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_primitive.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/gson/json_primitive.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/http_file_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/i18n/collator.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/i18n/collator_jni.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/i18n/number_format.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/i18n/number_format_jni.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/java/util.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/java/util.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/java_types.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/java_types.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/jni_native.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/jni_native.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/logger.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/logger.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/logging_android.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/main.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map/camera_position.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map/camera_position.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map/image.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map/image.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map_renderer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map_renderer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/mapbox.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/mapbox.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/native_map_view.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/native_map_view.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_manager.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_manager.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/android_conversion.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/filter.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/filter.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/position.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/position.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/property_expression.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/property_value.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/formatted.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/formatted.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/formatted_section.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/formatted_section.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/light.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/light.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/position.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/position.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/image_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/image_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/transition_options.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/transition_options.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/value.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/value.hpp create mode 100644 MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer_jni.hpp diff --git a/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt new file mode 100644 index 000000000..d031fafcd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.10) + +add_subdirectory(../../../vendor/mapbox-gl-native ../../../vendor/mapbox-gl-native) + +add_library( + mapbox-gl SHARED + ${PROJECT_SOURCE_DIR}/main.cpp + ${PROJECT_SOURCE_DIR}/jni_native.cpp + ${PROJECT_SOURCE_DIR}/jni_native.hpp + ${PROJECT_SOURCE_DIR}/file_source.cpp + ${PROJECT_SOURCE_DIR}/file_source.hpp + ${PROJECT_SOURCE_DIR}/http_file_source.cpp + ${PROJECT_SOURCE_DIR}/i18n/collator.cpp + ${PROJECT_SOURCE_DIR}/i18n/collator_jni.hpp + ${PROJECT_SOURCE_DIR}/i18n/number_format.cpp + ${PROJECT_SOURCE_DIR}/i18n/number_format_jni.hpp + ${PROJECT_SOURCE_DIR}/logger.cpp + ${PROJECT_SOURCE_DIR}/logger.hpp + ${PROJECT_SOURCE_DIR}/logging_android.cpp + ${PROJECT_SOURCE_DIR}/text/local_glyph_rasterizer.cpp + ${PROJECT_SOURCE_DIR}/text/local_glyph_rasterizer_jni.hpp + ${PROJECT_SOURCE_DIR}/android_renderer_backend.cpp + ${PROJECT_SOURCE_DIR}/android_renderer_backend.hpp + ${PROJECT_SOURCE_DIR}/android_renderer_frontend.cpp + ${PROJECT_SOURCE_DIR}/android_renderer_frontend.hpp + ${PROJECT_SOURCE_DIR}/annotation/marker.cpp + ${PROJECT_SOURCE_DIR}/annotation/marker.hpp + ${PROJECT_SOURCE_DIR}/annotation/multi_point.hpp + ${PROJECT_SOURCE_DIR}/annotation/polygon.cpp + ${PROJECT_SOURCE_DIR}/annotation/polygon.hpp + ${PROJECT_SOURCE_DIR}/annotation/polyline.cpp + ${PROJECT_SOURCE_DIR}/annotation/polyline.hpp + ${PROJECT_SOURCE_DIR}/asset_manager.hpp + ${PROJECT_SOURCE_DIR}/asset_manager_file_source.cpp + ${PROJECT_SOURCE_DIR}/asset_manager_file_source.hpp + ${PROJECT_SOURCE_DIR}/connectivity_listener.cpp + ${PROJECT_SOURCE_DIR}/connectivity_listener.hpp + ${PROJECT_SOURCE_DIR}/conversion/collection.cpp + ${PROJECT_SOURCE_DIR}/conversion/collection.hpp + ${PROJECT_SOURCE_DIR}/conversion/color.cpp + ${PROJECT_SOURCE_DIR}/conversion/color.hpp + ${PROJECT_SOURCE_DIR}/conversion/constant.cpp + ${PROJECT_SOURCE_DIR}/conversion/constant.hpp + ${PROJECT_SOURCE_DIR}/conversion/conversion.hpp + ${PROJECT_SOURCE_DIR}/geojson/feature.cpp + ${PROJECT_SOURCE_DIR}/geojson/feature.hpp + ${PROJECT_SOURCE_DIR}/geojson/feature_collection.cpp + ${PROJECT_SOURCE_DIR}/geojson/feature_collection.hpp + ${PROJECT_SOURCE_DIR}/geojson/geometry.cpp + ${PROJECT_SOURCE_DIR}/geojson/geometry.hpp + ${PROJECT_SOURCE_DIR}/geojson/geometry_collection.cpp + ${PROJECT_SOURCE_DIR}/geojson/geometry_collection.hpp + ${PROJECT_SOURCE_DIR}/geojson/line_string.cpp + ${PROJECT_SOURCE_DIR}/geojson/line_string.hpp + ${PROJECT_SOURCE_DIR}/geojson/multi_line_string.cpp + ${PROJECT_SOURCE_DIR}/geojson/multi_line_string.hpp + ${PROJECT_SOURCE_DIR}/geojson/multi_point.cpp + ${PROJECT_SOURCE_DIR}/geojson/multi_point.hpp + ${PROJECT_SOURCE_DIR}/geojson/multi_polygon.cpp + ${PROJECT_SOURCE_DIR}/geojson/multi_polygon.hpp + ${PROJECT_SOURCE_DIR}/geojson/point.cpp + ${PROJECT_SOURCE_DIR}/geojson/point.hpp + ${PROJECT_SOURCE_DIR}/geojson/polygon.cpp + ${PROJECT_SOURCE_DIR}/geojson/polygon.hpp + ${PROJECT_SOURCE_DIR}/geojson/util.hpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng.cpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng.hpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng_bounds.cpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng_bounds.hpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng_quad.cpp + ${PROJECT_SOURCE_DIR}/geometry/lat_lng_quad.hpp + ${PROJECT_SOURCE_DIR}/geometry/projected_meters.cpp + ${PROJECT_SOURCE_DIR}/geometry/projected_meters.hpp + ${PROJECT_SOURCE_DIR}/graphics/pointf.cpp + ${PROJECT_SOURCE_DIR}/graphics/pointf.hpp + ${PROJECT_SOURCE_DIR}/graphics/rectf.cpp + ${PROJECT_SOURCE_DIR}/graphics/rectf.hpp + ${PROJECT_SOURCE_DIR}/gson/json_array.cpp + ${PROJECT_SOURCE_DIR}/gson/json_array.hpp + ${PROJECT_SOURCE_DIR}/gson/json_element.cpp + ${PROJECT_SOURCE_DIR}/gson/json_element.hpp + ${PROJECT_SOURCE_DIR}/gson/json_object.cpp + ${PROJECT_SOURCE_DIR}/gson/json_object.hpp + ${PROJECT_SOURCE_DIR}/gson/json_primitive.cpp + ${PROJECT_SOURCE_DIR}/gson/json_primitive.hpp + ${PROJECT_SOURCE_DIR}/java/util.cpp + ${PROJECT_SOURCE_DIR}/java/util.hpp + ${PROJECT_SOURCE_DIR}/java_types.cpp + ${PROJECT_SOURCE_DIR}/java_types.hpp + ${PROJECT_SOURCE_DIR}/java/util.cpp + ${PROJECT_SOURCE_DIR}/java/util.hpp + ${PROJECT_SOURCE_DIR}/java_types.cpp + ${PROJECT_SOURCE_DIR}/java_types.hpp + ${PROJECT_SOURCE_DIR}/mapbox.cpp + ${PROJECT_SOURCE_DIR}/mapbox.hpp + ${PROJECT_SOURCE_DIR}/map/camera_position.cpp + ${PROJECT_SOURCE_DIR}/map/camera_position.hpp + ${PROJECT_SOURCE_DIR}/map/image.cpp + ${PROJECT_SOURCE_DIR}/map/image.hpp + ${PROJECT_SOURCE_DIR}/map_renderer.cpp + ${PROJECT_SOURCE_DIR}/map_renderer.hpp + ${PROJECT_SOURCE_DIR}/map_renderer_runnable.cpp + ${PROJECT_SOURCE_DIR}/map_renderer_runnable.hpp + ${PROJECT_SOURCE_DIR}/native_map_view.cpp + ${PROJECT_SOURCE_DIR}/native_map_view.hpp + ${PROJECT_SOURCE_DIR}/offline/offline_manager.cpp + ${PROJECT_SOURCE_DIR}/offline/offline_manager.hpp + ${PROJECT_SOURCE_DIR}/offline/offline_region.cpp + ${PROJECT_SOURCE_DIR}/offline/offline_region.hpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_definition.cpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_definition.hpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_error.cpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_error.hpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_status.cpp + ${PROJECT_SOURCE_DIR}/offline/offline_region_status.hpp + ${PROJECT_SOURCE_DIR}/snapshotter/map_snapshot.cpp + ${PROJECT_SOURCE_DIR}/snapshotter/map_snapshot.hpp + ${PROJECT_SOURCE_DIR}/snapshotter/map_snapshotter.cpp + ${PROJECT_SOURCE_DIR}/snapshotter/map_snapshotter.hpp + ${PROJECT_SOURCE_DIR}/style/android_conversion.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/filter.cpp + ${PROJECT_SOURCE_DIR}/style/conversion/filter.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/position.cpp + ${PROJECT_SOURCE_DIR}/style/conversion/position.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/property_expression.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/property_value.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/transition_options.cpp + ${PROJECT_SOURCE_DIR}/style/conversion/transition_options.hpp + ${PROJECT_SOURCE_DIR}/style/conversion/url_or_tileset.cpp + ${PROJECT_SOURCE_DIR}/style/conversion/url_or_tileset.hpp + ${PROJECT_SOURCE_DIR}/style/formatted.cpp + ${PROJECT_SOURCE_DIR}/style/formatted.hpp + ${PROJECT_SOURCE_DIR}/style/formatted_section.cpp + ${PROJECT_SOURCE_DIR}/style/formatted_section.hpp + ${PROJECT_SOURCE_DIR}/style/layers/background_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/background_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/circle_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/circle_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/custom_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/custom_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/fill_extrusion_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/fill_extrusion_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/fill_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/fill_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/heatmap_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/heatmap_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/hillshade_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/hillshade_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/layer_manager.cpp + ${PROJECT_SOURCE_DIR}/style/layers/layer_manager.hpp + ${PROJECT_SOURCE_DIR}/style/layers/line_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/line_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/raster_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/raster_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/symbol_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/symbol_layer.hpp + ${PROJECT_SOURCE_DIR}/style/light.cpp + ${PROJECT_SOURCE_DIR}/style/light.hpp + ${PROJECT_SOURCE_DIR}/style/position.cpp + ${PROJECT_SOURCE_DIR}/style/position.hpp + ${PROJECT_SOURCE_DIR}/style/sources/custom_geometry_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/custom_geometry_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/geojson_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/geojson_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/image_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/image_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/raster_dem_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/raster_dem_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/raster_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/raster_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/unknown_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/unknown_source.hpp + ${PROJECT_SOURCE_DIR}/style/sources/vector_source.cpp + ${PROJECT_SOURCE_DIR}/style/sources/vector_source.hpp + ${PROJECT_SOURCE_DIR}/style/transition_options.cpp + ${PROJECT_SOURCE_DIR}/style/transition_options.hpp + ${PROJECT_SOURCE_DIR}/style/value.cpp + ${PROJECT_SOURCE_DIR}/style/value.hpp +) + + +target_include_directories( + mapbox-gl + PRIVATE + ${PROJECT_SOURCE_DIR} + ../../../vendor/mapbox-gl-native/src + ../../../vendor/mapbox-gl-native/platform/android/src + ../../../vendor/mapbox-gl-native/platform/default/include + +) + +target_link_libraries( + mapbox-gl + PRIVATE + mbgl-compiler-options + Mapbox::Base::jni.hpp + mbgl-core + mbgl-vendor-unique_resource + +) + +install(TARGETS mapbox-gl LIBRARY DESTINATION lib) diff --git a/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.cpp b/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.cpp new file mode 100755 index 000000000..e2d064838 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.cpp @@ -0,0 +1,67 @@ +#include "android_renderer_backend.hpp" + +#include +#include +#include + +#include + +#include + +namespace mbgl { +namespace android { + +class AndroidGLRenderableResource final : public mbgl::gl::RenderableResource { +public: + AndroidGLRenderableResource(AndroidRendererBackend& backend_) : backend(backend_) { + } + + void bind() override { + assert(gfx::BackendScope::exists()); + backend.setFramebufferBinding(0); + backend.setViewport(0, 0, backend.getSize()); + } + +private: + AndroidRendererBackend& backend; +}; + +AndroidRendererBackend::AndroidRendererBackend() + : gl::RendererBackend(gfx::ContextMode::Unique), + mbgl::gfx::Renderable({ 64, 64 }, std::make_unique(*this)) { +} + +AndroidRendererBackend::~AndroidRendererBackend() = default; + +gl::ProcAddress AndroidRendererBackend::getExtensionFunctionPointer(const char* name) { + assert(gfx::BackendScope::exists()); + return eglGetProcAddress(name); +} + +void AndroidRendererBackend::updateViewPort() { + assert(gfx::BackendScope::exists()); + setViewport(0, 0, size); +} + +void AndroidRendererBackend::resizeFramebuffer(int width, int height) { + size = { static_cast(width), static_cast(height) }; +} + +PremultipliedImage AndroidRendererBackend::readFramebuffer() { + assert(gfx::BackendScope::exists()); + return gl::RendererBackend::readFramebuffer(size); +} + +void AndroidRendererBackend::updateAssumedState() { + assumeFramebufferBinding(0); + assumeViewport(0, 0, size); +} + +void AndroidRendererBackend::markContextLost() { + if (context) { + getContext().setCleanupOnDestruction(false); + } +} + +} // namespace android +} // namspace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.hpp b/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.hpp new file mode 100755 index 000000000..f06f38e68 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/android_renderer_backend.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class AndroidRendererBackend : public gl::RendererBackend, public mbgl::gfx::Renderable { +public: + AndroidRendererBackend(); + ~AndroidRendererBackend() override; + + void updateViewPort(); + + // Ensures the current context is not cleaned up when destroyed + void markContextLost(); + + void resizeFramebuffer(int width, int height); + PremultipliedImage readFramebuffer(); + + // mbgl::gfx::RendererBackend implementation +public: + mbgl::gfx::Renderable& getDefaultRenderable() override { + return *this; + } + +protected: + void activate() override { + // no-op + } + void deactivate() override { + // no-op + } + + // mbgl::gl::RendererBackend implementation +protected: + mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override; + void updateAssumedState() override; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp new file mode 100644 index 000000000..d1a2624f0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp @@ -0,0 +1,143 @@ +#include "android_renderer_frontend.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "android_renderer_backend.hpp" + +namespace mbgl { +namespace android { + +// Forwards RendererObserver signals to the given +// Delegate RendererObserver on the given RunLoop +class ForwardingRendererObserver : public RendererObserver { +public: + ForwardingRendererObserver(util::RunLoop& mapRunLoop, RendererObserver& delegate_) + : mailbox(std::make_shared(mapRunLoop)) + , delegate(delegate_, mailbox) { + } + + ~ForwardingRendererObserver() { + mailbox->close(); + } + + void onInvalidate() override { + delegate.invoke(&RendererObserver::onInvalidate); + } + + void onResourceError(std::exception_ptr err) override { + delegate.invoke(&RendererObserver::onResourceError, err); + } + + void onWillStartRenderingMap() override { + delegate.invoke(&RendererObserver::onWillStartRenderingMap); + } + + void onWillStartRenderingFrame() override { + delegate.invoke(&RendererObserver::onWillStartRenderingFrame); + } + + void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) override { + delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged); + } + + void onDidFinishRenderingMap() override { + delegate.invoke(&RendererObserver::onDidFinishRenderingMap); + } + + void onStyleImageMissing(const std::string& id, StyleImageMissingCallback done) override { + delegate.invoke(&RendererObserver::onStyleImageMissing, id, done); + } + + void onRemoveUnusedStyleImages(const std::vector& ids) override { + delegate.invoke(&RendererObserver::onRemoveUnusedStyleImages, ids); + } + +private: + std::shared_ptr mailbox; + ActorRef delegate; +}; + +AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_) + : mapRenderer(mapRenderer_) + , mapRunLoop(util::RunLoop::Get()) + , updateAsyncTask(std::make_unique([this]() { + mapRenderer.update(std::move(updateParams)); + mapRenderer.requestRender(); + })) { +} + +AndroidRendererFrontend::~AndroidRendererFrontend() = default; + +void AndroidRendererFrontend::reset() { + mapRenderer.reset(); +} + +void AndroidRendererFrontend::setObserver(RendererObserver& observer) { + assert (util::RunLoop::Get()); + // Don't call the Renderer directly, but use MapRenderer#setObserver to make sure + // the Renderer may be re-initialised without losing the RendererObserver reference. + mapRenderer.setObserver(std::make_unique(*mapRunLoop, observer)); +} + +void AndroidRendererFrontend::update(std::shared_ptr params) { + updateParams = std::move(params); + updateAsyncTask->send(); +} + +void AndroidRendererFrontend::reduceMemoryUse() { + mapRenderer.actor().invoke(&Renderer::reduceMemoryUse); +} + +std::vector AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID, + const SourceQueryOptions& options) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get(); +} + +std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box, + const RenderedQueryOptions& options) const { + + // Select the right overloaded method + std::vector (Renderer::*fn)(const ScreenBox&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; + + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(fn, box, options).get(); +} + +std::vector AndroidRendererFrontend::queryRenderedFeatures(const ScreenCoordinate& point, + const RenderedQueryOptions& options) const { + + // Select the right overloaded method + std::vector (Renderer::*fn)(const ScreenCoordinate&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures; + + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(fn, point, options).get(); +} + +AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& box) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get(); +} + +AnnotationIDs AndroidRendererFrontend::queryShapeAnnotations(const ScreenBox& box) const { + // Waits for the result from the orchestration thread and returns + return mapRenderer.actor().ask(&Renderer::queryShapeAnnotations, box).get(); +} + +FeatureExtensionValue AndroidRendererFrontend::queryFeatureExtensions(const std::string& sourceID, + const Feature& feature, + const std::string& extension, + const std::string& extensionField, + const optional>& args) const { + return mapRenderer.actor().ask(&Renderer::queryFeatureExtensions, sourceID, feature, extension, extensionField, args).get(); +} + +} // namespace android +} // namespace mbgl + diff --git a/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.hpp b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.hpp new file mode 100644 index 000000000..dc5f11e57 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "map_renderer.hpp" + +namespace mbgl { + +class RenderedQueryOptions; +class SourceQueryOptions; + +namespace util { + +class AsyncTask; + +} // namespace util + +namespace android { + +class AndroidRendererFrontend : public RendererFrontend { +public: + + AndroidRendererFrontend(MapRenderer&); + ~AndroidRendererFrontend() override; + + void reset() override; + void setObserver(RendererObserver&) override; + + void update(std::shared_ptr) override; + + // Feature querying + std::vector queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const; + std::vector queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const; + std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; + AnnotationIDs queryPointAnnotations(const ScreenBox& box) const; + AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const; + + + // Feature extension query + FeatureExtensionValue + queryFeatureExtensions(const std::string& sourceID, + const Feature& feature, + const std::string& extension, + const std::string& extensionField, + const optional>& args) const; + + // Memory + void reduceMemoryUse(); + +private: + MapRenderer& mapRenderer; + util::RunLoop* mapRunLoop; + std::unique_ptr updateAsyncTask; + std::shared_ptr updateParams; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/marker.cpp b/MapboxGLAndroidSDK/src/cpp/annotation/marker.cpp new file mode 100644 index 000000000..899f87a74 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/marker.cpp @@ -0,0 +1,23 @@ +#include "marker.hpp" + +namespace mbgl { +namespace android { + +mbgl::Point Marker::getPosition(jni::JNIEnv& env, const jni::Object& marker) { + static auto& javaClass = jni::Class::Singleton(env); + static auto positionField = javaClass.GetField>(env, "position"); + return LatLng::getGeometry(env, marker.Get(env, positionField)); +} + +std::string Marker::getIconId(jni::JNIEnv& env, const jni::Object& marker) { + static auto& javaClass = jni::Class::Singleton(env); + static auto iconIdField = javaClass.GetField(env, "iconId"); + return jni::Make(env, marker.Get(env, iconIdField)); +} + +void Marker::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/marker.hpp b/MapboxGLAndroidSDK/src/cpp/annotation/marker.hpp new file mode 100644 index 000000000..b38a25b4f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/marker.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include + +#include "../geometry/lat_lng.hpp" + +namespace mbgl { +namespace android { + +class Marker : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; }; + + static mbgl::Point getPosition(jni::JNIEnv&, const jni::Object&); + + static std::string getIconId(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/multi_point.hpp b/MapboxGLAndroidSDK/src/cpp/annotation/multi_point.hpp new file mode 100644 index 000000000..20f1b3eaf --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/multi_point.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "../geometry/lat_lng.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { + +class MultiPoint : protected mbgl::util::noncopyable { + +protected: + + template + static Geometry toGeometry(JNIEnv& env, const jni::Object& pointsList) { + auto jarray = java::util::List::toArray(env, pointsList); + + std::size_t size = jarray.Length(env); + + Geometry geometry; + geometry.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + geometry.push_back(LatLng::getGeometry(env, jarray.Get(env, i))); + } + + return geometry; + } +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/polygon.cpp b/MapboxGLAndroidSDK/src/cpp/annotation/polygon.cpp new file mode 100644 index 000000000..f22cffb10 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/polygon.cpp @@ -0,0 +1,40 @@ +#include "polygon.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, const jni::Object& polygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto points = javaClass.GetField>(env, "points"); + static auto holes = javaClass.GetField>(env, "holes"); + static auto alpha = javaClass.GetField(env, "alpha"); + static auto fillColor = javaClass.GetField(env, "fillColor"); + static auto strokeColor = javaClass.GetField(env, "strokeColor"); + + mbgl::Polygon geometry { + MultiPoint::toGeometry>(env, polygon.Get(env, points)) + }; + + auto jHoleListsArray = java::util::List::toArray(env, polygon.Get(env, holes)); + + std::size_t jHoleListsSize = jHoleListsArray.Length(env); + for (std::size_t i = 0; i < jHoleListsSize; i++) { + geometry.push_back(MultiPoint::toGeometry>(env, jHoleListsArray.Get(env, i))); + } + + mbgl::FillAnnotation annotation { geometry }; + annotation.opacity = polygon.Get(env, alpha); + annotation.color = *conversion::convert(env, polygon.Get(env, fillColor)); + annotation.outlineColor = *conversion::convert(env, polygon.Get(env, strokeColor)); + + return annotation; +} + +void Polygon::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/polygon.hpp b/MapboxGLAndroidSDK/src/cpp/annotation/polygon.hpp new file mode 100644 index 000000000..bc21878ef --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/polygon.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "multi_point.hpp" + +namespace mbgl { +namespace android { + +class Polygon : private MultiPoint { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; }; + + static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/polyline.cpp b/MapboxGLAndroidSDK/src/cpp/annotation/polyline.cpp new file mode 100644 index 000000000..d6161e856 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/polyline.cpp @@ -0,0 +1,31 @@ +#include "polyline.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, const jni::Object& polyline) { + static auto& javaClass = jni::Class::Singleton(env); + static auto points = javaClass.GetField>(env, "points"); + static auto alpha = javaClass.GetField(env, "alpha"); + static auto color = javaClass.GetField(env, "color"); + static auto width = javaClass.GetField(env, "width"); + + mbgl::LineAnnotation annotation { + MultiPoint::toGeometry>(env, polyline.Get(env, points)) + }; + + annotation.opacity = polyline.Get(env, alpha); + annotation.color = *conversion::convert(env, polyline.Get(env, color)); + annotation.width = polyline.Get(env, width); + + return annotation; +} + +void Polyline::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/annotation/polyline.hpp b/MapboxGLAndroidSDK/src/cpp/annotation/polyline.hpp new file mode 100644 index 000000000..6178e98cf --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/annotation/polyline.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "multi_point.hpp" + +namespace mbgl { +namespace android { + +class Polyline : private MultiPoint { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; }; + + static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/asset_manager.hpp b/MapboxGLAndroidSDK/src/cpp/asset_manager.hpp new file mode 100644 index 000000000..b87d18951 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/asset_manager.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace mbgl { +namespace android { + +class AssetManager { +public: + static constexpr auto Name() { + return "android/content/res/AssetManager"; + }; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.cpp b/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.cpp new file mode 100644 index 000000000..a8045a2b9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.cpp @@ -0,0 +1,65 @@ +#include "asset_manager_file_source.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace mbgl { + +class AssetManagerFileSource::Impl { +public: + Impl(ActorRef, AAssetManager* assetManager_) : assetManager(assetManager_) { + } + + void request(const std::string& url, ActorRef req) { + // Note: AssetManager already prepends "assets" to the filename. + const std::string path = mbgl::util::percentDecode(url.substr(8)); + + Response response; + + if (AAsset* asset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER)) { + response.data = std::make_shared( + reinterpret_cast(AAsset_getBuffer(asset)), AAsset_getLength64(asset)); + AAsset_close(asset); + } else { + response.error = std::make_unique(Response::Error::Reason::NotFound, + "Could not read asset"); + } + + req.invoke(&FileSourceRequest::setResponse, response); + } + +private: + AAssetManager* assetManager; +}; + +AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, + const jni::Object& assetManager_) + : assetManager(jni::NewGlobal(env, assetManager_)), + impl(std::make_unique>( + util::makeThreadPrioritySetter(platform::EXPERIMENTAL_THREAD_PRIORITY_FILE), + "AssetManagerFileSource", + AAssetManager_fromJava(&env, jni::Unwrap(assetManager.get())))) {} + +AssetManagerFileSource::~AssetManagerFileSource() = default; + +std::unique_ptr AssetManagerFileSource::request(const Resource& resource, Callback callback) { + auto req = std::make_unique(std::move(callback)); + + impl->actor().invoke(&Impl::request, resource.url, req->actor()); + + return std::move(req); +} + +bool AssetManagerFileSource::canRequest(const Resource& resource) const { + return 0 == resource.url.rfind(mbgl::util::ASSET_PROTOCOL, 0); +} + +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.hpp b/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.hpp new file mode 100644 index 000000000..bcbc6f1e9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/asset_manager_file_source.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "asset_manager.hpp" + +#include + +namespace mbgl { + +namespace util { +template class Thread; +} // namespace util + +class AssetManagerFileSource : public FileSource { +public: + AssetManagerFileSource(jni::JNIEnv&, const jni::Object&); + ~AssetManagerFileSource() override; + + std::unique_ptr request(const Resource&, Callback) override; + bool canRequest(const Resource&) const override; + +private: + class Impl; + + jni::Global> assetManager; + std::unique_ptr> impl; +}; + +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/connectivity_listener.cpp b/MapboxGLAndroidSDK/src/cpp/connectivity_listener.cpp new file mode 100644 index 000000000..9c13f1f74 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/connectivity_listener.cpp @@ -0,0 +1,41 @@ +#include "connectivity_listener.hpp" + +#include +#include + +#include + +namespace mbgl { +namespace android { + + /** + * Invoked when the construction is initiated from the jvm + */ + ConnectivityListener::ConnectivityListener(jni::JNIEnv&) {} + + ConnectivityListener::~ConnectivityListener() {} + + void ConnectivityListener::onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean connected) { + NetworkStatus::Set(connected ? NetworkStatus::Status::Online : NetworkStatus::Status::Offline); + } + + void ConnectivityListener::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + std::make_unique, + "initialize", + "finalize", + METHOD(&ConnectivityListener::onConnectivityStateChanged, "nativeOnConnectivityStateChanged") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/connectivity_listener.hpp b/MapboxGLAndroidSDK/src/cpp/connectivity_listener.hpp new file mode 100644 index 000000000..a09507c0f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/connectivity_listener.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class ConnectivityListener : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/net/NativeConnectivityListener"; }; + + static void registerNative(jni::JNIEnv&); + + /* + * Called when a Java object was created from the jvm side + */ + ConnectivityListener(jni::JNIEnv&); + + ~ConnectivityListener(); + + void onConnectivityStateChanged(jni::JNIEnv&, jni::jboolean); + +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/collection.cpp b/MapboxGLAndroidSDK/src/cpp/conversion/collection.cpp new file mode 100644 index 000000000..954a161ba --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/collection.cpp @@ -0,0 +1,32 @@ +#include "collection.hpp" +#include "constant.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector toVector(JNIEnv& env, const jni::Array& array) { + std::size_t len = array.Length(env); + std::vector vector; + vector.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + vector.push_back(jni::Make(env, array.Get(env, i))); + } + + return vector; +} + +jni::Local> toArray(JNIEnv& env, const std::vector& vector) { + auto result = jni::Array::New(env, vector.size()); + + for (std::size_t i = 0; i < vector.size(); i++) { + result.Set(env, i, jni::Make(env, vector.at(i))); + } + + return result; +} + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/collection.hpp b/MapboxGLAndroidSDK/src/cpp/conversion/collection.hpp new file mode 100644 index 000000000..322ebb62e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/collection.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "conversion.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector toVector(JNIEnv& env, const jni::Array& array); +jni::Local> toArray(JNIEnv& env, const std::vector&); + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/color.cpp b/MapboxGLAndroidSDK/src/cpp/conversion/color.cpp new file mode 100644 index 000000000..ce85943e6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/color.cpp @@ -0,0 +1,17 @@ +#include "color.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result Converter::operator()(jni::JNIEnv&, const int& color) const { + float r = (color >> 16) & 0xFF; + float g = (color >> 8) & 0xFF; + float b = (color) & 0xFF; + float a = (color >> 24) & 0xFF; + return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/color.hpp b/MapboxGLAndroidSDK/src/cpp/conversion/color.hpp new file mode 100644 index 000000000..2b4144b93 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/color.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "conversion.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter { + Result operator()(jni::JNIEnv&, const int& color) const; +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp b/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp new file mode 100644 index 000000000..46a91026d --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp @@ -0,0 +1,62 @@ +#include "constant.hpp" +#include "collection.hpp" +#include "../style/formatted.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, bool>::operator()(jni::JNIEnv& env, const bool& value) const { + return jni::Box(env, value ? jni::jni_true : jni::jni_false); +} + +Result>> Converter>, float>::operator()(jni::JNIEnv& env, const float& value) const { + return jni::Box(env, value); +} + +Result>> Converter>, double>::operator()(jni::JNIEnv& env, const double& value) const { + return jni::Box(env, value); +} + +Result>> Converter>, std::string>::operator()(jni::JNIEnv& env, const std::string& value) const { + return jni::Make(env, value); +} + +Result>> Converter>, Color>::operator()(jni::JNIEnv& env, const Color& value) const { + return jni::Make(env, value.stringify()); +} + +Result>> Converter>, style::expression::Formatted>::operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const { + return Formatted::New(env, value); +} + +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + + for (std::size_t i = 0; i < value.size(); i++) { + result.Set(env, i, jni::Make(env, value.at(i))); + } + + return result; +} + +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + + for (std::size_t i = 0; i < value.size(); i++) { + result.Set(env, i, jni::Box(env, value.at(i))); + } + + return result; +} + +Result>> Converter>, style::expression::Image>::operator()( + jni::JNIEnv& env, const style::expression::Image& value) const { + return jni::Make(env, value.id()); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp b/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp new file mode 100644 index 000000000..a9239fe84 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include "conversion.hpp" + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter>, bool> { + Result>> operator()(jni::JNIEnv& env, const bool& value) const; +}; + +template <> +struct Converter>, float> { + Result>> operator()(jni::JNIEnv& env, const float& value) const; +}; + +template <> +struct Converter>, double> { + Result>> operator()(jni::JNIEnv& env, const double& value) const; +}; + +/** + * All integrals. java is limited to 64 bit signed, so... + * TODO: use BigDecimal for > 64 / unsigned? + */ +template +struct Converter>, T, typename std::enable_if::value>::type> { + Result>> operator()(jni::JNIEnv& env, const T& value) const { + return jni::Box(env, jni::jlong(value)); + } +}; + +// TODO: convert integral types to primitive jni types + +template <> +struct Converter>, std::string> { + Result>> operator()(jni::JNIEnv& env, const std::string& value) const; +}; + +template <> +struct Converter>, Color> { + Result>> operator()(jni::JNIEnv& env, const Color& value) const; +}; + +template <> +struct Converter>, style::expression::Formatted> { + Result>> operator()(jni::JNIEnv& env, const style::expression::Formatted& value) const; +}; + +template +struct Converter>, std::array> { + Result>> operator()(jni::JNIEnv& env, const std::array& value) const { + std::vector v; + for (const float& id : value) { + v.push_back(id); + } + return convert>, std::vector>(env, v); + } +}; + +template <> +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; +}; + +template <> +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; +}; + +template +struct Converter>, T, typename std::enable_if_t::value>> { + Result>> operator()(jni::JNIEnv& env, const T& value) const { + return convert>, std::string>(env, Enum::toString(value)); + } +}; + +template +struct Converter>, std::vector, typename std::enable_if_t::value>> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + for (std::size_t i = 0; i < value.size(); ++i) { + result.Set(env, i, jni::Make(env, Enum::toString(value.at(i)))); + } + return result; + } +}; + +template <> +struct Converter>, style::expression::Image> { + Result>> operator()(jni::JNIEnv& env, const style::expression::Image& value) const; +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/conversion.hpp b/MapboxGLAndroidSDK/src/cpp/conversion/conversion.hpp new file mode 100644 index 000000000..d1766f975 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/conversion/conversion.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +struct Error { std::string message; }; + +template +class Result : private variant { +public: + using variant::variant; + + explicit operator bool() const { + return this->template is(); + } + + T& operator*() { + assert(this->template is()); + return this->template get(); + } + + const T& operator*() const { + assert(this->template is()); + return this->template get(); + } + + const Error& error() const { + assert(this->template is()); + return this->template get(); + } +}; + +template +struct Converter; + +template +Result convert(jni::JNIEnv& env, const V& value, Args&&...args) { + return Converter()(env, value, std::forward(args)...); +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/file_source.cpp b/MapboxGLAndroidSDK/src/cpp/file_source.cpp new file mode 100644 index 000000000..f95066546 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/file_source.cpp @@ -0,0 +1,252 @@ +#include "file_source.hpp" + +#include "attach_env.hpp" +#include "mapbox.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include "asset_manager_file_source.hpp" + +namespace mbgl { +namespace android { + +// FileSource // + +FileSource::FileSource(jni::JNIEnv& _env, const jni::String& accessToken, const jni::String& _cachePath) { + std::string path = jni::Make(_env, _cachePath); + mapbox::sqlite::setTempPath(path); + + mbgl::FileSourceManager::get()->registerFileSourceFactory( + mbgl::FileSourceType::Asset, [](const mbgl::ResourceOptions&) { + auto env{android::AttachEnv()}; + std::unique_ptr assetFileSource; + if (android::Mapbox::hasInstance(*env)) { + auto assetManager = android::Mapbox::getAssetManager(*env); + assetFileSource = std::make_unique(*env, assetManager); + } + return assetFileSource; + }); + + resourceOptions.withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE); + + // Create a core file sources + // TODO: Split Android FileSource API to smaller interfaces + resourceLoader = + mbgl::FileSourceManager::get()->getFileSource(mbgl::FileSourceType::ResourceLoader, resourceOptions); + databaseSource = std::static_pointer_cast(std::shared_ptr( + mbgl::FileSourceManager::get()->getFileSource(mbgl::FileSourceType::Database, resourceOptions))); + onlineSource = mbgl::FileSourceManager::get()->getFileSource(mbgl::FileSourceType::Network, resourceOptions); +} + +FileSource::~FileSource() { +} + +jni::Local FileSource::getAccessToken(jni::JNIEnv& env) { + if (auto* token = onlineSource->getProperty(mbgl::ACCESS_TOKEN_KEY).getString()) { + return jni::Make(env, *token); + } + + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Online functionality is disabled."); + return jni::Make(env, ""); +} + +void FileSource::setAccessToken(jni::JNIEnv& env, const jni::String& token) { + if (onlineSource) { + onlineSource->setProperty(mbgl::ACCESS_TOKEN_KEY, token ? jni::Make(env, token) : ""); + } else { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Online functionality is disabled."); + } +} + +void FileSource::setAPIBaseUrl(jni::JNIEnv& env, const jni::String& url) { + if (onlineSource) { + onlineSource->setProperty(mbgl::API_BASE_URL_KEY, jni::Make(env, url)); + } else { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Online functionality is disabled."); + } +} + +void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object& transformCallback) { + // Core could be built without support for network resource provider. + if (!onlineSource) { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Online functionality is disabled."); + return; + } + + if (transformCallback) { + auto global = jni::NewGlobal(env, transformCallback); + resourceTransform = std::make_unique>( + *Scheduler::GetCurrent(), + // Capture the ResourceTransformCallback object as a managed global into + // the lambda. It is released automatically when we're setting a new ResourceTransform in + // a subsequent call. + // Note: we're converting it to shared_ptr because this lambda is converted to a std::function, + // which requires copyability of its captured variables. + [callback = std::make_shared(std::move(global))]( + mbgl::Resource::Kind kind, const std::string& url_, ResourceTransform::FinishedCallback cb) { + android::UniqueEnv _env = android::AttachEnv(); + cb(FileSource::ResourceTransformCallback::onURL(*_env, *callback, int(kind), url_)); + }); + onlineSource->setResourceTransform( + {[actorRef = resourceTransform->self()]( + Resource::Kind kind, const std::string& url, ResourceTransform::FinishedCallback cb) { + actorRef.invoke(&ResourceTransform::TransformCallback::operator(), kind, url, std::move(cb)); + }}); + } else { + // Reset the callback + resourceTransform.reset(); + onlineSource->setResourceTransform({}); + } +} + +void FileSource::setResourceCachePath(jni::JNIEnv& env, + const jni::String& path, + const jni::Object& _callback) { + if (!databaseSource) { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Offline functionality is disabled."); + return; + } + + if (pathChangeCallback) { + FileSource::ResourcesCachePathChangeCallback::onError(env, _callback, jni::Make(env, "Another resources cache path change is in progress")); + return; + } + + std::string newPath = jni::Make(env, path); + mapbox::sqlite::setTempPath(newPath); + + auto global = jni::NewGlobal(env, _callback); + pathChangeCallback = Scheduler::GetCurrent()->bindOnce( + [this, callback = std::make_shared(std::move(global)), newPath] { + android::UniqueEnv _env = android::AttachEnv(); + FileSource::ResourcesCachePathChangeCallback::onSuccess( + *_env, *callback, jni::Make(*_env, newPath)); + pathChangeCallback = {}; + }); + + databaseSource->setDatabasePath(newPath + DATABASE_FILE, pathChangeCallback); +} + +void FileSource::resume(jni::JNIEnv&) { + if (!resourceLoader) { + return; + } + + if (!activationCounter) { + activationCounter = optional(1) ; + return; + } + + activationCounter.value()++; + if (activationCounter == 1) { + resourceLoader->resume(); + } +} + +void FileSource::pause(jni::JNIEnv&) { + if (!resourceLoader) { + return; + } + + if (activationCounter) { + activationCounter.value()--; + if (activationCounter == 0) { + resourceLoader->pause(); + } + } +} + +jni::jboolean FileSource::isResumed(jni::JNIEnv&) { + if (activationCounter) { + return (jboolean) (activationCounter > 0); + } + return (jboolean) false; +} + +FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object& jFileSource) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "nativePtr"); + return reinterpret_cast(jFileSource.Get(env, field)); +} + +mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, + const jni::Object& jFileSource) { + FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); + // Core could be compiled without support for any sources. + if (fileSource) { + return fileSource->resourceOptions.clone(); + } + + return {}; +} + +// FileSource::ResourcesCachePathChangeCallback // + +void FileSource::ResourcesCachePathChangeCallback::onSuccess(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& path) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onSuccess"); + + callback.Call(env, method, path); +} + +void FileSource::ResourcesCachePathChangeCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& message) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, message); +} + +void FileSource::registerNative(jni::JNIEnv& env) { + // Ensure the classes are cached. If they're requested for the + // first time on a background thread, Android's class loader heuristics will fail. + // https://developer.android.com/training/articles/perf-jni#faq_FindClass + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FileSource::getAccessToken, "getAccessToken"), + METHOD(&FileSource::setAccessToken, "setAccessToken"), + METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), + METHOD(&FileSource::setResourceTransform, "setResourceTransform"), + METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), + METHOD(&FileSource::resume, "activate"), + METHOD(&FileSource::pause, "deactivate"), + METHOD(&FileSource::isResumed, "isActivated")); +} + + +// FileSource::ResourceTransformCallback // + +std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, const jni::Object& callback, int kind, std::string url_) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onURL"); + + return jni::Make(env, + callback.Call(env, method, kind, + jni::Make(env, url_))); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/file_source.hpp b/MapboxGLAndroidSDK/src/cpp/file_source.hpp new file mode 100644 index 000000000..3bf0fed2e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/file_source.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include + +#include "asset_manager.hpp" + +#include + +namespace mbgl { + +template class Actor; + +namespace android { + +/** + * Peer class for the Android FileSource holder. Ensures that a single core FileSource + * of a ResourceLoader type is used. + */ +class FileSource { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; }; + + struct ResourceTransformCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; } + + static std::string onURL(jni::JNIEnv&, const jni::Object&, int, std::string); + }; + + struct ResourcesCachePathChangeCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourcesCachePathChangeCallback";} + + static void onSuccess(jni::JNIEnv&, + const jni::Object&, + const jni::String&); + + static void onError(jni::JNIEnv&, + const jni::Object&, + const jni::String&); + }; + + FileSource(jni::JNIEnv&, const jni::String&, const jni::String&); + + ~FileSource(); + + jni::Local getAccessToken(jni::JNIEnv&); + + void setAccessToken(jni::JNIEnv&, const jni::String&); + + void setAPIBaseUrl(jni::JNIEnv&, const jni::String&); + + void setResourceTransform(jni::JNIEnv&, const jni::Object&); + + void setResourceCachePath(jni::JNIEnv&, const jni::String&, const jni::Object&); + + void resume(jni::JNIEnv&); + + void pause(jni::JNIEnv&); + + jni::jboolean isResumed(jni::JNIEnv&); + + static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object&); + + static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); + +private: + const std::string DATABASE_FILE = "/mbgl-offline.db"; + optional activationCounter; + mbgl::ResourceOptions resourceOptions; + std::unique_ptr> resourceTransform; + std::function pathChangeCallback; + std::shared_ptr databaseSource; + std::shared_ptr onlineSource; + std::shared_ptr resourceLoader; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/feature.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/feature.cpp new file mode 100644 index 000000000..afbf1ee11 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/feature.cpp @@ -0,0 +1,88 @@ +#include "feature.hpp" +#include "geometry.hpp" +#include "../gson/json_object.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +using namespace gson; + +mbgl::GeoJSONFeature Feature::convert(jni::JNIEnv& env, const jni::Object& jFeature) { + static auto& javaClass = jni::Class::Singleton(env); + static auto id = javaClass.GetMethod(env, "id"); + static auto geometry = javaClass.GetMethod ()>(env, "geometry"); + static auto properties = javaClass.GetMethod ()>(env, "properties"); + + auto jId = jFeature.Call(env, id); + + using mbid = mapbox::feature::identifier; + + return mbgl::GeoJSONFeature{Geometry::convert(env, jFeature.Call(env, geometry)), + JsonObject::convert(env, jFeature.Call(env, properties)), + jId ? mbid{jni::Make(env, jId)} : mbid{mapbox::feature::null_value}}; +} + +/** + * Turn feature identifier into std::string + */ +class FeatureIdVisitor { +public: + template + std::string operator()(const T& i) const { + return util::toString(i); + } + + std::string operator()(const std::string& i) const { + return i; + } + + std::string operator()(const std::nullptr_t&) const { + return {}; + } + + std::string operator()(const mapbox::feature::null_value_t&) const { + return {}; + } +}; + +jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::GeoJSONFeature& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); + + return javaClass.Call(env, method, + Geometry::New(env, value.geometry), + JsonObject::New(env, value.properties), + jni::Make(env, value.id.is() ? std::string {} : value.id.match(FeatureIdVisitor()))); +} + +jni::Local>> Feature::convert(jni::JNIEnv& env, const std::vector& value) { + auto features = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); ++i) { + features.Set(env, i, convertFeature(env, static_cast(value.at(i)))); + } + + return features; +} + +jni::Local>> Feature::convert(jni::JNIEnv& env, + const std::vector& value) { + auto features = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); ++i) { + features.Set(env, i, convertFeature(env, value.at(i))); + } + + return features; +} + +void Feature::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/feature.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/feature.hpp new file mode 100644 index 000000000..aee45262e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/feature.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Feature { +public: + static constexpr auto Name() { return "com/mapbox/geojson/Feature"; }; + + static mbgl::GeoJSONFeature convert(jni::JNIEnv&, const jni::Object&); + static jni::Local>> convert(jni::JNIEnv&, const std::vector&); + static jni::Local>> convert(jni::JNIEnv&, const std::vector&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.cpp new file mode 100644 index 000000000..f90d5226b --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.cpp @@ -0,0 +1,37 @@ +#include "feature_collection.hpp" + +#include "feature.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, const jni::Object& jCollection) { + auto collection = mbgl::FeatureCollection(); + + if (jCollection) { + auto jFeatureList = FeatureCollection::features(env, jCollection); + auto jFeatures = java::util::List::toArray(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + collection.reserve(size); + + for (size_t i = 0; i < size; i++) { + collection.push_back(Feature::convert(env, jFeatures.Get(env, i))); + } + } + return collection; +} + +jni::Local> FeatureCollection::features(jni::JNIEnv& env, const jni::Object& jCollection) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "features"); + return jCollection.Call(env, method); +} + +void FeatureCollection::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.hpp new file mode 100644 index 000000000..66e92eaca --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/feature_collection.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../java/util.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class FeatureCollection { +public: + static constexpr auto Name() { return "com/mapbox/geojson/FeatureCollection"; }; + + static mbgl::FeatureCollection convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> features(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/geometry.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/geometry.cpp new file mode 100644 index 000000000..0598b9fc5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/geometry.cpp @@ -0,0 +1,97 @@ +#include "geometry.hpp" + +#include "point.hpp" +#include "multi_point.hpp" +#include "line_string.hpp" +#include "multi_line_string.hpp" +#include "polygon.hpp" +#include "multi_polygon.hpp" +#include "geometry_collection.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +/** + * Turn mapbox::geometry type into Java GeoJson Geometries + */ +class GeometryEvaluator { +public: + + jni::JNIEnv& env; + + jni::Local> operator()(const mbgl::EmptyGeometry &) const { + // FIXME: mapbox-java needs to have its own Empty type. + return GeometryCollection::New(env, {}); + } + + jni::Local> operator()(const mbgl::Point &geometry) const { + return Point::New(env, geometry); + } + + jni::Local> operator()(const mbgl::LineString &geometry) const { + return LineString::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiLineString &geometry) const { + return MultiLineString::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiPoint &geometry) const { + return MultiPoint::New(env, geometry); + } + + jni::Local> operator()(const mbgl::Polygon &geometry) const { + return Polygon::New(env, geometry); + } + + jni::Local> operator()(const mbgl::MultiPolygon &geometry) const { + return MultiPolygon::New(env, geometry); + } + + jni::Local> operator()(const mapbox::geometry::geometry_collection &geometry) const { + return GeometryCollection::New(env, geometry); + } +}; + +jni::Local> Geometry::New(jni::JNIEnv& env, mbgl::Geometry geometry) { + GeometryEvaluator evaluator { env } ; + return mbgl::Geometry::visit(geometry, evaluator); +} + +mbgl::Geometry Geometry::convert(jni::JNIEnv &env, const jni::Object& jGeometry) { + auto type = Geometry::getType(env, jGeometry); + if (type == Point::Type()) { + return { Point::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiPoint::Type()) { + return { MultiPoint::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == LineString::Type()) { + return { LineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiLineString::Type()) { + return { MultiLineString::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == Polygon::Type()) { + return { Polygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == MultiPolygon::Type()) { + return { MultiPolygon::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } else if (type == GeometryCollection::Type()) { + return { GeometryCollection::convert(env, jni::Cast(env, jni::Class::Singleton(env), jGeometry)) }; + } + + throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); +} + +std::string Geometry::getType(jni::JNIEnv &env, const jni::Object& jGeometry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "type"); + return jni::Make(env, jGeometry.Call(env, method)); +} + +void Geometry::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/geometry.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/geometry.hpp new file mode 100644 index 000000000..4bf55c858 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/geometry.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Geometry { +public: + static constexpr auto Name() { return "com/mapbox/geojson/Geometry"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::Geometry); + + static mbgl::Geometry convert(jni::JNIEnv&, const jni::Object&); + + static std::string getType(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.cpp new file mode 100644 index 000000000..cca909126 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.cpp @@ -0,0 +1,47 @@ +#include "geometry_collection.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> GeometryCollection::New(jni::JNIEnv& env, const mapbox::geometry::geometry_collection& collection) { + // Create an array of geometries + auto jarray = jni::Array>::New(env, collection.size()); + + for (size_t i = 0; i < collection.size(); i++) { + jarray.Set(env, i, Geometry::New(env, collection.at(i))); + } + + // create the GeometryCollection + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromGeometries"); + return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); +} + +mapbox::geometry::geometry_collection GeometryCollection::convert(jni::JNIEnv &env, const jni::Object& jCollection) { + // Get geometries + static auto& javaClass = jni::Class::Singleton(env); + static auto getGeometries = javaClass.GetMethod ()>(env, "geometries"); + + // Turn into array + auto jarray = java::util::List::toArray(env, jCollection.Call(env, getGeometries)); + + // Convert each geometry + mapbox::geometry::geometry_collection collection{}; + + auto size = jarray.Length(env); + for (jni::jsize i = 0; i < size; i++) { + collection.push_back(Geometry::convert(env, jarray.Get(env, i))); + } + + return collection; +} + +void GeometryCollection::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.hpp new file mode 100644 index 000000000..9f02ac848 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/geometry_collection.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class GeometryCollection { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/GeometryCollection"; }; + static constexpr auto Type() { return "GeometryCollection"; }; + + static jni::Local> New(jni::JNIEnv&, const mapbox::geometry::geometry_collection&); + + static mapbox::geometry::geometry_collection convert(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/line_string.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/line_string.cpp new file mode 100644 index 000000000..ae1345c95 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/line_string.cpp @@ -0,0 +1,55 @@ +#include "line_string.hpp" +#include "point.hpp" +#include "util.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> LineString::New(jni::JNIEnv& env, const mbgl::LineString& lineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsList(env, lineString)); +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object& jLineString) { + mapbox::geojson::line_string lineString; + + if (jLineString) { + lineString = LineString::convert(env, LineString::coordinates(env, jLineString)); + } + + return lineString; +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, const jni::Object*/>& jPointList) { + mapbox::geojson::line_string lineString; + + if (jPointList) { + auto jPointArray = java::util::List::toArray(env, jPointList); + auto size = jPointArray.Length(env); + lineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + lineString.push_back(Point::convert(env, jPointArray.Get(env, i))); + } + } + + return lineString; +} + +jni::Local> LineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jLineString.Call(env, method); +} + +void LineString::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/line_string.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/line_string.hpp new file mode 100644 index 000000000..906d809fa --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/line_string.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + + +class LineString { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/LineString"; }; + static constexpr auto Type() { return "LineString"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::LineString&); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object&); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, const jni::Object*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.cpp new file mode 100644 index 000000000..1aaf53c01 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.cpp @@ -0,0 +1,56 @@ +#include "multi_line_string.hpp" + +#include "line_string.hpp" +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiLineString::New(jni::JNIEnv& env, const mbgl::MultiLineString& multiLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsListsList(env, multiLineString)); +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object& jMultiLineString) { + mapbox::geojson::multi_line_string multiLineString; + + if (jMultiLineString) { + multiLineString = MultiLineString::convert(env, MultiLineString::coordinates(env, jMultiLineString)); + } + + return multiLineString; +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { + mapbox::geojson::multi_line_string multiLineString; + + if (jPointListsList) { + auto jPositionListsArray = java::util::List::toArray(env, jPointListsList); + + auto size = jPositionListsArray.Length(env); + multiLineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + multiLineString.push_back(LineString::convert(env, jPositionListsArray.Get(env, i))); + } + } + + return multiLineString; +} + +jni::Local> MultiLineString::coordinates(jni::JNIEnv &env, const jni::Object& jLineString) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jLineString.Call(env, method); +} + +void MultiLineString::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.hpp new file mode 100644 index 000000000..65ce43bd1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_line_string.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "../java/util.hpp" +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiLineString { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiLineString"; }; + static constexpr auto Type() { return "MultiLineString"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiLineString&); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object&); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, const jni::Object>*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.cpp new file mode 100644 index 000000000..d530ef721 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.cpp @@ -0,0 +1,41 @@ +#include "multi_point.hpp" + +#include "line_string.hpp" + +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiPoint::New(JNIEnv& env, const mbgl::MultiPoint& multiPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsList(env, multiPoint)); +} + +mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv& env, const jni::Object& jMultiPoint) { + mapbox::geojson::multi_point multiPoint; + + if (jMultiPoint) { + multiPoint = convertExplicit( + LineString::convert(env, MultiPoint::coordinates(env, jMultiPoint))); + } + + return multiPoint; +} + +jni::Local> MultiPoint::coordinates(jni::JNIEnv& env, const jni::Object& jMultiPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jMultiPoint.Call(env, method); +} + +void MultiPoint::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.hpp new file mode 100644 index 000000000..a3ca49b73 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_point.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPoint { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPoint"; }; + static constexpr auto Type() { return "MultiPoint"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPoint&); + + static mapbox::geojson::multi_point convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.cpp new file mode 100644 index 000000000..3c5c3ec33 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.cpp @@ -0,0 +1,53 @@ +#include "multi_polygon.hpp" + +#include "polygon.hpp" +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> MultiPolygon::New(JNIEnv& env, const mbgl::MultiPolygon& multiPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + auto jarray = jni::Array>::New(env, multiPolygon.size()); + + for (size_t i = 0; i < multiPolygon.size(); i++) { + jarray.Set(env, i, asPointsListsList(env, multiPolygon.at(i))); + } + + return javaClass.Call(env, method, java::util::Arrays::asList(env, jarray)); +} + +mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv& env, const jni::Object& jMultiPolygon) { + mapbox::geojson::multi_polygon multiPolygon; + + if (jMultiPolygon) { + auto jPointListsListList = MultiPolygon::coordinates(env, jMultiPolygon); + auto jPointListsListArray = java::util::List::toArray(env, jPointListsListList); + + auto size = jPointListsListArray.Length(env); + multiPolygon.reserve(size); + + for (size_t i = 0; i < size; i++) { + multiPolygon.push_back(Polygon::convert(env, jPointListsListArray.Get(env, i))); + } + } + + return multiPolygon; +} + +jni::Local> MultiPolygon::coordinates(jni::JNIEnv& env, const jni::Object& jPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jPolygon.Call(env, method); +} + +void MultiPolygon::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.hpp new file mode 100644 index 000000000..fd7b08016 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/multi_polygon.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "../java/util.hpp" +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPolygon { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPolygon"; }; + static constexpr auto Type() { return "MultiPolygon"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::MultiPolygon&); + + static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, const jni::Object&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/point.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/point.cpp new file mode 100644 index 000000000..2000447c0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/point.cpp @@ -0,0 +1,34 @@ +#include "point.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> Point::New(jni::JNIEnv& env, const mbgl::Point& point) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::jdouble, jni::jdouble)>(env, "fromLngLat"); + return javaClass.Call(env, method, point.x, point.y); +} + +mbgl::Point Point::convert(jni::JNIEnv &env, const jni::Object& jPoint) { + static auto& javaClass = jni::Class::Singleton(env); + static auto longitude = javaClass.GetMethod(env, "longitude"); + static auto latitude = javaClass.GetMethod(env, "latitude"); + + if (!jPoint) { + return {}; + } + + return { + jPoint.Call(env, longitude), + jPoint.Call(env, latitude) + }; +} + +void Point::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/point.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/point.hpp new file mode 100644 index 000000000..b5d71ecae --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/point.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "geometry.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Point { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/Point"; }; + static constexpr auto Type() { return "Point"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Point&); + static mbgl::Point convert(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/polygon.cpp b/MapboxGLAndroidSDK/src/cpp/geojson/polygon.cpp new file mode 100644 index 000000000..4437d134a --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/polygon.cpp @@ -0,0 +1,55 @@ +#include "polygon.hpp" + +#include "multi_line_string.hpp" + +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Local> Polygon::New(jni::JNIEnv& env, const mbgl::Polygon& polygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "fromLngLats"); + + return javaClass.Call(env, method, asPointsListsList(env, polygon)); +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object& jPolygon) { + mapbox::geojson::polygon polygon; + + if (jPolygon) { + polygon = Polygon::convert(env, Polygon::coordinates(env, jPolygon)); + } + + return polygon; +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, const jni::Object>*/>& jPointListsList) { + mapbox::geojson::polygon polygon; + + if (jPointListsList) { + auto multiLine = MultiLineString::convert(env, jPointListsList); + polygon.reserve(multiLine.size()); + for (auto&& line : multiLine) { + polygon.emplace_back(convertExplicit(std::move(line))); + } + } + + return polygon; +} + + +jni::Local> Polygon::coordinates(jni::JNIEnv &env, const jni::Object& jPolygon) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "coordinates"); + return jPolygon.Call(env, method); +} + +void Polygon::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/polygon.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/polygon.hpp new file mode 100644 index 000000000..8e1761fed --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/polygon.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "geometry.hpp" +#include "../java/util.hpp" + +#include + + +namespace mbgl { +namespace android { +namespace geojson { + +class Polygon { +public: + using SuperTag = Geometry; + static constexpr auto Name() { return "com/mapbox/geojson/Polygon"; }; + static constexpr auto Type() { return "Polygon"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Polygon&); + + static mapbox::geojson::polygon convert(jni::JNIEnv &, const jni::Object&); + + static mapbox::geojson::polygon convert(jni::JNIEnv&, const jni::Object>*/>&); + + static jni::Local> coordinates(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv &); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geojson/util.hpp b/MapboxGLAndroidSDK/src/cpp/geojson/util.hpp new file mode 100644 index 000000000..59154516f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geojson/util.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "point.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +// Clang 3.8 fails to implicitly convert matching types, so we'll have to do it explicitly. +template +To convertExplicit(From&& src) { + static_assert(std::is_same::container_type, + typename To::container_type>::value, + "container types do not match"); + static_assert(std::is_rvalue_reference::value, + "argument must be rvalue reference"); + return *reinterpret_cast>(&src); +} + +/** + * Geometry -> List + */ +template +static jni::Local> asPointsList(jni::JNIEnv& env, const T& pointsList) { + auto jarray = jni::Array>::New(env, pointsList.size()); + + for (jni::jsize i = 0; i < pointsList.size(); i++) { + jarray.Set(env, i, Point::New(env, pointsList.at(i))); + } + + return java::util::Arrays::asList(env, jarray); +} + +/** + * Geometry -> List> + */ +template +static jni::Local> asPointsListsList(JNIEnv& env, const SHAPE& value) { + auto jarray = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); i++) { + jarray.Set(env, i, asPointsList(env, value[i])); + } + + return java::util::Arrays::asList(env, jarray); +} + +} // namespace geojson +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.cpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.cpp new file mode 100644 index 000000000..5d8313cb2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.cpp @@ -0,0 +1,29 @@ +#include "lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLng::New(jni::JNIEnv& env, const mbgl::LatLng& latLng) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, latLng.latitude(), latLng.longitude()); +} + +mbgl::Point LatLng::getGeometry(jni::JNIEnv& env, const jni::Object& latLng) { + static auto& javaClass = jni::Class::Singleton(env); + static auto latitudeField = javaClass.GetField(env, "latitude"); + static auto longitudeField = javaClass.GetField(env, "longitude"); + return mbgl::Point(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField)); +} + +mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, const jni::Object& latLng) { + auto point = LatLng::getGeometry(env, latLng); + return mbgl::LatLng(point.y, point.x); +} + +void LatLng::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.hpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.hpp new file mode 100644 index 000000000..30b7db1ef --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include + +namespace mbgl { +namespace android { + +class LatLng : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::LatLng&); + + static mbgl::Point getGeometry(jni::JNIEnv&, const jni::Object&); + + static mbgl::LatLng getLatLng(jni::JNIEnv&, const jni::Object&); + + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.cpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.cpp new file mode 100644 index 000000000..cf534a06e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.cpp @@ -0,0 +1,30 @@ +#include "lat_lng_bounds.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west()); +} + +mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, const jni::Object& bounds) { + static auto& javaClass = jni::Class::Singleton(env); + static auto swLatField = javaClass.GetField(env, "latitudeSouth"); + static auto swLonField = javaClass.GetField(env, "longitudeWest"); + static auto neLatField = javaClass.GetField(env, "latitudeNorth"); + static auto neLonField = javaClass.GetField(env, "longitudeEast"); + + mbgl::LatLng sw = { bounds.Get(env, swLatField), bounds.Get(env, swLonField) }; + mbgl::LatLng ne = { bounds.Get(env, neLatField), bounds.Get(env, neLonField) }; + + return mbgl::LatLngBounds::hull(sw, ne); +} + +void LatLngBounds::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.hpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.hpp new file mode 100644 index 000000000..d51026711 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_bounds.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +namespace mbgl { +namespace android { + +class LatLngBounds : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::LatLngBounds); + + static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.cpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.cpp new file mode 100644 index 000000000..1a1e49048 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.cpp @@ -0,0 +1,37 @@ +#include "lat_lng_quad.hpp" +#include "lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> LatLngQuad::New(jni::JNIEnv& env, std::array coordinates) { + static auto& javaClass = jni::Class::Singleton(env); + static auto quadConstructor = javaClass.GetConstructor, jni::Object, jni::Object, jni::Object>(env); + return javaClass.New(env, quadConstructor, + LatLng::New(env, coordinates[0]), + LatLng::New(env, coordinates[1]), + LatLng::New(env, coordinates[2]), + LatLng::New(env, coordinates[3])); +} + +std::array LatLngQuad::getLatLngArray(jni::JNIEnv& env, const jni::Object& quad) { + static auto& javaClass = jni::Class::Singleton(env); + static auto topLeftField = javaClass.GetField >(env, "topLeft"); + static auto topRightField = javaClass.GetField >(env, "topRight"); + static auto bottomRightField = javaClass.GetField >(env, "bottomRight"); + static auto bottomLeftField = javaClass.GetField >(env, "bottomLeft"); + + return std::array < mbgl::LatLng, 4 > {{ + LatLng::getLatLng(env, quad.Get(env, topLeftField)), + LatLng::getLatLng(env, quad.Get(env, topRightField)), + LatLng::getLatLng(env, quad.Get(env, bottomRightField)), + LatLng::getLatLng(env, quad.Get(env, bottomLeftField)) + }}; +} + +void LatLngQuad::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.hpp b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.hpp new file mode 100644 index 000000000..f6560b57b --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/lat_lng_quad.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace android { + +class LatLngQuad : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngQuad"; }; + + static jni::Local> New(jni::JNIEnv&, std::array); + + static std::array getLatLngArray(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.cpp b/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.cpp new file mode 100644 index 000000000..e079de006 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.cpp @@ -0,0 +1,17 @@ +#include "projected_meters.hpp" + +namespace mbgl { +namespace android { + +jni::Local> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, northing, easting); +} + +void ProjectedMeters::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.hpp b/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.hpp new file mode 100644 index 000000000..baad1efc8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/geometry/projected_meters.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { + +class ProjectedMeters : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; }; + + static jni::Local> New(jni::JNIEnv&, double, double); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/graphics/pointf.cpp b/MapboxGLAndroidSDK/src/cpp/graphics/pointf.cpp new file mode 100644 index 000000000..2fc762d6e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/graphics/pointf.cpp @@ -0,0 +1,25 @@ +#include +#include "pointf.hpp" + +namespace mbgl { +namespace android { + +jni::Local> PointF::New(jni::JNIEnv& env, float x, float y) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, x, y); +} + +mbgl::ScreenCoordinate PointF::getScreenCoordinate(jni::JNIEnv& env, const jni::Object& point) { + static auto& javaClass = jni::Class::Singleton(env); + static auto xField = javaClass.GetField(env, "x"); + static auto yField = javaClass.GetField(env, "y"); + return mbgl::ScreenCoordinate{point.Get(env, xField), point.Get(env, yField)}; +} + +void PointF::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/graphics/pointf.hpp b/MapboxGLAndroidSDK/src/cpp/graphics/pointf.hpp new file mode 100644 index 000000000..899468b8e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/graphics/pointf.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class PointF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/PointF"; }; + + static jni::Local> New(jni::JNIEnv&, float, float); + + static mbgl::ScreenCoordinate getScreenCoordinate(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/graphics/rectf.cpp b/MapboxGLAndroidSDK/src/cpp/graphics/rectf.cpp new file mode 100644 index 000000000..8f418da03 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/graphics/rectf.cpp @@ -0,0 +1,35 @@ +#include "rectf.hpp" + +namespace mbgl { +namespace android { + +float RectF::getLeft(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "left"); + return rectf.Get(env, field); +} + +float RectF::getTop(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "top"); + return rectf.Get(env, field); +} + +float RectF::getRight(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "right"); + return rectf.Get(env, field); +} + +float RectF::getBottom(jni::JNIEnv& env, const jni::Object& rectf) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "bottom"); + return rectf.Get(env, field); +} + +void RectF::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/graphics/rectf.hpp b/MapboxGLAndroidSDK/src/cpp/graphics/rectf.hpp new file mode 100644 index 000000000..ba611f226 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/graphics/rectf.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class RectF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/RectF"; }; + + static float getLeft(jni::JNIEnv&, const jni::Object&); + + static float getTop(jni::JNIEnv&, const jni::Object&); + + static float getRight(jni::JNIEnv&, const jni::Object&); + + static float getBottom(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_array.cpp b/MapboxGLAndroidSDK/src/cpp/gson/json_array.cpp new file mode 100644 index 000000000..8ffa658b7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_array.cpp @@ -0,0 +1,50 @@ +#include "json_array.hpp" +#include "json_element.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +jni::Local> JsonArray::New(jni::JNIEnv& env, const std::vector& values){ + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + static auto addMethod = javaClass.GetMethod)>(env, "add"); + + auto jsonArray = javaClass.New(env, constructor); + + for (const auto &v : values) { + jsonArray.Call(env, addMethod, JsonElement::New(env, v)); + } + + return jsonArray; +} + +std::vector JsonArray::convert(jni::JNIEnv& env, const jni::Object& jsonArray) { + std::vector values; + + if (jsonArray) { + static auto& javaClass = jni::Class::Singleton(env); + static auto getMethod = javaClass.GetMethod (jni::jint)>(env, "get"); + static auto sizeMethod = javaClass.GetMethod(env, "size"); + + int size = jsonArray.Call(env, sizeMethod); + values.reserve(uint(size)); + + for (int i = 0; i < size; i++) { + auto entry = jsonArray.Call(env, getMethod, i); + if (entry) { + values.push_back(JsonElement::convert(env, entry)); + } + } + } + + return values; +} + +void JsonArray::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_array.hpp b/MapboxGLAndroidSDK/src/cpp/gson/json_array.hpp new file mode 100644 index 000000000..24d5d3d29 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_array.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonArray { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonArray"; }; + + static jni::Local> New(jni::JNIEnv&, const std::vector&); + static std::vector convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_element.cpp b/MapboxGLAndroidSDK/src/cpp/gson/json_element.cpp new file mode 100644 index 000000000..ba22304d0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_element.cpp @@ -0,0 +1,88 @@ +#include "json_element.hpp" +#include "json_array.hpp" +#include "json_object.hpp" +#include "json_primitive.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +jni::Local> JsonElement::New(jni::JNIEnv& env, const mbgl::Value& value) { + static auto& primitive = jni::Class::Singleton(env); + static auto stringConstructor = primitive.GetConstructor(env); + static auto numberConstructor = primitive.GetConstructor(env); + static auto booleanConstructor = primitive.GetConstructor(env); + + return value.match( + [&] (const mbgl::NullValue&) { + return jni::Local>(); + }, + [&] (const std::string& value) { + return primitive.New(env, stringConstructor, jni::Make(env, value)); + }, + [&] (const double value) { + return primitive.New(env, numberConstructor, jni::Box(env, value)); + }, + [&] (const int64_t value) { + return primitive.New(env, numberConstructor, jni::Box(env, value)); + }, + [&] (const uint64_t value) { + return primitive.New(env, numberConstructor, jni::Box(env, int64_t(value))); // TODO: should use BigInteger + }, + [&] (const bool value) { + return primitive.New(env, booleanConstructor, jni::Box(env, value ? jni::jni_true : jni::jni_false)); + }, + [&] (const std::vector& values) { + return JsonArray::New(env, values); + }, + [&] (const mbgl::PropertyMap& values) { + return JsonObject::New(env, values); + } + ); +} + +mbgl::Value JsonElement::convert(jni::JNIEnv &env, const jni::Object& jsonElement) { + if (!jsonElement) { + return mbgl::NullValue(); + } + + static auto& elementClass = jni::Class::Singleton(env); + static auto isJsonObject = elementClass.GetMethod(env, "isJsonObject"); + static auto isJsonArray = elementClass.GetMethod(env, "isJsonArray"); + static auto isJsonPrimitive = elementClass.GetMethod(env, "isJsonPrimitive"); + + static auto& primitiveClass = jni::Class::Singleton(env); + static auto isBoolean = primitiveClass.GetMethod(env, "isBoolean"); + static auto isString = primitiveClass.GetMethod(env, "isString"); + static auto isNumber = primitiveClass.GetMethod(env, "isNumber"); + static auto getAsBoolean = primitiveClass.GetMethod(env, "getAsBoolean"); + static auto getAsString = primitiveClass.GetMethod(env, "getAsString"); + static auto getAsDouble = primitiveClass.GetMethod(env, "getAsDouble"); + + if (jsonElement.Call(env, isJsonPrimitive)) { + auto primitive = jni::Cast(env, primitiveClass, jsonElement); + if (primitive.Call(env, isBoolean)) { + return bool(primitive.Call(env, getAsBoolean)); + } else if (primitive.Call(env, isNumber)) { + return primitive.Call(env, getAsDouble); + } else if (primitive.Call(env, isString)) { + return jni::Make(env, primitive.Call(env, getAsString)); + } else { + return mbgl::NullValue(); + } + } else if (jsonElement.Call(env, isJsonObject)) { + return JsonObject::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); + } else if (jsonElement.Call(env, isJsonArray)) { + return JsonArray::convert(env, jni::Cast(env, jni::Class::Singleton(env), jsonElement)); + } else { + return mbgl::NullValue(); + } +} + +void JsonElement::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_element.hpp b/MapboxGLAndroidSDK/src/cpp/gson/json_element.hpp new file mode 100644 index 000000000..e3b8a0268 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_element.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonElement { +public: + using SuperTag = jni::ObjectTag; + static constexpr auto Name() { return "com/google/gson/JsonElement"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::Value&); + static mbgl::Value convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_object.cpp b/MapboxGLAndroidSDK/src/cpp/gson/json_object.cpp new file mode 100644 index 000000000..10d244ee4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_object.cpp @@ -0,0 +1,65 @@ +#include "json_object.hpp" + +#include "json_element.hpp" + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace gson { + + +jni::Local> JsonObject::New(jni::JNIEnv& env, const mbgl::PropertyMap& values) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + static auto addMethod = javaClass.GetMethod)>(env, "add"); + + auto jsonObject = javaClass.New(env, constructor); + + for (auto &item : values) { + jsonObject.Call(env, addMethod, + jni::Make(env, item.first), + JsonElement::New(env, item.second)); + } + + return jsonObject; +} + +template // void (jni::String, jni::Object) +static void iterateEntrySet(jni::JNIEnv& env, const jni::Object& jsonObject, F callback) { + // Get Set> + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "entrySet"); + + auto entryArray = java::util::Set::toArray(env, jsonObject.Call(env, method)); + + size_t size = entryArray.Length(env); + for (size_t i = 0; i < size; i++) { + auto entry = entryArray.Get(env, i); + if (entry) { + callback( + java::util::Map::Entry::getKey(env, entry), + java::util::Map::Entry::getValue(env, entry)); + } + } +} + +mbgl::PropertyMap JsonObject::convert(jni::JNIEnv& env, const jni::Object& jsonObject) { + mbgl::PropertyMap map; + + if (jsonObject) { + iterateEntrySet(env, jsonObject, [&map, &env](const jni::String& jId, const jni::Object& jsonElement) { + map[jni::Make(env, jId)] = JsonElement::convert(env, jsonElement); + }); + } + + return map; +} + +void JsonObject::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_object.hpp b/MapboxGLAndroidSDK/src/cpp/gson/json_object.hpp new file mode 100644 index 000000000..b8916f8ae --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_object.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonObject { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonObject"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::PropertyMap&); + static mbgl::PropertyMap convert(JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.cpp b/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.cpp new file mode 100644 index 000000000..79d6b0761 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.cpp @@ -0,0 +1,13 @@ +#include "json_primitive.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +void JsonPrimitive::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.hpp b/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.hpp new file mode 100644 index 000000000..36f138d90 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/gson/json_primitive.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "json_element.hpp" + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonPrimitive { +public: + using SuperTag = JsonElement; + static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; }; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/http_file_source.cpp b/MapboxGLAndroidSDK/src/cpp/http_file_source.cpp new file mode 100644 index 000000000..37f730737 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/http_file_source.cpp @@ -0,0 +1,195 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "attach_env.hpp" + +namespace mbgl { + +class HTTPFileSource::Impl { +public: + android::UniqueEnv env { android::AttachEnv() }; +}; + +class HTTPRequest : public AsyncRequest { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/NativeHttpRequest"; }; + + HTTPRequest(jni::JNIEnv&, const Resource&, FileSource::Callback); + ~HTTPRequest(); + + void onFailure(jni::JNIEnv&, int type, const jni::String& message); + void onResponse(jni::JNIEnv&, int code, + const jni::String& etag, const jni::String& modified, + const jni::String& cacheControl, const jni::String& expires, + const jni::String& retryAfter, const jni::String& xRateLimitReset, + const jni::Array& body); + + jni::Global> javaRequest; + +private: + Resource resource; + FileSource::Callback callback; + Response response; + + util::AsyncTask async { [this] { + // Calling `callback` may result in deleting `this`. Copy data to temporaries first. + auto callback_ = callback; + auto response_ = response; + callback_(response_); + } }; + + static const int connectionError = 0; + static const int temporaryError = 1; + static const int permanentError = 2; +}; + +namespace android { + +void RegisterNativeHTTPRequest(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&HTTPRequest::onFailure, "nativeOnFailure"), + METHOD(&HTTPRequest::onResponse, "nativeOnResponse")); +} + +} // namespace android + +HTTPRequest::HTTPRequest(jni::JNIEnv& env, const Resource& resource_, FileSource::Callback callback_) + : resource(resource_), + callback(callback_) { + std::string etagStr; + std::string modifiedStr; + + if (resource.priorEtag) { + etagStr = *resource.priorEtag; + } else if (resource.priorModified) { + modifiedStr = util::rfc1123(*resource.priorModified); + } + + jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 10); + + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = + javaClass.GetConstructor(env); + + javaRequest = jni::NewGlobal(env, + javaClass.New(env, constructor, + reinterpret_cast(this), + jni::Make(env, resource.url), + jni::Make(env, etagStr), + jni::Make(env, modifiedStr), + (jboolean) (resource_.usage == Resource::Usage::Offline) + ) + ); +} + +HTTPRequest::~HTTPRequest() { + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto cancel = javaClass.GetMethod(*env, "cancel"); + + javaRequest.Call(*env, cancel); +} + +void HTTPRequest::onResponse(jni::JNIEnv& env, int code, + const jni::String& etag, const jni::String& modified, + const jni::String& cacheControl, const jni::String& expires, + const jni::String& jRetryAfter, const jni::String& jXRateLimitReset, + const jni::Array& body) { + + using Error = Response::Error; + + if (etag) { + response.etag = jni::Make(env, etag); + } + + if (modified) { + response.modified = util::parseTimestamp(jni::Make(env, modified).c_str()); + } + + if (cacheControl) { + const auto cc = http::CacheControl::parse(jni::Make(env, cacheControl).c_str()); + response.expires = cc.toTimePoint(); + response.mustRevalidate = cc.mustRevalidate; + } + + if (expires) { + response.expires = util::parseTimestamp(jni::Make(env, expires).c_str()); + } + + if (code == 200) { + if (body) { + auto data = std::make_shared(body.Length(env), char()); + jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast(&(*data)[0])); + response.data = data; + } else { + response.data = std::make_shared(); + } + } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) { + response.noContent = true; + } else if (code == 304) { + response.notModified = true; + } else if (code == 404) { + response.error = std::make_unique(Error::Reason::NotFound, "HTTP status code 404"); + } else if (code == 429) { + optional retryAfter; + optional xRateLimitReset; + if (jRetryAfter) { + retryAfter = jni::Make(env, jRetryAfter); + } + if (jXRateLimitReset) { + xRateLimitReset = jni::Make(env, jXRateLimitReset); + } + response.error = std::make_unique(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset)); + } else if (code >= 500 && code < 600) { + response.error = std::make_unique(Error::Reason::Server, std::string{ "HTTP status code " } + util::toString(code)); + } else { + response.error = std::make_unique(Error::Reason::Other, std::string{ "HTTP status code " } + util::toString(code)); + } + + async.send(); +} + +void HTTPRequest::onFailure(jni::JNIEnv& env, int type, const jni::String& message) { + std::string messageStr = jni::Make(env, message); + + using Error = Response::Error; + + switch (type) { + case connectionError: + response.error = std::make_unique(Error::Reason::Connection, messageStr); + break; + case temporaryError: + response.error = std::make_unique(Error::Reason::Server, messageStr); + break; + default: + response.error = std::make_unique(Error::Reason::Other, messageStr); + } + + async.send(); +} + +HTTPFileSource::HTTPFileSource() + : impl(std::make_unique()) { +} + +HTTPFileSource::~HTTPFileSource() = default; + +std::unique_ptr HTTPFileSource::request(const Resource& resource, Callback callback) { + return std::make_unique(*impl->env, resource, callback); +} + +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/i18n/collator.cpp b/MapboxGLAndroidSDK/src/cpp/i18n/collator.cpp new file mode 100644 index 000000000..92c6ce016 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/i18n/collator.cpp @@ -0,0 +1,192 @@ +#include +#include + +#include + +#include "attach_env.hpp" +#include "collator_jni.hpp" + +namespace mbgl { +namespace android { + +void Collator::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setStrength"); + collator.Call(env, method, strength); +} + +jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "compare"); + return collator.Call(env, method, lhs, rhs); +} + +void StringUtils::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(env, "unaccent"); + return javaClass.Call(env, method, value); +} + +void Locale::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +/* +We would prefer to use for/toLanguageTag, but they're only available in API level 21+ + +jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { + using Signature = jni::Object(jni::String); + auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); + return javaClass.Call(env, method, languageTag); +} + +jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { + using Signature = jni::String(); + auto static method = javaClass.GetMethod(env, "toLanguageTag"); + return locale.Call(env, method); +} +*/ + +jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getLanguage"); + return locale.Call(env, method); +} + +jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getCountry"); + return locale.Call(env, method); +} + +jni::Local> Locale::getDefault(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); + return javaClass.Call(env, method); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language, region); +} + +} // namespace android + +namespace platform { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + , env(android::AttachEnv()) + { + LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, + android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); + if (!diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); + } else if (diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); + } else if (caseSensitive) { + // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator + // and a fallback implementation of diacritic-insensitivity. + android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); + } + } + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && + diacriticSensitive == other.diacriticSensitive && + resolvedLocale() == other.resolvedLocale(); + } + + int compare(const std::string& lhs, const std::string& rhs) const { + bool useUnaccent = !diacriticSensitive && caseSensitive; + // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation + // order, so we have to compromise here. We use Android's case-sensitive Collator + // against strings that have been "unaccented" using non-locale-aware nunicode logic. + // Because of the difference in locale-awareness, this means turning on case-sensitivity + // can _potentially_ change compare results for strings that don't actually have any case + // differences. + jni::Local jlhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) + : jni::Make(*env, lhs); + jni::Local jrhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) + : jni::Make(*env, rhs); + + jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); + + return result; + } + + std::string resolvedLocale() const { + std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); + std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); + + optional resultLanguage; + if (!language.empty()) resultLanguage = language; + optional resultRegion; + if (!region.empty()) resultRegion = region; + + return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); + } + +private: + bool caseSensitive; + bool diacriticSensitive; + + android::UniqueEnv env; + jni::Global> collator; + jni::Global> locale; +}; + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, const optional& locale_) + : impl(std::make_shared(caseSensitive, diacriticSensitive, locale_)) {} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +} // namespace platform +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/i18n/collator_jni.hpp b/MapboxGLAndroidSDK/src/cpp/i18n/collator_jni.hpp new file mode 100644 index 000000000..612f9b49f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/i18n/collator_jni.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +/* + android::Collator and android::Locale are + the JNI wrappers of + java/text/Collator and java/util/Locale + + mbgl::Collator is the portable interface + Both implementations are in collator.cpp + */ + +namespace mbgl { +namespace android { + +class Locale { +public: + static constexpr auto Name() { return "java/util/Locale"; }; + + /* Requires API level 21+ in order to support script/variant + static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); + static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); + */ + static jni::Local> getDefault(jni::JNIEnv&); + static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); + static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::String&); + static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +class Collator { +public: + static constexpr auto Name() { return "java/text/Collator"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + + static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); + + static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + + +class StringUtils { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; + + static jni::Local unaccent(jni::JNIEnv&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/i18n/number_format.cpp b/MapboxGLAndroidSDK/src/cpp/i18n/number_format.cpp new file mode 100644 index 000000000..a804e74f1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/i18n/number_format.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include + +#include "attach_env.hpp" +#include "number_format_jni.hpp" + +namespace mbgl { +namespace android { + +void NumberFormat::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "format"); + return nf.Call(env, method, number); +} + +void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); + return nf.Call(env, method, value); +} + +void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); + return nf.Call(env, method, value); +} + +} // namespace android + +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + auto env{ android::AttachEnv() }; + + jni::Global> locale; + LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + + jni::Global> formatter; + if (currency.empty()) { + formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); + android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); + android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); + } else { + formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); + } + + auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); + return jni::Make(*env, result); +} + +} // namespace platform +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/i18n/number_format_jni.hpp b/MapboxGLAndroidSDK/src/cpp/i18n/number_format_jni.hpp new file mode 100644 index 000000000..172003892 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/i18n/number_format_jni.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "collator_jni.hpp" + +/* + android::NumberFormat is the JNI wrapper + of java/text/NumberFormat. + */ + +namespace mbgl { +namespace android { + +class NumberFormat { +public: + static constexpr auto Name() { return "java/text/NumberFormat"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); + static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/java/util.cpp b/MapboxGLAndroidSDK/src/cpp/java/util.cpp new file mode 100644 index 000000000..b3aebb36c --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/java/util.cpp @@ -0,0 +1,19 @@ +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +void registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); +} + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/java/util.hpp b/MapboxGLAndroidSDK/src/cpp/java/util.hpp new file mode 100644 index 000000000..9b0c01459 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/java/util.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +class List : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/List"; }; + + template + static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { + static auto& javaClass = jni::Class::Singleton(env); + static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); + + return jni::Local>>(env, list.Call(env, toArray).release()); + }; +}; + +class Arrays : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Arrays"; }; + + template + static jni::Local> asList(jni::JNIEnv& env, const jni::Array>& array) { + static auto& javaClass = jni::Class::Singleton(env); + static auto asList = javaClass.GetStaticMethod(jni::Array>)>(env, "asList"); + + auto typeErasedArray = jni::Local>>(env, jni::NewLocal(env, array).release()); + return javaClass.Call(env, asList, typeErasedArray); + } +}; + +class Set : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Set"; }; + + template + static jni::Local>> toArray(jni::JNIEnv& env, const jni::Object& list) { + static auto& javaClass = jni::Class::Singleton(env); + static auto toArray = javaClass.GetMethod> ()>(env, "toArray"); + + return jni::Local>>(env, list.Call(env, toArray).release()); + }; +}; + +class Map : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/util/Map"; }; + + class Entry : private mbgl::util::noncopyable { + public: + static constexpr auto Name() { return "java/util/Map$Entry"; }; + + template + static jni::Local> getKey(jni::JNIEnv& env, const jni::Object& entry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "getKey"); + return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); + } + + template + static jni::Local> getValue(jni::JNIEnv& env, const jni::Object& entry) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod ()>(env, "getValue"); + return jni::Cast(env, jni::Class::Singleton(env), entry.Call(env, method)); + } + }; +}; + +void registerNative(jni::JNIEnv&); + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/java_types.cpp b/MapboxGLAndroidSDK/src/cpp/java_types.cpp new file mode 100644 index 000000000..7a1ba93a5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/java_types.cpp @@ -0,0 +1,49 @@ +#include "java_types.hpp" + +namespace mbgl { +namespace android { +namespace java { + + jni::jclass* ObjectArray::jclass; + + jni::jclass* String::jclass; + + jni::jclass* Boolean::jclass; + jni::jmethodID* Boolean::booleanValueMethodId; + + jni::jclass* Number::jclass; + jni::jmethodID* Number::floatValueMethodId; + jni::jmethodID* Number::doubleValueMethodId; + jni::jmethodID* Number::longValueMethodId; + + jni::jclass* Map::jclass; + jni::jmethodID* Map::getMethodId; + jni::jmethodID* Map::keySetMethodId; + + jni::jclass* Set::jclass; + jni::jmethodID* Set::toArrayMethodId; + + void registerNatives(JNIEnv& env) { + ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release(); + + String::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); + + Boolean::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); + Boolean::booleanValueMethodId = &jni::GetMethodID(env, *Boolean::jclass, "booleanValue", "()Z"); + + Number::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Number")).release(); + Number::floatValueMethodId = &jni::GetMethodID(env, *Number::jclass, "floatValue", "()F"); + Number::doubleValueMethodId = &jni::GetMethodID(env, *Number::jclass, "doubleValue", "()D"); + Number::longValueMethodId = &jni::GetMethodID(env, *Number::jclass, "longValue", "()J"); + + Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release(); + Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); + Map::keySetMethodId = &jni::GetMethodID(env, *Map::jclass, "keySet", "()Ljava/util/Set;"); + + Set::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Set")).release(); + Set::toArrayMethodId = &jni::GetMethodID(env, *Set::jclass, "toArray", "()[Ljava/lang/Object;"); + } + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/java_types.hpp b/MapboxGLAndroidSDK/src/cpp/java_types.hpp new file mode 100644 index 000000000..c7c93ce71 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/java_types.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { +namespace java { + + struct ObjectArray { + static jni::jclass* jclass; + }; + + struct String { + static jni::jclass* jclass; + }; + + struct Boolean { + static jni::jclass* jclass; + static jni::jmethodID* booleanValueMethodId; + }; + + struct Number { + static jni::jclass* jclass; + static jni::jmethodID* floatValueMethodId; + static jni::jmethodID* doubleValueMethodId; + static jni::jmethodID* longValueMethodId; + }; + + struct Map { + static jni::jclass* jclass; + static jni::jmethodID* getMethodId; + static jni::jmethodID* keySetMethodId; + }; + + struct Set { + static jni::jclass* jclass; + static jni::jmethodID* toArrayMethodId; + }; + + void registerNatives(JNIEnv&); +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/jni_native.cpp b/MapboxGLAndroidSDK/src/cpp/jni_native.cpp new file mode 100644 index 000000000..d6b03d981 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/jni_native.cpp @@ -0,0 +1,168 @@ +#include "jni_native.hpp" + +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "bitmap.hpp" +#include "bitmap_factory.hpp" +#include "connectivity_listener.hpp" +#include "conversion/collection.hpp" +#include "conversion/conversion.hpp" +#include "file_source.hpp" +#include "geojson/feature.hpp" +#include "geojson/feature_collection.hpp" +#include "geojson/geometry.hpp" +#include "geojson/geometry_collection.hpp" +#include "geojson/line_string.hpp" +#include "geojson/multi_line_string.hpp" +#include "geojson/multi_point.hpp" +#include "geojson/multi_polygon.hpp" +#include "geojson/point.hpp" +#include "geojson/polygon.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "geometry/lat_lng_quad.hpp" +#include "geometry/projected_meters.hpp" +#include "graphics/pointf.hpp" +#include "graphics/rectf.hpp" +#include "gson/json_array.hpp" +#include "gson/json_element.hpp" +#include "gson/json_object.hpp" +#include "gson/json_primitive.hpp" +#include "java_types.hpp" +#include "map_renderer.hpp" +#include "map_renderer_runnable.hpp" +#include "mapbox.hpp" +#include "native_map_view.hpp" +#ifndef MBGL_MODULE_OFFLINE_DISABLE +#include "offline/offline_manager.hpp" +#include "offline/offline_region.hpp" +#include "offline/offline_region_definition.hpp" +#include "offline/offline_region_error.hpp" +#include "offline/offline_region_status.hpp" +#endif +#include "style/transition_options.hpp" +#include "style/layers/layer_manager.hpp" +#include "style/sources/source.hpp" +#include "style/light.hpp" +#include "style/formatted.hpp" +#include "style/formatted_section.hpp" +#ifndef MBGL_MODULE_SNAPSHOT_DISABLE +#include "snapshotter/map_snapshotter.hpp" +#include "snapshotter/map_snapshot.hpp" +#endif +#include "i18n/collator_jni.hpp" +#include "i18n/number_format_jni.hpp" +#include "logger.hpp" +#include "text/local_glyph_rasterizer_jni.hpp" + +namespace mbgl { +namespace android { + +void RegisterNativeHTTPRequest(JNIEnv&); + +void registerNatives(JavaVM *vm) { + theJVM = vm; + + jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6); + + // For the FileSource + static mbgl::util::RunLoop mainRunLoop; + FileSource::registerNative(env); + + // Basic types + java::registerNatives(env); + java::util::registerNative(env); + PointF::registerNative(env); + RectF::registerNative(env); + + // GeoJSON + geojson::Feature::registerNative(env); + geojson::FeatureCollection::registerNative(env); + geojson::Geometry::registerNative(env); + geojson::GeometryCollection::registerNative(env); + geojson::LineString::registerNative(env); + geojson::MultiLineString::registerNative(env); + geojson::MultiPoint::registerNative(env); + geojson::MultiPolygon::registerNative(env); + geojson::Point::registerNative(env); + geojson::Polygon::registerNative(env); + + // Geometry + LatLng::registerNative(env); + LatLngBounds::registerNative(env); + LatLngQuad::registerNative(env); + ProjectedMeters::registerNative(env); + + // GSon + gson::JsonArray::registerNative(env); + gson::JsonElement::registerNative(env); + gson::JsonObject::registerNative(env); + gson::JsonPrimitive::registerNative(env); + + //Annotation + Marker::registerNative(env); + Polygon::registerNative(env); + Polyline::registerNative(env); + + // Map + MapRenderer::registerNative(env); + MapRendererRunnable::registerNative(env); + NativeMapView::registerNative(env); + + // Http + RegisterNativeHTTPRequest(env); + + // Bitmap + Bitmap::registerNative(env); + BitmapFactory::registerNative(env); + + // Style + TransitionOptions::registerNative(env); + LayerManagerAndroid::get()->registerNative(env); + Source::registerNative(env); + Light::registerNative(env); + Position::registerNative(env); + Formatted::registerNative(env); + FormattedSection::registerNative(env); + + // Map + CameraPosition::registerNative(env); + Image::registerNative(env); + + // Connectivity + ConnectivityListener::registerNative(env); + + // Offline +#ifndef MBGL_MODULE_OFFLINE_DISABLE + OfflineManager::registerNative(env); + OfflineRegion::registerNative(env); + OfflineRegionDefinition::registerNative(env); + OfflineTilePyramidRegionDefinition::registerNative(env); + OfflineGeometryRegionDefinition::registerNative(env); + OfflineRegionError::registerNative(env); + OfflineRegionStatus::registerNative(env); +#endif + + // Snapshotter +#ifndef MBGL_MODULE_SNAPSHOT_DISABLE + MapSnapshotter::registerNative(env); + MapSnapshot::registerNative(env); +#endif + + // text + LocalGlyphRasterizer::registerNative(env); + Locale::registerNative(env); + Collator::registerNative(env); + StringUtils::registerNative(env); + NumberFormat::registerNative(env); + + // Logger + Logger::registerNative(env); + + // AssetManager + Mapbox::registerNative(env); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/jni_native.hpp b/MapboxGLAndroidSDK/src/cpp/jni_native.hpp new file mode 100644 index 000000000..1cc9a7e81 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/jni_native.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "jni.hpp" + +namespace mbgl { +namespace android { + +MBGL_EXPORT void registerNatives(JavaVM* vm); + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/logger.cpp b/MapboxGLAndroidSDK/src/cpp/logger.cpp new file mode 100644 index 000000000..f5d78cc83 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/logger.cpp @@ -0,0 +1,34 @@ +#include "logger.hpp" +#include "java_types.hpp" + +namespace mbgl { +namespace android { + +void Logger::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +void Logger::log(jni::JNIEnv& env, EventSeverity severity, const std::string &msg) { + static auto& _class = jni::Class::Singleton(env); + + auto tag = jni::Make(env, "Mbgl"); + auto message = jni::Make(env, msg); + using Signature = void(jni::String, jni::String); + + if (severity == EventSeverity::Debug) { + auto static debug = _class.GetStaticMethod(env, "d"); + _class.Call(env, debug, tag, message); + } else if (severity == EventSeverity::Info) { + auto static info = _class.GetStaticMethod(env, "i"); + _class.Call(env, info, tag, message); + } else if(severity == EventSeverity::Warning) { + auto static warning = _class.GetStaticMethod(env, "w"); + _class.Call(env, warning, tag, message); + } else { + auto static error = _class.GetStaticMethod(env, "e"); + _class.Call(env, error, tag, message); + } +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/logger.hpp b/MapboxGLAndroidSDK/src/cpp/logger.hpp new file mode 100644 index 000000000..7481ecb26 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/logger.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include "bitmap.hpp" + +namespace mbgl { +namespace android { + +class Logger { +public: + static constexpr auto Name() { + return "com/mapbox/mapboxsdk/log/Logger"; + }; + static void registerNative(jni::JNIEnv&); + + static void log(jni::JNIEnv&, EventSeverity severity, const std::string &msg); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/logging_android.cpp b/MapboxGLAndroidSDK/src/cpp/logging_android.cpp new file mode 100644 index 000000000..130136728 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/logging_android.cpp @@ -0,0 +1,13 @@ +#include + +#include "logger.hpp" +#include "attach_env.hpp" + +namespace mbgl { + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + auto env{ android::AttachEnv() }; + android::Logger::log(*env, severity, msg); +} + +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/main.cpp b/MapboxGLAndroidSDK/src/cpp/main.cpp new file mode 100644 index 000000000..9b5c6c197 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/main.cpp @@ -0,0 +1,9 @@ +#include "jni.hpp" +#include "jni_native.hpp" +#include + +extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { + assert(vm != nullptr); + mbgl::android::registerNatives(vm); + return JNI_VERSION_1_6; +} diff --git a/MapboxGLAndroidSDK/src/cpp/map/camera_position.cpp b/MapboxGLAndroidSDK/src/cpp/map/camera_position.cpp new file mode 100644 index 000000000..4266b64fd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map/camera_position.cpp @@ -0,0 +1,69 @@ +#include "camera_position.hpp" +#include "../geometry/lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Local> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options, float pixelRatio) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, double, double, double, jni::Array>(env); + + // wrap LatLng values coming from core + auto center = options.center.value(); + center.wrap(); + + // convert bearing, measured in radians counterclockwise from true north. + // Wrapped to [−π rad, π rad). Android binding from 0 to 360 degrees + double bearing_degrees = options.bearing.value_or(0); + while (bearing_degrees > 360) { + bearing_degrees -= 360; + } + while (bearing_degrees < 0) { + bearing_degrees += 360; + } + + // convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60 + double tilt_degrees = options.pitch.value_or(0); + + std::vector paddingVect; + auto insets = options.padding.value_or(EdgeInsets {0, 0, 0, 0}); + auto padding = jni::Array::New(env, 4); + paddingVect.push_back(insets.left() * pixelRatio); + paddingVect.push_back(insets.top() * pixelRatio); + paddingVect.push_back(insets.right() * pixelRatio); + paddingVect.push_back(insets.bottom() * pixelRatio); + padding.SetRegion>(env, 0, paddingVect); + + return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees, padding); +} + +mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object& position, float pixelRatio) { + static auto& javaClass = jni::Class::Singleton(env); + static auto bearing = javaClass.GetField(env, "bearing"); + static auto target = javaClass.GetField>(env, "target"); + static auto tilt = javaClass.GetField(env, "tilt"); + static auto zoom = javaClass.GetField(env, "zoom"); + static auto paddingField = javaClass.GetField>(env, "padding"); + + auto padding = position.Get(env, paddingField); + auto center = LatLng::getLatLng(env, position.Get(env, target)); + + return mbgl::CameraOptions{center, + padding && padding.Length(env) == 4 ? EdgeInsets{padding.Get(env, 1) * pixelRatio, + padding.Get(env, 0) * pixelRatio, + padding.Get(env, 3) * pixelRatio, + padding.Get(env, 2) * pixelRatio} + : (EdgeInsets){}, + {}, + position.Get(env, zoom), + position.Get(env, bearing), + position.Get(env, tilt)}; +} + +void CameraPosition::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mb + diff --git a/MapboxGLAndroidSDK/src/cpp/map/camera_position.hpp b/MapboxGLAndroidSDK/src/cpp/map/camera_position.hpp new file mode 100644 index 000000000..b677f04ea --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map/camera_position.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { + +class CameraPosition : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::CameraOptions, float pixelRatio); + + static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object&, float pixelRatio); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/map/image.cpp b/MapboxGLAndroidSDK/src/cpp/map/image.cpp new file mode 100644 index 000000000..10c32d257 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map/image.cpp @@ -0,0 +1,41 @@ +#include +#include +#include "image.hpp" + +namespace mbgl { +namespace android { + +mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& image) { + static auto& javaClass = jni::Class::Singleton(env); + static auto widthField = javaClass.GetField(env, "width"); + static auto heightField = javaClass.GetField(env, "height"); + static auto pixelRatioField = javaClass.GetField(env, "pixelRatio"); + static auto bufferField = javaClass.GetField>(env, "buffer"); + static auto nameField = javaClass.GetField(env, "name"); + static auto sdfField = javaClass.GetField(env, "sdf"); + + auto height = image.Get(env, heightField); + auto width = image.Get(env, widthField); + auto pixelRatio = image.Get(env, pixelRatioField); + auto pixels = image.Get(env, bufferField); + auto name = jni::Make(env, image.Get(env, nameField)); + auto sdf = (bool) image.Get(env, sdfField); + + jni::NullCheck(env, pixels.get()); + std::size_t size = pixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(width), static_cast(height) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::StyleImageException("Image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf}; +} + +void Image::registerNative(jni::JNIEnv &env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mb diff --git a/MapboxGLAndroidSDK/src/cpp/map/image.hpp b/MapboxGLAndroidSDK/src/cpp/map/image.hpp new file mode 100644 index 000000000..7549bc646 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map/image.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { +namespace android { + +class Image : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/Image"; }; + + static mbgl::style::Image getImage(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/map_renderer.cpp b/MapboxGLAndroidSDK/src/cpp/map_renderer.cpp new file mode 100644 index 000000000..3ebbdb7e5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map_renderer.cpp @@ -0,0 +1,247 @@ +#include "map_renderer.hpp" + +#include +#include +#include + +#include + +#include "attach_env.hpp" +#include "android_renderer_backend.hpp" +#include "map_renderer_runnable.hpp" + +namespace mbgl { +namespace android { + +MapRenderer::MapRenderer(jni::JNIEnv& _env, + const jni::Object& obj, + jni::jfloat pixelRatio_, + const jni::String& localIdeographFontFamily_) + : javaPeer(_env, obj), + pixelRatio(pixelRatio_), + localIdeographFontFamily(localIdeographFontFamily_ ? jni::Make(_env, localIdeographFontFamily_) + : optional{}), + mailboxData(this) {} + +MapRenderer::MailboxData::MailboxData(Scheduler* scheduler_) : scheduler(scheduler_) { + assert(scheduler); +} + +std::shared_ptr MapRenderer::MailboxData::getMailbox() const noexcept { + if (!mailbox) { + mailbox = std::make_shared(*scheduler); + } + return mailbox; +} + +MapRenderer::~MapRenderer() = default; + +void MapRenderer::reset() { + destroyed = true; + + if (renderer) { + // Make sure to destroy the renderer on the GL Thread + auto self = ActorRef(*this, mailboxData.getMailbox()); + self.ask(&MapRenderer::resetRenderer).wait(); + } + + // Lock to make sure there is no concurrent initialisation on the gl thread + std::lock_guard lock(initialisationMutex); + rendererObserver.reset(); +} + +ActorRef MapRenderer::actor() const { + return *rendererRef; +} + +void MapRenderer::schedule(std::function scheduled) { + // Create a runnable + android::UniqueEnv _env = android::AttachEnv(); + auto runnable = std::make_unique(*_env, std::move(scheduled)); + + // Obtain ownership of the peer (gets transferred to the MapRenderer on the JVM for later GC) + auto peer = runnable->peer(); + + // Queue the event on the Java Peer + static auto& javaClass = jni::Class::Singleton(*_env); + static auto queueEvent = javaClass.GetMethod)>(*_env, "queueEvent"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, queueEvent, peer); + } + + // Release the c++ peer as it will be destroyed on GC of the Java Peer + runnable.release(); +} + +void MapRenderer::requestRender() { + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onInvalidate = javaClass.GetMethod(*_env, "requestRender"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onInvalidate); + } +} + +void MapRenderer::update(std::shared_ptr params) { + // Lock on the parameters + std::lock_guard lock(updateMutex); + updateParameters = std::move(params); +} + +void MapRenderer::setObserver(std::shared_ptr _rendererObserver) { + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(initialisationMutex); + + rendererObserver = std::move(_rendererObserver); + + // Set the new observer on the Renderer implementation + if (renderer) { + renderer->setObserver(rendererObserver.get()); + } +} + +void MapRenderer::requestSnapshot(SnapshotCallback callback) { + auto self = ActorRef(*this, mailboxData.getMailbox()); + self.invoke( + &MapRenderer::scheduleSnapshot, + std::make_unique([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) { + runloop->invoke([callback=std::move(callback), image=std::move(image), renderer=std::move(this)]() mutable { + if (renderer && !renderer->destroyed) { + callback(std::move(image)); + } + }); + snapshotCallback.reset(); + }) + ); +} + +// Called on OpenGL thread // + +void MapRenderer::resetRenderer() { + renderer.reset(); +} + +void MapRenderer::scheduleSnapshot(std::unique_ptr callback) { + snapshotCallback = std::move(callback); + requestRender(); +} + +void MapRenderer::render(JNIEnv&) { + assert (renderer); + + std::shared_ptr params; + { + // Lock on the parameters + std::unique_lock lock(updateMutex); + if (!updateParameters) return; + + // Hold on to the update parameters during render + params = updateParameters; + } + + // Activate the backend + gfx::BackendScope backendGuard { *backend }; + + // Ensure that the "current" scheduler on the render thread is + // this scheduler. + Scheduler::SetCurrent(this); + + if (framebufferSizeChanged) { + backend->updateViewPort(); + framebufferSizeChanged = false; + } + + renderer->render(params); + + // Deliver the snapshot if requested + if (snapshotCallback) { + snapshotCallback->operator()(backend->readFramebuffer()); + snapshotCallback.reset(); + } +} + +void MapRenderer::onSurfaceCreated(JNIEnv&) { + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(initialisationMutex); + + // The GL context is already active if get a new surface. + gfx::BackendScope backendGuard { *backend, gfx::BackendScope::ScopeType::Implicit }; + + // The android system will have already destroyed the underlying + // GL resources if this is not the first initialization and an + // attempt to clean them up will fail + if (backend) backend->markContextLost(); + if (renderer) renderer->markContextLost(); + + // Reset in opposite order + renderer.reset(); + backend.reset(); + + // Create the new backend and renderer + backend = std::make_unique(); + renderer = std::make_unique(*backend, pixelRatio, localIdeographFontFamily); + rendererRef = std::make_unique>(*renderer, mailboxData.getMailbox()); + + // Set the observer on the new Renderer implementation + if (rendererObserver) { + renderer->setObserver(rendererObserver.get()); + } +} + +void MapRenderer::onSurfaceChanged(JNIEnv& env, jint width, jint height) { + if (!renderer) { + // In case the surface has been destroyed (due to app back-grounding) + onSurfaceCreated(env); + } + + backend->resizeFramebuffer(width, height); + framebufferSizeChanged = true; + requestRender(); +} + +void MapRenderer::onRendererReset(JNIEnv&) { + // Make sure to destroy the renderer on the GL Thread + auto self = ActorRef(*this, mailboxData.getMailbox()); + self.ask(&MapRenderer::resetRenderer).wait(); +} + +// needs to be called on GL thread +void MapRenderer::onSurfaceDestroyed(JNIEnv&) { + resetRenderer(); +} + +// Static methods // + +void MapRenderer::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + jni::MakePeer&, jni::jfloat, const jni::String&>, + "nativeInitialize", "finalize", + METHOD(&MapRenderer::render, "nativeRender"), + METHOD(&MapRenderer::onRendererReset, "nativeReset"), + METHOD(&MapRenderer::onSurfaceCreated, + "nativeOnSurfaceCreated"), + METHOD(&MapRenderer::onSurfaceChanged, + "nativeOnSurfaceChanged"), + METHOD(&MapRenderer::onSurfaceDestroyed, + "nativeOnSurfaceDestroyed")); +} + +MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, const jni::Object& jObject) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "nativePtr"); + MapRenderer* mapRenderer = reinterpret_cast(jObject.Get(env, field)); + assert(mapRenderer != nullptr); + return *mapRenderer; +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/map_renderer.hpp b/MapboxGLAndroidSDK/src/cpp/map_renderer.hpp new file mode 100644 index 000000000..e37d37cfc --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map_renderer.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace mbgl { + +template +class ActorRef; +class Mailbox; +class Renderer; +class RendererBackend; +class RendererObserver; +class ThreadPool; +class UpdateParameters; + +namespace android { + +class AndroidRendererBackend; + +/** + * The MapRenderer is a peer class that encapsulates the actions + * performed on the GL Thread. + * + * The public methods are safe to call from the main thread, others are not. + */ +class MapRenderer : public Scheduler { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRenderer"; }; + + static void registerNative(jni::JNIEnv&); + + static MapRenderer& getNativePeer(JNIEnv&, const jni::Object&); + + MapRenderer(jni::JNIEnv& _env, + const jni::Object&, + jni::jfloat pixelRatio, + const jni::String& localIdeographFontFamily); + + ~MapRenderer() override; + + // Resets the renderer to clean up on the calling thread + void reset(); + + // Takes the RendererObserver by shared_ptr so we + // don't have to make the header public. Use + // this instead of Renderer#setObserver directly + void setObserver(std::shared_ptr); + + // Sets the new update parameters to use on subsequent + // renders. Be sure to trigger a render with + // requestRender(). + void update(std::shared_ptr); + + // Gives a handle to the Renderer to enable actions on + // any thread. + ActorRef actor() const; + + // From Scheduler. Schedules by using callbacks to the + // JVM to process the mailbox on the right thread. + void schedule(std::function scheduled) override; + mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } + + void requestRender(); + + // Snapshot - requires a RunLoop on the calling thread + using SnapshotCallback = std::function; + void requestSnapshot(SnapshotCallback); + +protected: + // Called from the GL Thread // + + void scheduleSnapshot(std::unique_ptr); + +private: + struct MailboxData { + explicit MailboxData(Scheduler*); + std::shared_ptr getMailbox() const noexcept; + + private: + Scheduler* scheduler; + mutable std::shared_ptr mailbox; + }; + // Called from the GL Thread // + + // Resets the renderer + void resetRenderer(); + + // Renders a frame. + void render(JNIEnv&); + + void onSurfaceCreated(JNIEnv&); + + void onSurfaceChanged(JNIEnv&, jint width, jint height); + + void onSurfaceDestroyed(JNIEnv&); + +private: + // Called on either Main or GL thread // + void onRendererReset(JNIEnv&); + +private: + jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; + + float pixelRatio; + optional localIdeographFontFamily; + + std::shared_ptr threadPool; + const MailboxData mailboxData; + + std::mutex initialisationMutex; + std::shared_ptr rendererObserver; + + std::unique_ptr backend; + std::unique_ptr renderer; + std::unique_ptr> rendererRef; + + std::shared_ptr updateParameters; + std::mutex updateMutex; + + bool framebufferSizeChanged = false; + std::atomic destroyed {false}; + + std::unique_ptr snapshotCallback; + mapbox::base::WeakPtrFactory weakFactory{this}; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.cpp b/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.cpp new file mode 100644 index 000000000..227f49ee3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.cpp @@ -0,0 +1,49 @@ +#include "map_renderer_runnable.hpp" + +#include + +namespace mbgl { +namespace android { + +MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::function function_) + : function(std::move(function_)) { + // Create the Java peer and hold on to a global reference + // Not using a weak reference here as this might oerflow + // the weak reference table on some devices + jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5); + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + auto instance = javaClass.New(env, constructor, reinterpret_cast(this)); + javaPeer = jni::NewGlobal(env, instance); +} + +MapRendererRunnable::~MapRendererRunnable() = default; + +void MapRendererRunnable::run(jni::JNIEnv&) { + if (function) function(); +} + +jni::Global> MapRendererRunnable::peer() { + return std::move(javaPeer); +} + +// Static methods // + +void MapRendererRunnable::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + std::make_unique, + "nativeInitialize", + "finalize", + METHOD(&MapRendererRunnable::run, "run")); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.hpp b/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.hpp new file mode 100644 index 000000000..24d0f2af4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/map_renderer_runnable.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include +#include + +#include + +namespace mbgl { +namespace android { + +/** + * The MapRendererRunnable is a peer class that encapsulates + * a scheduled mailbox in a Java Runnable so it can be + * scheduled on the map renderer thread. + * + */ +class MapRendererRunnable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable"; }; + + static void registerNative(jni::JNIEnv&); + + MapRendererRunnable(jni::JNIEnv&, std::function); + + // Only for jni registration, unused + MapRendererRunnable(jni::JNIEnv&) { + assert(false); + } + + ~MapRendererRunnable(); + + void run(jni::JNIEnv&); + + // Transfers ownership of the Peer object to the caller + jni::Global> peer(); + +private: + jni::Global> javaPeer; + std::function function; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/mapbox.cpp b/MapboxGLAndroidSDK/src/cpp/mapbox.cpp new file mode 100644 index 000000000..5246739cf --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/mapbox.cpp @@ -0,0 +1,23 @@ +#include "mapbox.hpp" + +namespace mbgl { +namespace android { + +jni::Local> Mapbox::getAssetManager(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod()>(env, "getAssetManager"); + return javaClass.Call(env, method); +} + +jboolean Mapbox::hasInstance(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod(env, "hasInstance"); + return javaClass.Call(env, method); +} + +void Mapbox::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/mapbox.hpp b/MapboxGLAndroidSDK/src/cpp/mapbox.hpp new file mode 100644 index 000000000..813f5bf17 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/mapbox.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "asset_manager.hpp" + +#include + +namespace mbgl { +namespace android { + +class Mapbox { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/Mapbox"; }; + static jboolean hasInstance(jni::JNIEnv&); + static jni::Local> getAssetManager(jni::JNIEnv&); + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/native_map_view.cpp b/MapboxGLAndroidSDK/src/cpp/native_map_view.cpp new file mode 100644 index 000000000..ddb2e2c3b --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/native_map_view.cpp @@ -0,0 +1,1263 @@ +#include "native_map_view.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Java -> C++ conversion +#include "style/android_conversion.hpp" +#include +#include + +// C++ -> Java conversion +#include "conversion/conversion.hpp" +#include "conversion/collection.hpp" +#include "style/conversion/filter.hpp" +#include "geojson/feature.hpp" + +#include "android_renderer_frontend.hpp" +#include "attach_env.hpp" +#include "bitmap.hpp" +#include "bitmap_factory.hpp" +#include "file_source.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "java/util.hpp" +#include "jni.hpp" +#include "map/camera_position.hpp" +#include "map/image.hpp" +#include "map_renderer.hpp" +#include "run_loop_impl.hpp" +#include "style/light.hpp" + +namespace mbgl { +namespace android { + +NativeMapView::NativeMapView(jni::JNIEnv& _env, + const jni::Object& _obj, + const jni::Object& jFileSource, + const jni::Object& jMapRenderer, + jni::jfloat pixelRatio_, + jni::jboolean crossSourceCollisions_) + : javaPeer(_env, _obj), mapRenderer(MapRenderer::getNativePeer(_env, jMapRenderer)), pixelRatio(pixelRatio_) { + // Get a reference to the JavaVM for callbacks + if (_env.GetJavaVM(&vm) < 0) { + _env.ExceptionDescribe(); + return; + } + + // Create a renderer frontend + rendererFrontend = std::make_unique(mapRenderer); + + // Create Map options + MapOptions options; + options.withMapMode(MapMode::Continuous) + .withSize(mbgl::Size{static_cast(width), static_cast(height)}) + .withPixelRatio(pixelRatio) + .withConstrainMode(ConstrainMode::HeightOnly) + .withViewportMode(ViewportMode::Default) + .withCrossSourceCollisions(crossSourceCollisions_); + + // Create the core map + map = std::make_unique( + *rendererFrontend, *this, options, + mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource)); +} + +/** + * Called through NativeMapView#destroy() + */ +NativeMapView::~NativeMapView() { + map.reset(); + vm = nullptr; +} + +void NativeMapView::onCameraWillChange(MapObserver::CameraChangeMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraWillChange = javaClass.GetMethod(*_env, "onCameraWillChange"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraWillChange, (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); + } +} + + +void NativeMapView::onCameraIsChanging() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraIsChanging = javaClass.GetMethod(*_env, "onCameraIsChanging"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraIsChanging); + } +} + +void NativeMapView::onCameraDidChange(MapObserver::CameraChangeMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCameraDidChange = javaClass.GetMethod(*_env, "onCameraDidChange"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onCameraDidChange, + (jboolean) (mode != MapObserver::CameraChangeMode::Immediate)); + } +} + +void NativeMapView::onWillStartLoadingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartLoadingMap = javaClass.GetMethod(*_env, "onWillStartLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartLoadingMap); + } +} + +void NativeMapView::onDidFinishLoadingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishLoadingMap = javaClass.GetMethod(*_env, "onDidFinishLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishLoadingMap); + } +} + +void NativeMapView::onDidFailLoadingMap(MapLoadError, const std::string& error) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFailLoadingMap = javaClass.GetMethod(*_env, "onDidFailLoadingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFailLoadingMap, jni::Make(*_env, error)); + } +} + +void NativeMapView::onWillStartRenderingFrame() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartRenderingFrame = javaClass.GetMethod(*_env, "onWillStartRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartRenderingFrame); + } +} + +void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderFrameStatus status) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingFrame = javaClass.GetMethod(*_env, "onDidFinishRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (status.mode != MapObserver::RenderMode::Partial)); + } +} + + +void NativeMapView::onWillStartRenderingMap() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onWillStartRenderingMap = javaClass.GetMethod(*_env, "onWillStartRenderingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onWillStartRenderingMap); + } +} + +void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingMap = javaClass.GetMethod(*_env, "onDidFinishRenderingMap"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishRenderingMap, (jboolean) (mode != MapObserver::RenderMode::Partial)); + } +} + +void NativeMapView::onDidBecomeIdle() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidBecomeIdle = javaClass.GetMethod(*_env, "onDidBecomeIdle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidBecomeIdle); + } +} + +void NativeMapView::onDidFinishLoadingStyle() { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishLoadingStyle = javaClass.GetMethod(*_env, "onDidFinishLoadingStyle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishLoadingStyle); + } +} + +void NativeMapView::onSourceChanged(mbgl::style::Source& source) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onSourceChanged = javaClass.GetMethod(*_env, "onSourceChanged"); + auto sourceId = jni::Make(*_env, source.getID()); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSourceChanged, sourceId); + } +} + +void NativeMapView::onStyleImageMissing(const std::string& imageId) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onStyleImageMissing = javaClass.GetMethod(*_env, "onStyleImageMissing"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onStyleImageMissing, jni::Make(*_env, imageId)); + } +} + +bool NativeMapView::onCanRemoveUnusedStyleImage(const std::string& imageId) { + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onCanRemoveUnusedStyleImage = javaClass.GetMethod(*_env, "onCanRemoveUnusedStyleImage"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + return weakReference.Call(*_env, onCanRemoveUnusedStyleImage, jni::Make(*_env, imageId)); + } + + return true; +} + +// JNI Methods // + +void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) { + width = util::max(64, w); + height = util::max(64, h); + map->setSize({ static_cast(width), static_cast(height) }); +} + +jni::Local NativeMapView::getStyleUrl(jni::JNIEnv& env) { + return jni::Make(env, map->getStyle().getURL()); +} + +void NativeMapView::setStyleUrl(jni::JNIEnv& env, const jni::String& url) { + map->getStyle().loadURL(jni::Make(env, url)); +} + +jni::Local NativeMapView::getStyleJson(jni::JNIEnv& env) { + return jni::Make(env, map->getStyle().getJSON()); +} + +void NativeMapView::setStyleJson(jni::JNIEnv& env, const jni::String& json) { + map->getStyle().loadJSON(jni::Make(env, json)); +} + +void NativeMapView::setLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds) { + mbgl::BoundOptions bounds; + if (jBounds) { + bounds.withLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds)); + } else { + bounds.withLatLngBounds(mbgl::LatLngBounds()); + } + map->setBounds(bounds); +} + +void NativeMapView::cancelTransitions(jni::JNIEnv&) { + map->cancelTransitions(); +} + +void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) { + map->setGestureInProgress(inProgress); +} + +void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::jlong duration) { + mbgl::AnimationOptions animationOptions; + if (duration > 0) { + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + animationOptions.easing.emplace(mbgl::util::UnitBezier {0.25, 0.46, 0.45, 0.94}); + } + map->moveBy({dx, dy}, animationOptions); +} + +void NativeMapView::jumpTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { + mbgl::CameraOptions options; + if (bearing != -1) { + options.bearing = bearing; + } + options.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + options.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + options.pitch = pitch; + } + if (zoom != -1) { + options.zoom = zoom; + } + + map->jumpTo(options); +} + +void NativeMapView::easeTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding, jni::jboolean easing) { + mbgl::CameraOptions cameraOptions; + if (bearing != -1) { + cameraOptions.bearing = bearing; + } + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + cameraOptions.pitch = pitch; + } + if (zoom != -1) { + cameraOptions.zoom = zoom; + } + + mbgl::AnimationOptions animationOptions; + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + if (!easing) { + // add a linear interpolator instead of easing + animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 }); + } + + map->easeTo(cameraOptions, animationOptions); +} + +void NativeMapView::flyTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array& padding) { + mbgl::CameraOptions cameraOptions; + if (bearing != -1) { + cameraOptions.bearing = bearing; + } + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + if (pitch != -1) { + cameraOptions.pitch = pitch; + } + if (zoom != -1) { + cameraOptions.zoom = zoom; + } + + mbgl::AnimationOptions animationOptions; + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + map->flyTo(cameraOptions, animationOptions); +} + +jni::Local> NativeMapView::getLatLng(JNIEnv& env) { + return LatLng::New(env, *map->getCameraOptions(mbgl::nullopt).center); +} + +void NativeMapView::setLatLng(jni::JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude, const jni::Array& padding, jni::jlong duration) { + mbgl::CameraOptions cameraOptions; + cameraOptions.center = mbgl::LatLng(latitude, longitude); + if (padding) { + assert(padding.Length(env) == 4); + cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1), + padding.Get(env, 2), padding.Get(env, 3)}; + } + map->easeTo(cameraOptions, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +jni::Local> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, const jni::Object& jBounds, double top, double left, double bottom, double right, double bearing, double tilt) { + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt), pixelRatio); +} + +jni::Local> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, const jni::Object& jGeometry, double top, double left, double bottom, double right, double bearing, double tilt) { + auto geometry = geojson::Geometry::convert(env, jGeometry); + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt), pixelRatio); +} + +void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) { + if (reachable) { + mbgl::NetworkStatus::Reachable(); + } +} + +void NativeMapView::resetPosition(jni::JNIEnv&) { + map->jumpTo(mbgl::CameraOptions().withCenter(mbgl::LatLng {}).withZoom(0.0).withBearing(0.0).withPitch(0.0)); +} + +jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) { + return *map->getCameraOptions().pitch; +} + +void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withPitch(pitch), + mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); +} + +void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jdouble x, jni::jdouble y, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate{ x, y }), + mbgl::AnimationOptions{ mbgl::Milliseconds(duration) }); +} + +jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) { + return *map->getCameraOptions().zoom; +} + +void NativeMapView::resetZoom(jni::JNIEnv&) { + map->jumpTo(mbgl::CameraOptions().withZoom(0.0)); +} + +void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setBounds(BoundOptions().withMinZoom(zoom)); +} + +jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) { + return *map->getBounds().minZoom; +} + +void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setBounds(BoundOptions().withMaxZoom(zoom)); +} + +jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) { + return *map->getBounds().maxZoom; +} + +void NativeMapView::setMinPitch(jni::JNIEnv&, jni::jdouble pitch) { + map->setBounds(BoundOptions().withMinPitch(pitch)); +} + +jni::jdouble NativeMapView::getMinPitch(jni::JNIEnv&) { + return *map->getBounds().minPitch; +} + +void NativeMapView::setMaxPitch(jni::JNIEnv&, jni::jdouble pitch) { + map->setBounds(BoundOptions().withMaxPitch(pitch)); +} + +jni::jdouble NativeMapView::getMaxPitch(jni::JNIEnv&) { + return *map->getBounds().maxPitch; +} + +void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) { + mbgl::ScreenCoordinate first(sx, sy); + mbgl::ScreenCoordinate second(ex, ey); + map->rotateBy(first, second, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) { + map->easeTo(mbgl::CameraOptions().withBearing(degrees), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) { + mbgl::ScreenCoordinate anchor(cx, cy); + map->easeTo(mbgl::CameraOptions().withBearing(degrees).withAnchor(anchor), mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); +} + +jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) { + return *map->getCameraOptions().bearing; +} + +void NativeMapView::resetNorth(jni::JNIEnv&) { + map->easeTo(mbgl::CameraOptions().withBearing(0.0), mbgl::AnimationOptions {{mbgl::Milliseconds(500)}}); +} + +void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, const jni::Array>& coordinates, const jni::Object& padding, jdouble direction, jni::jlong duration) { + NullCheck(env, &coordinates); + std::size_t count = coordinates.Length(env); + + std::vector latLngs; + latLngs.reserve(count); + + for (std::size_t i = 0; i < count; i++) { + latLngs.push_back(LatLng::getLatLng(env, coordinates.Get(env, i))); + } + + mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) }; + mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets); + if (direction >= 0) { + cameraOptions.bearing = direction; + } + + mbgl::AnimationOptions animationOptions; + if (duration > 0) { + animationOptions.duration.emplace(mbgl::Milliseconds(duration)); + // equivalent to kCAMediaTimingFunctionDefault in iOS + animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 }); + } + + map->easeTo(cameraOptions, animationOptions); +} + +void NativeMapView::getVisibleCoordinateBounds(JNIEnv& env, jni::Array& output) { + auto latlngBounds = map->latLngBoundsForCameraUnwrapped(map->getCameraOptions(mbgl::nullopt)); + + double latNorth = latlngBounds.north(); + double lonEast = latlngBounds.east(); + double latSouth = latlngBounds.south(); + double lonWest = latlngBounds.west(); + + std::vector buffer; + buffer.reserve(4); + + // Order of the LatLngBounds: double latNorth, double lonEast, double latSouth, double lonWest + buffer.push_back(latNorth); + buffer.push_back(lonEast); + buffer.push_back(latSouth); + buffer.push_back(lonWest); + + output.SetRegion>(env, 0, buffer); +} + +void NativeMapView::scheduleSnapshot(jni::JNIEnv&) { + mapRenderer.requestSnapshot([&](PremultipliedImage image) { + auto _env = android::AttachEnv(); + // Convert image to bitmap + auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image)); + + // invoke Mapview#OnSnapshotReady + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotReady, bitmap); + } + }); +} + +jni::Local> NativeMapView::getCameraPosition(jni::JNIEnv& env) { + return CameraPosition::New(env, map->getCameraOptions(mbgl::nullopt), pixelRatio); +} + +void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, const jni::String& jid) { + if (markerId == -1) { + return; + } + + std::string iconId = jni::Make(env, jid); + // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. + map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point(lon, lat), iconId }); +} + +jni::Local> NativeMapView::addMarkers(jni::JNIEnv& env, const jni::Array>& jmarkers) { + jni::NullCheck(env, &jmarkers); + std::size_t len = jmarkers.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + auto marker = jmarkers.Get(env, i); + ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation { + Marker::getPosition(env, marker), + Marker::getIconId(env, marker) + })); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +void NativeMapView::onLowMemory(JNIEnv&) { + rendererFrontend->reduceMemoryUse(); +} + +using DebugOptions = mbgl::MapDebugOptions; + +void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) { + DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision + : DebugOptions::NoDebug; + map->setDebug(debugOptions); +} + +jni::jboolean NativeMapView::getDebug(JNIEnv&) { + return map->getDebug() != DebugOptions::NoDebug; +} + +jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) { + return map->isFullyLoaded(); +} + +jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) { + return mbgl::Projection::getMetersPerPixelAtLatitude(lat, zoom); +} + +jni::Local> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) { + mbgl::ProjectedMeters projectedMeters = mbgl::Projection::projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); + return ProjectedMeters::New(env, projectedMeters.northing(), projectedMeters.easting()); +} + +jni::Local> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) { + return LatLng::New(env, mbgl::Projection::latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting))); +} + +jni::Local> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) { + mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude)); + return PointF::New(env, static_cast(pixel.x), static_cast(pixel.y)); +} + +void NativeMapView::pixelsForLatLngs(JNIEnv& env, + const jni::Array& input, + jni::Array& output, + jfloat pixelRatio_) { + jni::NullCheck(env, &input); + std::size_t len = input.Length(env); + + std::vector latLngs; + latLngs.reserve(len); + + for (std::size_t i = 0; i < len; i += 2) { + auto latLng = mbgl::LatLng(input.Get(env, i), input.Get(env, i + 1)); + latLngs.push_back(latLng); + } + + std::vector buffer; + buffer.reserve(len); + std::vector coordinates = map->pixelsForLatLngs(latLngs); + for (std::size_t i = 0; i < len / 2; i++) { + buffer.push_back(coordinates[i].x * pixelRatio_); + buffer.push_back(coordinates[i].y * pixelRatio_); + } + + output.SetRegion>(env, 0, buffer); +} + +jni::Local> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) { + return LatLng::New(env, map->latLngForPixel(mbgl::ScreenCoordinate(x, y))); +} + +void NativeMapView::latLngsForPixels(JNIEnv& env, + const jni::Array& input, + jni::Array& output, + jfloat pixelRatio_) { + jni::NullCheck(env, &input); + std::size_t len = input.Length(env); + + std::vector coordinates; + coordinates.reserve(len); + + for (std::size_t i = 0; i < len; i += 2) { + auto coordinate = mbgl::ScreenCoordinate(input.Get(env, i) / pixelRatio_, input.Get(env, i + 1) / pixelRatio_); + coordinates.push_back(coordinate); + } + + std::vector buffer; + buffer.reserve(len); + std::vector latLngs = map->latLngsForPixels(coordinates); + for (std::size_t i = 0; i < len / 2; i++) { + buffer.push_back(latLngs[i].latitude()); + buffer.push_back(latLngs[i].longitude()); + } + + output.SetRegion>(env, 0, buffer); +} + +jni::Local> NativeMapView::addPolylines(JNIEnv& env, const jni::Array>& polylines) { + NullCheck(env, &polylines); + std::size_t len = polylines.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polylines.Get(env, i)); + ids.push_back(map->addAnnotation(annotation)); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + + +jni::Local> NativeMapView::addPolygons(JNIEnv& env, const jni::Array>& polygons) { + NullCheck(env, &polygons); + std::size_t len = polygons.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygons.Get(env, i)); + ids.push_back(map->addAnnotation(annotation)); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, const jni::Object& polyline) { + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline); + map->updateAnnotation(polylineId, annotation); +} + +void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, const jni::Object& polygon) { + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon); + map->updateAnnotation(polygonId, annotation); +} + +void NativeMapView::removeAnnotations(JNIEnv& env, const jni::Array& ids) { + NullCheck(env, &ids); + std::size_t len = ids.Length(env); + auto elements = jni::GetArrayElements(env, *ids); + jlong* jids = std::get<0>(elements).get(); + + for (std::size_t i = 0; i < len; i++) { + if(jids[i] == -1L) { + continue; + } + map->removeAnnotation(jids[i]); + } +} + +void NativeMapView::addAnnotationIcon(JNIEnv& env, const jni::String& symbol, jint w, jint h, jfloat scale, const jni::Array& jpixels) { + const std::string symbolName = jni::Make(env, symbol); + + NullCheck(env, &jpixels); + std::size_t size = jpixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(w), static_cast(h) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::StyleImageException("Annotation icon image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + map->addAnnotationImage(std::make_unique( + symbolName, std::move(premultipliedImage), float(scale))); +} + +void NativeMapView::removeAnnotationIcon(JNIEnv& env, const jni::String& symbol) { + const std::string symbolName = jni::Make(env, symbol); + map->removeAnnotationImage(symbolName); +} + +jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, const jni::String& symbolName) { + return map->getTopOffsetPixelsForAnnotationImage(jni::Make(env, symbolName)); +} + +jni::Local> NativeMapView::getTransitionOptions(JNIEnv& env) { + const auto transitionOptions = map->getStyle().getTransitionOptions(); + const auto duration = std::chrono::duration_cast(transitionOptions.duration.value_or(mbgl::Duration::zero())).count(); + const auto delay = std::chrono::duration_cast(transitionOptions.delay.value_or(mbgl::Duration::zero())).count(); + const auto enablePlacementTransitions = (jboolean) transitionOptions.enablePlacementTransitions; + return TransitionOptions::fromTransitionOptions(env, duration, delay, enablePlacementTransitions); +} + +void NativeMapView::setTransitionOptions(JNIEnv& env, const jni::Object& options) { + const mbgl::style::TransitionOptions transitionOptions( + Duration(mbgl::Milliseconds(TransitionOptions::getDuration(env, options))), + Duration(mbgl::Milliseconds(TransitionOptions::getDelay(env, options))), + TransitionOptions::isEnablePlacementTransitions(env, options) + ); + map->getStyle().setTransitionOptions(transitionOptions); +} + +jni::Local> NativeMapView::queryPointAnnotations(JNIEnv& env, const jni::Object& rect) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + // Convert input + mbgl::ScreenBox box = { + { RectF::getLeft(env, rect), RectF::getTop(env, rect) }, + { RectF::getRight(env, rect), RectF::getBottom(env, rect) }, + }; + + // Assume only points for now + mbgl::AnnotationIDs ids = rendererFrontend->queryPointAnnotations(box); + + // Convert result + std::vector longIds(ids.begin(), ids.end()); + auto result = jni::Array::New(env, ids.size()); + result.SetRegion>(env, 0, longIds); + + return result; +} + +jni::Local> NativeMapView::queryShapeAnnotations(JNIEnv& env, const jni::Object& rect) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + // Convert input + mbgl::ScreenBox box = { + {RectF::getLeft(env, rect), RectF::getTop(env, rect)}, + {RectF::getRight(env, rect), RectF::getBottom(env, rect)}, + }; + + mbgl::AnnotationIDs ids = rendererFrontend->queryShapeAnnotations(box); + + // Convert result + std::vector longIds(ids.begin(), ids.end()); + auto result = jni::Array::New(env, ids.size()); + result.SetRegion>(env, 0, longIds); + + return result; +} + +jni::Local>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, + const jni::Array& layerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + mbgl::optional> layers; + if (layerIds && layerIds.Length(env) > 0) { + layers = android::conversion::toVector(env, layerIds); + } + mapbox::geometry::point point = {x, y}; + + return Feature::convert( + env, + rendererFrontend->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) })); +} + +jni::Local>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, + jni::jfloat right, jni::jfloat bottom, const jni::Array& layerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + mbgl::optional> layers; + if (layerIds && layerIds.Length(env) > 0) { + layers = toVector(env, layerIds); + } + mapbox::geometry::box box = { + mapbox::geometry::point{ left, top}, + mapbox::geometry::point{ right, bottom } + }; + + return Feature::convert( + env, + rendererFrontend->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) })); +} + +jni::Local> NativeMapView::getLight(JNIEnv& env) { + mbgl::style::Light* light = map->getStyle().getLight(); + if (light) { + return Light::createJavaLightPeer(env, *map, *light); + } else { + return jni::Local>(); + } +} + +jni::Local>> NativeMapView::getLayers(JNIEnv& env) { + + // Get the core layers + std::vector layers = map->getStyle().getLayers(); + + // Convert + auto jLayers = jni::Array>::New(env, layers.size()); + int index = 0; + for (auto layer : layers) { + jLayers.Set(env, index, LayerManagerAndroid::get()->createJavaLayerPeer(env, *layer)); + index++; + } + + return jLayers; +} + +jni::Local> NativeMapView::getLayer(JNIEnv& env, const jni::String& layerId) { + + // Find the layer + mbgl::style::Layer* coreLayer = map->getStyle().getLayer(jni::Make(env, layerId)); + if (!coreLayer) { + mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); + return jni::Local>(); + } + + // Create and return the layer's native peer + return LayerManagerAndroid::get()->createJavaLayerPeer(env, *coreLayer); +} + +void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, const jni::String& before) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + try { + layer->addToStyle( + map->getStyle(), + before ? mbgl::optional(jni::Make(env, before)) : mbgl::optional()); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, const jni::String& above) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + + // Find the sibling + auto layers = map->getStyle().getLayers(); + auto siblingId = jni::Make(env, above); + + size_t index = 0; + for (auto l : layers) { + if (l->getID() == siblingId) { + break; + } + index++; + } + + // Check if we found a sibling to place before + mbgl::optional before; + if (index + 1 > layers.size()) { + // Not found + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Could not find layer: ").append(siblingId).c_str()); + return; + } else if (index + 1 < layers.size()) { + // Place before the sibling + before = { layers.at(index + 1)->getID() }; + } + + // Add the layer + try { + layer->addToStyle(map->getStyle(), before); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + auto layers = map->getStyle().getLayers(); + + // Check index + int numLayers = layers.size() - 1; + if (index > numLayers || index < 0) { + Log::Error(Event::JNI, "Index out of range: %i", index); + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Invalid index").c_str()); + return; + } + + // Insert it below the current at that index + try { + layer->addToStyle(map->getStyle(), layers.at(index)->getID()); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + + +/** + * Remove layer at index. + */ +jni::jboolean NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) { + auto layers = map->getStyle().getLayers(); + + // Check index + int numLayers = layers.size() - 1; + if (index > numLayers || index < 0) { + Log::Warning(Event::JNI, "Index out of range: %i", index); + return jni::jni_false; + } + + std::unique_ptr coreLayer = map->getStyle().removeLayer(layers.at(index)->getID()); + if (coreLayer) { + jni::Local> layerObj = + LayerManagerAndroid::get()->createJavaLayerPeer(env, std::move(coreLayer)); + return jni::jni_true; + } + return jni::jni_false; +} + +/** + * Remove with wrapper object id. Ownership is transferred back to the wrapper + */ +jni::jboolean NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) { + assert(layerPtr != 0); + + mbgl::android::Layer *layer = reinterpret_cast(layerPtr); + std::unique_ptr coreLayer = map->getStyle().removeLayer(layer->get().getID()); + if (coreLayer) { + layer->setLayer(std::move(coreLayer)); + return jni::jni_true; + } + return jni::jni_false; +} + +jni::Local>> NativeMapView::getSources(JNIEnv& env) { + // Get the core sources + std::vector sources = map->getStyle().getSources(); + + // Convert + auto jSources = jni::Array>::New(env, sources.size()); + int index = 0; + for (auto source : sources) { + jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend)); + index++; + } + + return jSources; +} + +jni::Local> NativeMapView::getSource(JNIEnv& env, const jni::String& sourceId) { + // Find the source + mbgl::style::Source* coreSource = map->getStyle().getSource(jni::Make(env, sourceId)); + if (!coreSource) { + mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); + return jni::Local>(); + } + + // Create and return the source's native peer + return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend)); +} + +void NativeMapView::addSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { + assert(sourcePtr != 0); + + Source *source = reinterpret_cast(sourcePtr); + try { + source->addToMap(env, obj, *map, *rendererFrontend); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); + } +} + +jni::jboolean NativeMapView::removeSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { + assert(sourcePtr != 0); + + mbgl::android::Source *source = reinterpret_cast(sourcePtr); + if (source->removeFromMap(env, obj, *map)) { + source->releaseJavaPeer(); + return jni::jni_true; + } + + return jni::jni_false; +} + +void NativeMapView::addImage(JNIEnv& env, const jni::String& name, const jni::Object& bitmap, jni::jfloat scale, jni::jboolean sdf) { + jni::NullCheck(env, &bitmap); + mbgl::PremultipliedImage premultipliedImage = Bitmap::GetImage(env, bitmap); + + map->getStyle().addImage(std::make_unique( + jni::Make(env, name), + std::move(premultipliedImage), + float(scale), + sdf) + ); +} + +void NativeMapView::addImages(JNIEnv& env, const jni::Array>& jimages) { + jni::NullCheck(env, &jimages); + std::size_t len = jimages.Length(env); + + for (std::size_t i = 0; i < len; i++) { + auto image = mbgl::android::Image::getImage(env, jimages.Get(env, i)); + map->getStyle().addImage(std::make_unique(image)); + } +} + +void NativeMapView::removeImage(JNIEnv& env, const jni::String& name) { + map->getStyle().removeImage(jni::Make(env, name)); +} + +jni::Local> NativeMapView::getImage(JNIEnv& env, const jni::String& name) { + if (auto image = map->getStyle().getImage(jni::Make(env, name))) { + return Bitmap::CreateBitmap(env, image->getImage()); + } + return jni::Local>(); +} + +void NativeMapView::setPrefetchTiles(JNIEnv&, jni::jboolean enable) { + map->setPrefetchZoomDelta(enable ? util::DEFAULT_PREFETCH_ZOOM_DELTA : uint8_t(0)); +} + +jni::jboolean NativeMapView::getPrefetchTiles(JNIEnv&) { + return jni::jboolean(map->getPrefetchZoomDelta() > 0); +} + +void NativeMapView::setPrefetchZoomDelta(JNIEnv&, jni::jint delta) { + map->setPrefetchZoomDelta(uint8_t(delta)); +} + +jni::jint NativeMapView::getPrefetchZoomDelta(JNIEnv&) { + return jni::jint(map->getPrefetchZoomDelta()); +} + +mbgl::Map& NativeMapView::getMap() { + return *map; +} + +void NativeMapView::triggerRepaint(JNIEnv&) { + assert(map); + map->triggerRepaint(); +} + +// Static methods // + +void NativeMapView::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer&, + const jni::Object&, + const jni::Object&, + jni::jfloat, + jni::jboolean>, + "nativeInitialize", + "nativeDestroy", + METHOD(&NativeMapView::resizeView, "nativeResizeView"), + METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), + METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), + METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), + METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), + METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), + METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), + METHOD(&NativeMapView::moveBy, "nativeMoveBy"), + METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), + METHOD(&NativeMapView::easeTo, "nativeEaseTo"), + METHOD(&NativeMapView::flyTo, "nativeFlyTo"), + METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), + METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), + METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), + METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), + METHOD(&NativeMapView::setReachability, "nativeSetReachability"), + METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), + METHOD(&NativeMapView::getPitch, "nativeGetPitch"), + METHOD(&NativeMapView::setPitch, "nativeSetPitch"), + METHOD(&NativeMapView::getZoom, "nativeGetZoom"), + METHOD(&NativeMapView::setZoom, "nativeSetZoom"), + METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), + METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), + METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), + METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&NativeMapView::setMinPitch, "nativeSetMinPitch"), + METHOD(&NativeMapView::getMinPitch, "nativeGetMinPitch"), + METHOD(&NativeMapView::setMaxPitch, "nativeSetMaxPitch"), + METHOD(&NativeMapView::getMaxPitch, "nativeGetMaxPitch"), + METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), + METHOD(&NativeMapView::setBearing, "nativeSetBearing"), + METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), + METHOD(&NativeMapView::getBearing, "nativeGetBearing"), + METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), + METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), + METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), + METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), + METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), + METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), + METHOD(&NativeMapView::setDebug, "nativeSetDebug"), + METHOD(&NativeMapView::getDebug, "nativeGetDebug"), + METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), + METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), + METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), + METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), + METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), + METHOD(&NativeMapView::pixelsForLatLngs, "nativePixelsForLatLngs"), + METHOD(&NativeMapView::getVisibleCoordinateBounds, "nativeGetVisibleCoordinateBounds"), + METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), + METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), + METHOD(&NativeMapView::latLngsForPixels, "nativeLatLngsForPixels"), + METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), + METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), + METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), + METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), + METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), + METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), + METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), + METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), + METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), + METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), + METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), + METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), + METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), + METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), + METHOD(&NativeMapView::getLight, "nativeGetLight"), + METHOD(&NativeMapView::getLayers, "nativeGetLayers"), + METHOD(&NativeMapView::getLayer, "nativeGetLayer"), + METHOD(&NativeMapView::addLayer, "nativeAddLayer"), + METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), + METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), + METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), + METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), + METHOD(&NativeMapView::getSources, "nativeGetSources"), + METHOD(&NativeMapView::getSource, "nativeGetSource"), + METHOD(&NativeMapView::addSource, "nativeAddSource"), + METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), + METHOD(&NativeMapView::addImage, "nativeAddImage"), + METHOD(&NativeMapView::addImages, "nativeAddImages"), + METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), + METHOD(&NativeMapView::getImage, "nativeGetImage"), + METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), + METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), + METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles"), + METHOD(&NativeMapView::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), + METHOD(&NativeMapView::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta"), + METHOD(&NativeMapView::triggerRepaint, "nativeTriggerRepaint")); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/native_map_view.hpp b/MapboxGLAndroidSDK/src/cpp/native_map_view.hpp new file mode 100644 index 000000000..be632e242 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/native_map_view.hpp @@ -0,0 +1,279 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "graphics/pointf.hpp" +#include "graphics/rectf.hpp" +#include "geojson/feature.hpp" +#include "geojson/geometry.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/projected_meters.hpp" +#include "style/layers/layer_manager.hpp" +#include "style/sources/source.hpp" +#include "geometry/lat_lng_bounds.hpp" +#include "map/camera_position.hpp" +#include "map/image.hpp" +#include "style/light.hpp" +#include "bitmap.hpp" + +#include +#include +#include +#include +#include +#include + +namespace mbgl { +namespace android { + +class AndroidRendererFrontend; +class FileSource; +class MapRenderer; + +class NativeMapView : public MapObserver { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; }; + + static void registerNative(jni::JNIEnv&); + + NativeMapView(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + const jni::Object&, + jni::jfloat, + jni::jboolean); + + virtual ~NativeMapView(); + + // mbgl::RendererBackend (mbgl::MapObserver) // + void onCameraWillChange(MapObserver::CameraChangeMode) override; + void onCameraIsChanging() override; + void onCameraDidChange(MapObserver::CameraChangeMode) override; + void onWillStartLoadingMap() override; + void onDidFinishLoadingMap() override; + void onDidFailLoadingMap(MapLoadError, const std::string&) override; + void onWillStartRenderingFrame() override; + void onDidFinishRenderingFrame(MapObserver::RenderFrameStatus) override; + void onWillStartRenderingMap() override; + void onDidFinishRenderingMap(MapObserver::RenderMode) override; + void onDidBecomeIdle() override; + void onDidFinishLoadingStyle() override; + void onSourceChanged(mbgl::style::Source&) override; + void onStyleImageMissing(const std::string&) override; + bool onCanRemoveUnusedStyleImage(const std::string&) override; + + // JNI // + + void resizeView(jni::JNIEnv&, int, int); + + jni::Local getStyleUrl(jni::JNIEnv&); + + void setStyleUrl(jni::JNIEnv&, const jni::String&); + + jni::Local getStyleJson(jni::JNIEnv&); + + void setStyleJson(jni::JNIEnv&, const jni::String&); + + void setLatLngBounds(jni::JNIEnv&, const jni::Object&); + + void cancelTransitions(jni::JNIEnv&); + + void setGestureInProgress(jni::JNIEnv&, jni::jboolean); + + void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong); + + void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, const jni::Array&); + + void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&, jni::jboolean); + + void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array&); + + jni::Local> getLatLng(JNIEnv&); + + void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, const jni::Array&, jni::jlong); + + jni::Local> getCameraForLatLngBounds(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); + + jni::Local> getCameraForGeometry(jni::JNIEnv&, const jni::Object&, double top, double left, double bottom, double right, double bearing, double tilt); + + void setReachability(jni::JNIEnv&, jni::jboolean); + + void resetPosition(jni::JNIEnv&); + + jni::jdouble getPitch(jni::JNIEnv&); + + void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong); + + void setZoom(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + jni::jdouble getZoom(jni::JNIEnv&); + + void resetZoom(jni::JNIEnv&); + + void setMinZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMinZoom(jni::JNIEnv&); + + void setMaxZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMaxZoom(jni::JNIEnv&); + + void setMinPitch(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMinPitch(jni::JNIEnv&); + + void setMaxPitch(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMaxPitch(jni::JNIEnv&); + + void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong); + + void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong); + + jni::jdouble getBearing(jni::JNIEnv&); + + void resetNorth(jni::JNIEnv&); + + void setVisibleCoordinateBounds(JNIEnv&, const jni::Array>&, const jni::Object&, jni::jdouble, jni::jlong); + + void getVisibleCoordinateBounds(JNIEnv& env, jni::Array& output); + + void scheduleSnapshot(jni::JNIEnv&); + + jni::Local> getCameraPosition(jni::JNIEnv&); + + void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, const jni::String&); + + jni::Local> addMarkers(jni::JNIEnv&, const jni::Array>&); + + void onLowMemory(JNIEnv& env); + + void setDebug(JNIEnv&, jni::jboolean); + + jni::jboolean getDebug(JNIEnv&); + + jni::jboolean isFullyLoaded(JNIEnv&); + + jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Local> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Local> pixelForLatLng(JNIEnv&, jdouble, jdouble); + + void pixelsForLatLngs(JNIEnv&, const jni::Array&, jni::Array&, jfloat); + + jni::Local> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble); + + jni::Local> latLngForPixel(JNIEnv&, jfloat, jfloat); + + void latLngsForPixels(JNIEnv&, const jni::Array&, jni::Array&, jfloat); + + jni::Local> addPolylines(JNIEnv&, const jni::Array>&); + + jni::Local> addPolygons(JNIEnv&, const jni::Array>&); + + void updatePolyline(JNIEnv&, jlong, const jni::Object&); + + void updatePolygon(JNIEnv&, jlong, const jni::Object&); + + void removeAnnotations(JNIEnv&, const jni::Array&); + + void addAnnotationIcon(JNIEnv&, const jni::String&, jint, jint, jfloat, const jni::Array&); + + void removeAnnotationIcon(JNIEnv&, const jni::String&); + + jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, const jni::String&); + + jni::Local> getTransitionOptions(JNIEnv&); + + void setTransitionOptions(JNIEnv&, const jni::Object&); + + jni::Local> queryPointAnnotations(JNIEnv&, const jni::Object&); + + jni::Local> queryShapeAnnotations(JNIEnv&, const jni::Object&); + + jni::Local>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, + const jni::Array&, + const jni::Array>& jfilter); + + jni::Local>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, + jni::jfloat, const jni::Array&, + const jni::Array>& jfilter); + + jni::Local> getLight(JNIEnv&); + + jni::Local>> getLayers(JNIEnv&); + + jni::Local> getLayer(JNIEnv&, const jni::String&); + + void addLayer(JNIEnv&, jlong, const jni::String&); + + void addLayerAbove(JNIEnv&, jlong, const jni::String&); + + void addLayerAt(JNIEnv&, jni::jlong, jni::jint); + + jni::jboolean removeLayerAt(JNIEnv&, jni::jint); + + jni::jboolean removeLayer(JNIEnv&, jlong); + + jni::Local>> getSources(JNIEnv&); + + jni::Local> getSource(JNIEnv&, const jni::String&); + + void addSource(JNIEnv&, const jni::Object&, jlong nativePtr); + + jni::jboolean removeSource(JNIEnv&, const jni::Object&, jlong nativePtr); + + void addImage(JNIEnv&, const jni::String&, const jni::Object& bitmap, jni::jfloat, jni::jboolean); + + void addImages(JNIEnv&, const jni::Array>&); + + void removeImage(JNIEnv&, const jni::String&); + + jni::Local> getImage(JNIEnv&, const jni::String&); + + void setPrefetchTiles(JNIEnv&, jni::jboolean); + + jni::jboolean getPrefetchTiles(JNIEnv&); + + void setPrefetchZoomDelta(JNIEnv&, jni::jint); + + jni::jint getPrefetchZoomDelta(JNIEnv&); + + mbgl::Map& getMap(); + + void triggerRepaint(JNIEnv&); + +private: + std::unique_ptr rendererFrontend; + + JavaVM *vm = nullptr; + jni::WeakReference> javaPeer; + + MapRenderer& mapRenderer; + + std::string styleUrl; + + float pixelRatio; + + // Minimum texture size according to OpenGL ES 2.0 specification. + int width = 64; + int height = 64; + + // Ensure these are initialised last + std::unique_ptr map; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.cpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.cpp new file mode 100644 index 000000000..74176b0e4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.cpp @@ -0,0 +1,335 @@ +#include "offline_manager.hpp" + +#include +#include +#include + +#include "attach_env.hpp" + +namespace mbgl { +namespace android { + +namespace { +// Reattach, the callback comes from a different thread +void handleException(std::exception_ptr exception, + const jni::Object& callback, + android::UniqueEnv env = android::AttachEnv()) { + if (exception) { + OfflineManager::FileSourceCallback::onError( + *env, callback, jni::Make(*env, mbgl::util::toString(exception))); + } else { + OfflineManager::FileSourceCallback::onSuccess(*env, callback); + } +} +} // namespace + +// OfflineManager // +OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object& jFileSource) + : fileSource(std::static_pointer_cast( + std::shared_ptr(mbgl::FileSourceManager::get()->getFileSource( + mbgl::FileSourceType::Database, FileSource::getSharedResourceOptions(env, jFileSource))))) { + if (!fileSource) { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Offline functionality is disabled."); + } +} + +OfflineManager::~OfflineManager() {} + +void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { + fileSource->setOfflineMapboxTileCountLimit(limit); +} + +void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + fileSource->listOfflineRegions([ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected regions) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (regions) { + OfflineManager::ListOfflineRegionsCallback::onList( + *env, *jFileSource, *callback, *regions); + } else { + OfflineManager::ListOfflineRegionsCallback::onError( + *env, *callback, regions.error()); + } + }); +} + +void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, + const jni::Object& jFileSource_, + const jni::Object& definition_, + const jni::Array& metadata_, + const jni::Object& callback_) { + // Convert + auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); + + mbgl::OfflineRegionMetadata metadata; + if (metadata_) { + metadata = OfflineRegion::metadata(env_, metadata_); + } + + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + // Create region + fileSource->createOfflineRegion(definition, metadata, [ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected region) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (region) { + OfflineManager::CreateOfflineRegionCallback::onCreate( + *env, *jFileSource, *callback, *region + ); + } else { + OfflineManager::CreateOfflineRegionCallback::onError( + *env, *callback, region.error()); + } + }); +} + +void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, + const jni::String& jString_, + const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + auto globalFilesource = jni::NewGlobal(env_, jFileSource_); + + auto path = jni::Make(env_, jString_); + fileSource->mergeOfflineRegions(path, [ + //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)), + jFileSource = std::make_shared(std::move(globalFilesource)) + ](mbgl::expected regions) mutable { + + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (regions) { + OfflineManager::MergeOfflineRegionsCallback::onMerge( + *env, *jFileSource, *callback, *regions); + } else { + OfflineManager::MergeOfflineRegionsCallback::onError( + *env, *callback, regions.error()); + } + }); +} + +void OfflineManager::resetDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->resetDatabase( + [ + // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback))]( + std::exception_ptr exception) mutable { handleException(exception, *callback); }); +} + +void OfflineManager::packDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->packDatabase( + [ + // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback))]( + std::exception_ptr exception) mutable { handleException(exception, *callback); }); +} + +void OfflineManager::invalidateAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->invalidateAmbientCache( + [ + // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback))]( + std::exception_ptr exception) mutable { handleException(exception, *callback); }); +} + +void OfflineManager::clearAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->clearAmbientCache( + [ + // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback))]( + std::exception_ptr exception) mutable { handleException(exception, *callback); }); +} + +void OfflineManager::setMaximumAmbientCacheSize(jni::JNIEnv& env_, const jni::jlong size_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->setMaximumAmbientCacheSize( + size_, + [ + // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile + callback = std::make_shared(std::move(globalCallback))]( + std::exception_ptr exception) mutable { handleException(exception, *callback); }); +} + +void OfflineManager::runPackDatabaseAutomatically(jni::JNIEnv&, jboolean autopack) { + fileSource->runPackDatabaseAutomatically(autopack); +} + +// FileSource::FileSourceCallback // + +void OfflineManager::FileSourceCallback::onSuccess(jni::JNIEnv& env, + const jni::Object& callback) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onSuccess"); + callback.Call(env, method); +} + +void OfflineManager::FileSourceCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + const jni::String& message) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + callback.Call(env, method, message); +} + +void OfflineManager::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"), + METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"), + METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"), + METHOD(&OfflineManager::mergeOfflineRegions, "mergeOfflineRegions"), + METHOD(&OfflineManager::resetDatabase, "nativeResetDatabase"), + METHOD(&OfflineManager::packDatabase, "nativePackDatabase"), + METHOD(&OfflineManager::invalidateAmbientCache, "nativeInvalidateAmbientCache"), + METHOD(&OfflineManager::clearAmbientCache, "nativeClearAmbientCache"), + METHOD(&OfflineManager::setMaximumAmbientCacheSize, "nativeSetMaximumAmbientCacheSize"), + METHOD(&OfflineManager::runPackDatabaseAutomatically, "runPackDatabaseAutomatically"), + METHOD(&OfflineManager::putResourceWithUrl, "putResourceWithUrl")); +} + +// OfflineManager::ListOfflineRegionsCallback // + +void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegions& regions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod>)>(env, "onList"); + + std::size_t index = 0; + auto jregions = jni::Array>::New(env, regions.size()); + for (auto& region : regions) { + jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); + index++; + } + + callback.Call(env, method, jregions); +} + +// OfflineManager::CreateOfflineRegionCallback // + +void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegion& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onCreate"); + + callback.Call(env, method, OfflineRegion::New(env, jFileSource, std::move(region))); +} + +// OfflineManager::MergeOfflineRegionsCallback // + +void OfflineManager::MergeOfflineRegionsCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineManager::MergeOfflineRegionsCallback::onMerge(jni::JNIEnv& env, + const jni::Object& jFileSource, + const jni::Object& callback, + mbgl::OfflineRegions& regions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod>)>(env, "onMerge"); + + std::size_t index = 0; + auto jregions = jni::Array>::New(env, regions.size()); + for (auto& region : regions) { + jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); + index++; + } + + callback.Call(env, method, jregions); +} + +void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, + const jni::String& url_, + const jni::Array& arr, + jlong modified, + jlong expires, + const jni::String& eTag_, + jboolean mustRevalidate) { + auto url = jni::Make(env, url_); + auto data = std::make_shared(arr.Length(env), char()); + jni::GetArrayRegion(env, *arr, 0, data->size(), reinterpret_cast(&(*data)[0])); + mbgl::Resource resource(mbgl::Resource::Kind::Unknown, url); + mbgl::Response response; + response.data = data; + response.mustRevalidate = mustRevalidate; + if (eTag_) { + response.etag = jni::Make(env, eTag_); + } + if (modified > 0) { + response.modified = Timestamp(mbgl::Seconds(modified)); + } + if (expires > 0) { + response.expires = Timestamp(mbgl::Seconds(expires)); + } + + fileSource->put(resource, response); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.hpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.hpp new file mode 100644 index 000000000..84111a742 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_manager.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include + +#include "../file_source.hpp" +#include "offline_region.hpp" +#include "offline_region_definition.hpp" +#include "../java_types.hpp" + +#include + +namespace mbgl { + +namespace android { + +class OfflineManager { +public: + + class ListOfflineRegionsCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";} + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onList(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegions&); + }; + + class CreateOfflineRegionCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; } + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onCreate(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegion&); + }; + + class MergeOfflineRegionsCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$MergeOfflineRegionsCallback";} + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onMerge(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + mbgl::OfflineRegions&); + }; + + struct FileSourceCallback { + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$FileSourceCallback";} + + static void onSuccess(jni::JNIEnv&, const jni::Object&); + + static void onError(jni::JNIEnv&, const jni::Object&, const jni::String&); + }; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }; + + static void registerNative(jni::JNIEnv&); + + OfflineManager(jni::JNIEnv&, const jni::Object&); + ~OfflineManager(); + + void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit); + + void listOfflineRegions(jni::JNIEnv&, const jni::Object&, const jni::Object& callback); + + void createOfflineRegion(jni::JNIEnv&, + const jni::Object& jFileSource_, + const jni::Object& definition, + const jni::Array& metadata, + const jni::Object& callback); + + void mergeOfflineRegions(jni::JNIEnv&, + const jni::Object&, + const jni::String&, + const jni::Object&); + + void putResourceWithUrl(jni::JNIEnv&, + const jni::String& url, + const jni::Array& data, + jlong modified, + jlong expires, + const jni::String& eTag, + jboolean mustRevalidate); + + void resetDatabase(jni::JNIEnv&, const jni::Object& callback_); + + void packDatabase(jni::JNIEnv&, const jni::Object& callback_); + + void invalidateAmbientCache(jni::JNIEnv&, const jni::Object& callback_); + + void clearAmbientCache(jni::JNIEnv&, const jni::Object& callback_); + + void setMaximumAmbientCacheSize(jni::JNIEnv&, const jni::jlong size, const jni::Object& callback_); + + void runPackDatabaseAutomatically(jni::JNIEnv&, jboolean autopack); + +private: + std::shared_ptr fileSource; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region.cpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region.cpp new file mode 100644 index 000000000..75734b5d1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region.cpp @@ -0,0 +1,314 @@ +#include "offline_region.hpp" + +#include +#include +#include + +#include "offline_region_definition.hpp" +#include "offline_region_error.hpp" +#include "offline_region_status.hpp" +#include "attach_env.hpp" + +namespace mbgl { +namespace android { + +// OfflineRegion // + +OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object& jFileSource) + : region(reinterpret_cast(offlineRegionPtr)), + fileSource(std::static_pointer_cast( + std::shared_ptr(mbgl::FileSourceManager::get()->getFileSource( + mbgl::FileSourceType::Database, FileSource::getSharedResourceOptions(env, jFileSource))))) { + if (!fileSource) { + ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Offline functionality is disabled."); + } +} + +OfflineRegion::~OfflineRegion() {} + +void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Object& callback) { + + // Define the observer + class Observer : public mbgl::OfflineRegionObserver { + public: + Observer(jni::Global, jni::EnvAttachingDeleter> callback_) + : callback(std::move(callback_)) { + } + + void statusChanged(mbgl::OfflineRegionStatus status) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod)>(*env, "onStatusChanged"); + + callback.Call(*env, method, OfflineRegionStatus::New(*env, status)); + } + + void responseError(mbgl::Response::Error error) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod)>(*env, "onError"); + + callback.Call(*env, method, OfflineRegionError::New(*env, error)); + } + + void mapboxTileCountLimitExceeded(uint64_t limit) override { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*env); + static auto method = javaClass.GetMethod(*env, "mapboxTileCountLimitExceeded"); + + callback.Call(*env, method, jlong(limit)); + } + + jni::Global, jni::EnvAttachingDeleter> callback; + }; + + // Set the observer + fileSource->setOfflineRegionObserver(*region, std::make_unique(jni::NewGlobal(env_, callback))); +} + +void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) { + // State + mbgl::OfflineRegionDownloadState state; + switch (jState) { + case 0: + state = mbgl::OfflineRegionDownloadState::Inactive; + break; + case 1: + state = mbgl::OfflineRegionDownloadState::Active; + break; + default: + mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active)."); + return; + } + + fileSource->setOfflineRegionDownloadState(*region, state); +} + +void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->getOfflineRegionStatus(*region, [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](mbgl::expected status) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (status) { + OfflineRegionStatusCallback::onStatus(*env, *callback, std::move(*status)); + } else { + OfflineRegionStatusCallback::onError(*env, *callback, status.error()); + } + }); +} + +void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->deleteOfflineRegion(*region, + [ + // Ensure the object is not gc'd in the meanwhile + callback = std::make_shared( + std::move(globalCallback))](std::exception_ptr error) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (error) { + OfflineRegionDeleteCallback::onError(*env, *callback, error); + } else { + OfflineRegionDeleteCallback::onDelete(*env, *callback); + } + }); +} + +void OfflineRegion::invalidateOfflineRegion(jni::JNIEnv& env_, + const jni::Object& callback_) { + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->invalidateOfflineRegion(*region, + [ + // Ensure the object is not gc'd in the meanwhile + callback = std::make_shared( + std::move(globalCallback))](std::exception_ptr error) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (error) { + OfflineRegionInvalidateCallback::onError(*env, *callback, error); + } else { + OfflineRegionInvalidateCallback::onInvalidate(*env, *callback); + } + }); +} + +void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Array& jMetadata, const jni::Object& callback_) { + auto metadata = OfflineRegion::metadata(env_, jMetadata); + auto globalCallback = jni::NewGlobal(env_, callback_); + + fileSource->updateOfflineMetadata(region->getID(), metadata, [ + //Ensure the object is not gc'd in the meanwhile + callback = std::make_shared(std::move(globalCallback)) + ](mbgl::expected data) mutable { + // Reattach, the callback comes from a different thread + android::UniqueEnv env = android::AttachEnv(); + + if (data) { + OfflineRegionUpdateMetadataCallback::onUpdate(*env, *callback, std::move(*data)); + } else { + OfflineRegionUpdateMetadataCallback::onError(*env, *callback, data.error()); + } + }); +} + +jni::Local> OfflineRegion::New(jni::JNIEnv& env, + const jni::Object& jFileSource, + mbgl::OfflineRegion region) { + // Definition + auto definition = region.getDefinition().match( + [&](const mbgl::OfflineTilePyramidRegionDefinition def) { + return OfflineTilePyramidRegionDefinition::New(env, def); + }, + [&](const mbgl::OfflineGeometryRegionDefinition def) { + return OfflineGeometryRegionDefinition::New(env, def); + }); + + // Create region java object + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jlong, jni::Object, jni::Array>(env); + + return javaClass.New(env, constructor, + reinterpret_cast(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap + jFileSource, + jni::jlong(region.getID()), + definition, + OfflineRegion::metadata(env, region.getMetadata())); +} + +jni::Local> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) { + std::vector convertedMetadata(metadata_.begin(), metadata_.end()); + std::size_t length = static_cast(convertedMetadata.size()); + auto metadata = jni::Array::New(env, length); + metadata.SetRegion>(env, 0, convertedMetadata); + return metadata; +} + +mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, const jni::Array& metadata_) { + std::size_t length = metadata_.Length(env); + auto metadata_tmp = std::vector(); + metadata_tmp.resize(length); + metadata_.GetRegion>(env, 0, metadata_tmp); + auto metadata = std::vector(metadata_tmp.begin(), metadata_tmp.end()); + return metadata; +} + +void OfflineRegion::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + jni::Class::Singleton(env); + + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"), + METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"), + METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"), + METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"), + METHOD(&OfflineRegion::invalidateOfflineRegion, "invalidateOfflineRegion"), + METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata")); +} + +// OfflineRegionObserver // + +// OfflineRegionStatusCallback // + +void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env, + const jni::Object& callback, + mbgl::optional status) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onStatus"); + + callback.Call(env, method, OfflineRegionStatus::New(env, std::move(*status))); +} + +// OfflineRegionDeleteCallback // + +void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, const jni::Object& callback) { + // Trigger callback + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onDelete"); + + callback.Call(env, method); +} + +// OfflineRegionUpdateMetadataCallback // + +void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env, + const jni::Object& callback, + mbgl::optional metadata) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod)>(env, "onUpdate"); + + callback.Call(env, method, OfflineRegion::metadata(env, std::move(*metadata))); +} + +// OfflineRegionInvalidateCallback // + +void OfflineRegion::OfflineRegionInvalidateCallback::onError(jni::JNIEnv& env, + const jni::Object& callback, + std::exception_ptr error) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onError"); + callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); +} + +void OfflineRegion::OfflineRegionInvalidateCallback::onInvalidate(jni::JNIEnv& env, const jni::Object& callback) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "onInvalidate"); + callback.Call(env, method); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region.hpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region.hpp new file mode 100644 index 000000000..6844008bb --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include "../file_source.hpp" + +#include + +namespace mbgl { +namespace android { + +class OfflineRegion { +public: + class OfflineRegionObserver { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; }; + }; + + class OfflineRegionStatusCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onStatus(jni::JNIEnv&, + const jni::Object&, + mbgl::optional); + }; + + class OfflineRegionDeleteCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onDelete(jni::JNIEnv&, const jni::Object&); + }; + + class OfflineRegionInvalidateCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionInvalidateCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onInvalidate(jni::JNIEnv&, const jni::Object&); + }; + + class OfflineRegionUpdateMetadataCallback { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; }; + + static void onError(jni::JNIEnv&, const jni::Object&, std::exception_ptr); + + static void onUpdate(jni::JNIEnv&, + const jni::Object&, + mbgl::optional); + }; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }; + + OfflineRegion(jni::JNIEnv&, jni::jlong, const jni::Object&); + + ~OfflineRegion(); + + void setOfflineRegionObserver(jni::JNIEnv&, const jni::Object&); + + void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint); + + void getOfflineRegionStatus(jni::JNIEnv&, const jni::Object&); + + void deleteOfflineRegion(jni::JNIEnv&, const jni::Object&); + + void invalidateOfflineRegion(jni::JNIEnv&, const jni::Object&); + + void updateOfflineRegionMetadata(jni::JNIEnv&, const jni::Array&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::Object&, mbgl::OfflineRegion); + + static jni::Local> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata); + + static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, const jni::Array&); + + static void registerNative(jni::JNIEnv&); + +private: + std::unique_ptr region; + std::shared_ptr fileSource; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.cpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.cpp new file mode 100644 index 000000000..bb9dfc8dd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.cpp @@ -0,0 +1,107 @@ +#include "offline_region_definition.hpp" + +#include "../geometry/lat_lng_bounds.hpp" +#include "../geojson/geometry.hpp" + +#include + +namespace mbgl { +namespace android { + +// OfflineRegionDefinition // + +void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, + const jni::Object& jDefinition) { + if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { + return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); + } else if (jDefinition.IsInstanceOf(env, jni::Class::Singleton(env))) { + return OfflineGeometryRegionDefinition::getDefinition(env, jni::Cast(env, jni::Class::Singleton(env), jDefinition)); + } + + throw std::runtime_error("Unknown offline region definition java class"); +} + +// OfflineTilePyramidRegionDefinition // + +jni::Local> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); + + return javaClass.New(env, constructor, + jni::Make(env, definition.styleURL), + LatLngBounds::New(env, definition.bounds), + definition.minZoom, + definition.maxZoom, + definition.pixelRatio, + jni::jboolean(definition.includeIdeographs)); +} + +mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { + // Field references + static auto& javaClass = jni::Class::Singleton(env); + static auto styleURLF = javaClass.GetField(env, "styleURL"); + static auto boundsF = javaClass.GetField>(env, "bounds"); + static auto minZoomF = javaClass.GetField(env, "minZoom"); + static auto maxZoomF = javaClass.GetField(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); + static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); + + return mbgl::OfflineTilePyramidRegionDefinition( + jni::Make(env, jDefinition.Get(env, styleURLF)), + LatLngBounds::getLatLngBounds(env, jDefinition.Get(env, boundsF)), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF), + jDefinition.Get(env, includeIdeographsF) + ); +} + +void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +// OfflineGeometryRegionDefinition // + +jni::Local> OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat, jni::jboolean>(env); + + return javaClass.New(env, constructor, + jni::Make(env, definition.styleURL), + geojson::Geometry::New(env, definition.geometry), + definition.minZoom, + definition.maxZoom, + definition.pixelRatio, + jni::jboolean(definition.includeIdeographs)); +} + +mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, const jni::Object& jDefinition) { + // Field references + static auto& javaClass = jni::Class::Singleton(env); + static auto styleURLF = javaClass.GetField(env, "styleURL"); + static auto geometryF = javaClass.GetField>(env, "geometry"); + static auto minZoomF = javaClass.GetField(env, "minZoom"); + static auto maxZoomF = javaClass.GetField(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); + static auto includeIdeographsF = javaClass.GetField(env, "includeIdeographs"); + + return mbgl::OfflineGeometryRegionDefinition( + jni::Make(env, jDefinition.Get(env, styleURLF)), + geojson::Geometry::convert(env, jDefinition.Get(env, geometryF)), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF), + jDefinition.Get(env, includeIdeographsF) + ); +} + +void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.hpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.hpp new file mode 100644 index 000000000..827fac0a8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_definition.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionDefinition { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; }; + + static void registerNative(jni::JNIEnv&); + + static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, const jni::Object& jDefinition); +}; + +class OfflineTilePyramidRegionDefinition { +public: + using SuperTag = OfflineRegionDefinition; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); + + static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +class OfflineGeometryRegionDefinition { +public: + using SuperTag = OfflineRegionDefinition; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; + + static jni::Local> New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); + + static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.cpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.cpp new file mode 100644 index 000000000..199bbafa6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.cpp @@ -0,0 +1,44 @@ +#include "offline_region_error.hpp" + +namespace mbgl { +namespace android { + +jni::Local> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) { + + // Handle the value of reason independently of the underlying int value + std::string reason; + switch(error.reason) { + case mbgl::Response::Error::Reason::Success: + reason = "REASON_SUCCESS"; + break; + case mbgl::Response::Error::Reason::NotFound: + reason = "REASON_NOT_FOUND"; + break; + case mbgl::Response::Error::Reason::Server: + reason = "REASON_SERVER"; + break; + case mbgl::Response::Error::Reason::Connection: + reason = "REASON_CONNECTION"; + break; + case mbgl::Response::Error::Reason::RateLimit: + reason = "REASON_RATE_LIMIT"; + break; + case mbgl::Response::Error::Reason::Other: + reason = "REASON_OTHER"; + break; + } + + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + + return javaClass.New(env, constructor, + jni::Make(env, reason), + jni::Make(env, error.message)); +} + +void OfflineRegionError::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.hpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.hpp new file mode 100644 index 000000000..151e05ab1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_error.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionError { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::Response::Error); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.cpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.cpp new file mode 100644 index 000000000..5dd9f20a7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.cpp @@ -0,0 +1,38 @@ +#include "offline_region_status.hpp" + +namespace mbgl { +namespace android { + +jni::Local> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) { + + // Convert to jint + jint downloadState; + switch(status.downloadState) { + case mbgl::OfflineRegionDownloadState::Inactive: + downloadState = 0; + break; + case mbgl::OfflineRegionDownloadState::Active: + downloadState = 1; + break; + } + + // Create java object + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, + downloadState, + jlong(status.completedResourceCount), + jlong(status.completedResourceSize), + jlong(status.completedTileCount), + jlong(status.completedTileSize), + jlong(status.requiredResourceCount), + jboolean(status.requiredResourceCountIsPrecise) + ); +} + +void OfflineRegionStatus::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.hpp b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.hpp new file mode 100644 index 000000000..9ef48ec35 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/offline/offline_region_status.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace android { + +class OfflineRegionStatus { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; }; + + static jni::Local> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.cpp b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.cpp new file mode 100644 index 000000000..03a532a43 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.cpp @@ -0,0 +1,65 @@ +#include "map_snapshot.hpp" + +#include "bitmap.hpp" +#include "../conversion/collection.hpp" + +#include + +namespace mbgl { +namespace android { + +MapSnapshot::MapSnapshot(float pixelRatio_, MapSnapshot::PointForFn pointForFn_, MapSnapshot::LatLngForFn latLngForFn_) + : pixelRatio(pixelRatio_) + , pointForFn(std::move(pointForFn_)) + , latLngForFn(std::move(latLngForFn_)) { +} + +MapSnapshot::~MapSnapshot() = default; + +jni::Local> MapSnapshot::pixelForLatLng(jni::JNIEnv& env, jni::Object& jLatLng) { + ScreenCoordinate point = pointForFn(LatLng::getLatLng(env, jLatLng)); + return PointF::New(env, point.x * pixelRatio, point.y * pixelRatio); +} + +jni::Local> MapSnapshot::latLngForPixel(jni::JNIEnv& env, jni::Object& jPoint) { + return LatLng::New(env, latLngForFn(PointF::getScreenCoordinate(env, jPoint))); +} + +// Static methods // + +jni::Local> MapSnapshot::New(JNIEnv& env, + PremultipliedImage&& image, + float pixelRatio, + std::vector attributions, + bool showLogo, + mbgl::MapSnapshotter::PointForFn pointForFn, + mbgl::MapSnapshotter::LatLngForFn latLngForFn) { + // Create the bitmap + auto bitmap = Bitmap::CreateBitmap(env, std::move(image)); + + // Create the Mapsnapshot peers + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor, jni::Array, jni::jboolean>(env); + auto nativePeer = std::make_unique(pixelRatio, pointForFn, latLngForFn); + return javaClass.New(env, constructor, reinterpret_cast(nativePeer.release()), bitmap, conversion::toArray(env, attributions), (jni::jboolean) showLogo); +} + +void MapSnapshot::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, javaClass, + "nativePtr", + std::make_unique, + "initialize", + "finalize", + METHOD(&MapSnapshot::latLngForPixel, "latLngForPixel"), + METHOD(&MapSnapshot::pixelForLatLng, "pixelForLatLng") + ); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.hpp b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.hpp new file mode 100644 index 000000000..6b82d0283 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshot.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include + +#include "../geometry/lat_lng.hpp" +#include "../graphics/pointf.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +class MapSnapshot { +public: + + using PointForFn = mbgl::MapSnapshotter::PointForFn; + using LatLngForFn = mbgl::MapSnapshotter::LatLngForFn; + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshot"; }; + + static void registerNative(jni::JNIEnv&); + + static jni::Local> New(JNIEnv& env, + PremultipliedImage&& image, + float pixelRatio, + std::vector attributions, + bool showLogo, + PointForFn pointForFn, + LatLngForFn latLngForFn); + + MapSnapshot(jni::JNIEnv&) {}; + MapSnapshot(float pixelRatio, PointForFn, LatLngForFn); + ~MapSnapshot(); + + jni::Local> pixelForLatLng(jni::JNIEnv&, jni::Object&); + jni::Local> latLngForPixel(jni::JNIEnv&, jni::Object&); + +private: + float pixelRatio; + mbgl::MapSnapshotter::PointForFn pointForFn; + mbgl::MapSnapshotter::LatLngForFn latLngForFn; +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.cpp b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.cpp new file mode 100644 index 000000000..159da809f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.cpp @@ -0,0 +1,353 @@ +#include "map_snapshotter.hpp" + +#include +#include +#include +#include +#include + +#include "attach_env.hpp" +#include "../style/layers/layer_manager.hpp" +#include "map_snapshot.hpp" + +namespace mbgl { +namespace android { + +MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, + const jni::Object& _obj, + const jni::Object& _jFileSource, + jni::jfloat _pixelRatio, + jni::jint width, + jni::jint height, + const jni::String& styleURL, + const jni::String& styleJSON, + const jni::Object& region, + const jni::Object& position, + jni::jboolean _showLogo, + const jni::String& _localIdeographFontFamily) + : javaPeer(_env, _obj) + , pixelRatio(_pixelRatio) { + + // Get a reference to the JavaVM for callbacks + if (_env.GetJavaVM(&vm) < 0) { + _env.ExceptionDescribe(); + return; + } + + weakScheduler = mbgl::Scheduler::GetCurrent()->makeWeakPtr(); + + jFileSource = FileSource::getNativePeer(_env, _jFileSource); + auto size = mbgl::Size { static_cast(width), static_cast(height) }; + + showLogo = _showLogo; + + // Create the core snapshotter + snapshotter = std::make_unique( + size, + pixelRatio, + mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource), + *this, + _localIdeographFontFamily ? jni::Make(_env, _localIdeographFontFamily) : optional{}); + + if (position) { + snapshotter->setCameraOptions(CameraPosition::getCameraOptions(_env, position, pixelRatio)); + } + + if (region) { + snapshotter->setRegion(LatLngBounds::getLatLngBounds(_env, region)); + } + + if (styleJSON) { + snapshotter->setStyleJSON(jni::Make(_env, styleJSON)); + } else { + snapshotter->setStyleURL(jni::Make(_env, styleURL)); + } +} + +MapSnapshotter::~MapSnapshotter() { + auto guard = weakScheduler.lock(); + if (weakScheduler && weakScheduler.get() != mbgl::Scheduler::GetCurrent()) { + snapshotter->cancel(); + weakScheduler->schedule([ptr = snapshotter.release()]() mutable { + if (ptr) { + delete ptr; + } + }); + } +} + +void MapSnapshotter::start(JNIEnv& env) { + MBGL_VERIFY_THREAD(tid); + activateFilesource(env); + snapshotter->snapshot([this](std::exception_ptr err, + PremultipliedImage image, + std::vector attributions, + mbgl::MapSnapshotter::PointForFn pointForFn, + mbgl::MapSnapshotter::LatLngForFn latLngForFn) { + MBGL_VERIFY_THREAD(tid); + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + + if (err) { + // error handler callback + static auto onSnapshotFailed = javaClass.GetMethod(*_env, "onSnapshotFailed"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotFailed, jni::Make(*_env, util::toString(err))); + } + } else { + // Create the wrapper + auto mapSnapshot = android::MapSnapshot::New(*_env, std::move(image), pixelRatio, attributions, showLogo, pointForFn, latLngForFn); + + // invoke callback + static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onSnapshotReady, mapSnapshot); + } + } + + deactivateFilesource(*_env); + }); +} + +void MapSnapshotter::cancel(JNIEnv& env) { + MBGL_VERIFY_THREAD(tid); + snapshotter->cancel(); + deactivateFilesource(env); +} + +void MapSnapshotter::setStyleUrl(JNIEnv& env, const jni::String& styleURL) { + snapshotter->setStyleURL(jni::Make(env, styleURL)); +} + +void MapSnapshotter::setStyleJson(JNIEnv& env, const jni::String& styleJSON) { + snapshotter->setStyleJSON(jni::Make(env, styleJSON)); +} + +void MapSnapshotter::setSize(JNIEnv&, jni::jint width, jni::jint height) { + auto size = mbgl::Size { static_cast(width), static_cast(height) }; + snapshotter->setSize(size); +} + +void MapSnapshotter::setCameraPosition(JNIEnv& env, const jni::Object& position) { + auto options = CameraPosition::getCameraOptions(env, position, pixelRatio); + snapshotter->setCameraOptions(options); +} + +void MapSnapshotter::setRegion(JNIEnv& env, const jni::Object& region) { + snapshotter->setRegion(LatLngBounds::getLatLngBounds(env, region)); +} + +// Private methods // + +void MapSnapshotter::activateFilesource(JNIEnv& env) { + if (!activatedFilesource) { + activatedFilesource = true; + jFileSource->resume(env); + } +} + +void MapSnapshotter::deactivateFilesource(JNIEnv& env) { + if (activatedFilesource) { + activatedFilesource = false; + jFileSource->pause(env); + } +} + +void MapSnapshotter::onDidFailLoadingStyle(const std::string& error) { + MBGL_VERIFY_THREAD(tid); + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFailLoadingStyle = javaClass.GetMethod(*_env, "onDidFailLoadingStyle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFailLoadingStyle, jni::Make(*_env, error)); + } +} + +void MapSnapshotter::onDidFinishLoadingStyle() { + MBGL_VERIFY_THREAD(tid); + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishLoadingStyle = javaClass.GetMethod(*_env, "onDidFinishLoadingStyle"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onDidFinishLoadingStyle); + } +} + +void MapSnapshotter::onStyleImageMissing(const std::string& imageName) { + MBGL_VERIFY_THREAD(tid); + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onStyleImageMissing = javaClass.GetMethod(*_env, "onStyleImageMissing"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + weakReference.Call(*_env, onStyleImageMissing, jni::Make(*_env, imageName)); + } +} + +void MapSnapshotter::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) { + assert(nativeLayerPtr != 0); + const auto layers = snapshotter->getStyle().getLayers(); + auto* layer = reinterpret_cast(nativeLayerPtr); + // Check index + const int numLayers = layers.size() - 1; + if (index > numLayers || index < 0) { + Log::Error(Event::JNI, "Index out of range: %i", index); + jni::ThrowNew(env, + jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Invalid index").c_str()); + } + // Insert it below the current at that index + try { + layer->addToStyle(snapshotter->getStyle(), layers.at(index)->getID()); + } catch (const std::runtime_error& error) { + jni::ThrowNew( + env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void MapSnapshotter::addLayerBelow(JNIEnv& env, jlong nativeLayerPtr, const jni::String& below) { + assert(nativeLayerPtr != 0); + + auto* layer = reinterpret_cast(nativeLayerPtr); + try { + layer->addToStyle( + snapshotter->getStyle(), + below ? mbgl::optional(jni::Make(env, below)) : mbgl::optional()); + } catch (const std::runtime_error& error) { + jni::ThrowNew( + env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void MapSnapshotter::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, const jni::String& above) { + assert(nativeLayerPtr != 0); + auto* newLayer = reinterpret_cast(nativeLayerPtr); + + // Find the sibling + const auto snapshotterLayers = snapshotter->getStyle().getLayers(); + auto siblingId = jni::Make(env, above); + + size_t index = 0; + for (auto* snapshotterLayer : snapshotterLayers) { + ++index; + if (snapshotterLayer->getID() == siblingId) { + break; + } + } + + // Check if we found a sibling to place before + mbgl::optional before; + if (index > snapshotterLayers.size()) { + // Not found + jni::ThrowNew(env, + jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), + std::string("Could not find layer: ").append(siblingId).c_str()); + } else if (index < snapshotterLayers.size()) { + // Place before the sibling + before = {snapshotterLayers.at(index)->getID()}; + } + + // Add the layer + try { + newLayer->addToStyle(snapshotter->getStyle(), before); + } catch (const std::runtime_error& error) { + jni::ThrowNew( + env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +void MapSnapshotter::addSource(JNIEnv& env, const jni::Object& obj, jlong sourcePtr) { + assert(sourcePtr != 0); + + auto* source = reinterpret_cast(sourcePtr); + try { + source->addToStyle(env, obj, snapshotter->getStyle()); + } catch (const std::runtime_error& error) { + jni::ThrowNew( + env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); + } +} + +void MapSnapshotter::addImages(JNIEnv& env, const jni::Array>& jimages) { + jni::NullCheck(env, &jimages); + std::size_t len = jimages.Length(env); + + for (std::size_t i = 0; i < len; ++i) { + auto image = mbgl::android::Image::getImage(env, jimages.Get(env, i)); + snapshotter->getStyle().addImage(std::make_unique(image)); + } +} + +jni::Local> MapSnapshotter::getLayer(JNIEnv& env, const jni::String& layerId) { + // Find the layer + mbgl::style::Layer* coreLayer = snapshotter->getStyle().getLayer(jni::Make(env, layerId)); + if (!coreLayer) { + mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); + return jni::Local>(); + } + + // Create and return the layer's native peer + return LayerManagerAndroid::get()->createJavaLayerPeer(env, *coreLayer); +} + +jni::Local> MapSnapshotter::getSource(JNIEnv& env, const jni::String& sourceId) { + // Find the source + mbgl::style::Source* coreSource = snapshotter->getStyle().getSource(jni::Make(env, sourceId)); + if (!coreSource) { + mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); + return jni::Local>(); + } + + // Create and return the source's native peer + return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource)); +} + +// Static methods // + +void MapSnapshotter::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, + javaClass, + "nativePtr", + jni::MakePeer&, + const jni::Object&, + jni::jfloat, + jni::jint, + jni::jint, + const jni::String&, + const jni::String&, + const jni::Object&, + const jni::Object&, + jni::jboolean, + const jni::String&>, + "nativeInitialize", + "finalize", + METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"), + METHOD(&MapSnapshotter::addLayerAt, "nativeAddLayerAt"), + METHOD(&MapSnapshotter::addLayerBelow, "nativeAddLayerBelow"), + METHOD(&MapSnapshotter::addLayerAbove, "nativeAddLayerAbove"), + METHOD(&MapSnapshotter::addSource, "nativeAddSource"), + METHOD(&MapSnapshotter::addImages, "nativeAddImages"), + METHOD(&MapSnapshotter::getLayer, "nativeGetLayer"), + METHOD(&MapSnapshotter::getSource, "nativeGetSource"), + METHOD(&MapSnapshotter::setStyleJson, "setStyleJson"), + METHOD(&MapSnapshotter::setSize, "setSize"), + METHOD(&MapSnapshotter::setCameraPosition, "setCameraPosition"), + METHOD(&MapSnapshotter::setRegion, "setRegion"), + METHOD(&MapSnapshotter::start, "nativeStart"), + METHOD(&MapSnapshotter::cancel, "nativeCancel")); +} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.hpp b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.hpp new file mode 100644 index 000000000..4d0186e7f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/snapshotter/map_snapshotter.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "../file_source.hpp" +#include "../geometry/lat_lng_bounds.hpp" +#include "../map/camera_position.hpp" +#include "../map/image.hpp" +#include "../style/layers/layer.hpp" +#include "../style/sources/source.hpp" + +namespace mbgl { +namespace android { + +class MapSnapshotter final : public mbgl::MapSnapshotterObserver { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshotter"; }; + + static void registerNative(jni::JNIEnv&); + + MapSnapshotter(jni::JNIEnv&, + const jni::Object&, + const jni::Object&, + jni::jfloat pixelRatio, + jni::jint width, + jni::jint height, + const jni::String& styleURL, + const jni::String& styleJSON, + const jni::Object& region, + const jni::Object& position, + jni::jboolean showLogo, + const jni::String& localIdeographFontFamily); + + virtual ~MapSnapshotter() override; + + void setStyleUrl(JNIEnv&, const jni::String& styleURL); + + void setStyleJson(JNIEnv&, const jni::String& styleJSON); + + void setSize(JNIEnv&, jni::jint width, jni::jint height); + + void setCameraPosition(JNIEnv&, const jni::Object& position); + + void setRegion(JNIEnv&, const jni::Object& region); + + void start(JNIEnv&); + + void cancel(JNIEnv&); + + void addLayerAt(JNIEnv&, jlong, jni::jint); + void addLayerBelow(JNIEnv&, jlong, const jni::String&); + void addLayerAbove(JNIEnv&, jlong, const jni::String&); + void addSource(JNIEnv&, const jni::Object&, jlong nativePtr); + void addImages(JNIEnv&, const jni::Array>&); + jni::Local> getLayer(JNIEnv&, const jni::String&); + jni::Local> getSource(JNIEnv&, const jni::String&); + + // MapSnapshotterObserver overrides + void onDidFailLoadingStyle(const std::string&) override; + void onDidFinishLoadingStyle() override; + void onStyleImageMissing(const std::string&) override; + +private: + MBGL_STORE_THREAD(tid); + + JavaVM *vm = nullptr; + jni::WeakReference, jni::EnvAttachingDeleter> javaPeer; + + float pixelRatio; + bool showLogo; + + FileSource *jFileSource; + void activateFilesource(JNIEnv&); + void deactivateFilesource(JNIEnv&); + bool activatedFilesource = false; + mapbox::base::WeakPtr weakScheduler; + std::unique_ptr snapshotter; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/android_conversion.hpp b/MapboxGLAndroidSDK/src/cpp/style/android_conversion.hpp new file mode 100644 index 000000000..6f1680459 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/android_conversion.hpp @@ -0,0 +1,148 @@ +#pragma once + +#include "value.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +class ConversionTraits { +public: + static bool isUndefined(const mbgl::android::Value& value) { + return value.isNull(); + } + + static bool isArray(const mbgl::android::Value& value) { + return value.isArray(); + } + + static bool isObject(const mbgl::android::Value& value) { + return value.isObject(); + } + + static std::size_t arrayLength(const mbgl::android::Value& value) { + return value.getLength();; + } + + static mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { + return value.get(i); + } + + static optional objectMember(const mbgl::android::Value& value, const char* key) { + mbgl::android::Value member = value.get(key); + if (!member.isNull()) { + return member; + } else { + return {}; + } + } + + template + static optional eachMember(const mbgl::android::Value& value, Fn&& fn) { + assert(value.isObject()); + mbgl::android::Value keys = value.keyArray(); + std::size_t length = arrayLength(keys); + for(std::size_t i = 0; i < length; ++i){ + const auto k = keys.get(i).toString(); + auto v = value.get(k.c_str()); + optional result = fn(k, std::move(v)); + if (result) { + return result; + } + } + return {}; + } + + static optional toBool(const mbgl::android::Value& value) { + if (value.isBool()) { + return value.toBool(); + } else { + return {}; + } + } + + static optional toNumber(const mbgl::android::Value& value) { + if (value.isNumber()) { + auto num = value.toFloat(); + return num; + } else { + return {}; + } + } + + static optional toDouble(const mbgl::android::Value& value) { + if (value.isNumber()) { + return value.toDouble(); + } else { + return {}; + } + } + + static optional toString(const mbgl::android::Value& value) { + if (value.isString()) { + return value.toString(); + } else { + return {}; + } + } + + static optional toValue(const mbgl::android::Value& value) { + if (value.isNull()) { + return {}; + } else if (value.isBool()) { + return { value.toBool() }; + } else if (value.isString()) { + return { value.toString() }; + } else if (value.isNumber()) { + return { value.toDouble() }; + } else { + return {}; + } + } + + static optional toGeoJSON(const mbgl::android::Value &value, Error &error) { + if (value.isNull()) { + error = { "no json data found" }; + return {}; + } + + if (value.isString()) { + return parseGeoJSON(value.toString(), error); + } + + if (value.isObject()) { + mbgl::android::Value keys = value.keyArray(); + std::size_t length = arrayLength(keys); + for (std::size_t i = 0; i < length; ++i) { + if (keys.get(i).toString() == "json") { + auto v = value.get("json"); + if (v.isString()) { + return parseGeoJSON(v.toString(), error); + } else { + break; + } + } + } + } + error = {"no json data found"}; + return {}; + } +}; + +template +optional convert(mbgl::android::Value&& value, Error& error, Args&&...args) { + return convert(Convertible(std::move(value)), error, std::forward(args)...); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.cpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.cpp new file mode 100644 index 000000000..d15e2747a --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.cpp @@ -0,0 +1,26 @@ +#include "filter.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +optional toFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { + mbgl::optional filter; + if (jfilter) { + mbgl::style::conversion::Error error; + auto converted = mbgl::style::conversion::convert(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); + } + filter = std::move(*converted); + } + return filter; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.hpp new file mode 100644 index 000000000..920d336a1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/filter.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +optional toFilter(jni::JNIEnv&, const jni::Array>&); + +} // namespace conversion +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/position.cpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/position.cpp new file mode 100644 index 000000000..e3c334afd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/position.cpp @@ -0,0 +1,24 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, mbgl::style::Position>::operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { + std::array cartPosition = value.getSpherical(); + return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); +} + +Result Converter>::operator()(jni::JNIEnv &env, const jni::Object &value) const { + float radialCoordinate = Position::getRadialCoordinate(env, value); + float azimuthalAngle = Position::getAzimuthalAngle(env, value); + float polarAngle = Position::getPolarAngle(env, value); + std::array cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; + mbgl::style::Position position{}; + position.set(cartPosition); + return position; +} + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/position.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/position.hpp new file mode 100644 index 000000000..90409d527 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/position.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../position.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter>, mbgl::style::Position> { + Result>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const; +}; + +template <> +struct Converter> { + Result operator()(jni::JNIEnv &env, const jni::Object &value) const; +}; + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/property_expression.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/property_expression.hpp new file mode 100644 index 000000000..4e26b11f9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/property_expression.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../../gson/json_element.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template +struct Converter>, mbgl::style::PropertyExpression> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyExpression& value) const { + return gson::JsonElement::New(env, value.getExpression().serialize()); + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/property_value.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/property_value.hpp new file mode 100644 index 000000000..317705a28 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/property_value.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include + +#include "../../conversion/conversion.hpp" +#include "../../conversion/constant.hpp" +#include "property_expression.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Conversion from core property value types to Java property value types + */ +template +class PropertyValueEvaluator { +public: + PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {} + + jni::Local> operator()(const mbgl::style::Undefined) const { + return jni::Local>(env, nullptr); + } + + jni::Local> operator()(const T& value) const { + return std::move(*convert>>(env, value)); + } + + jni::Local> operator()(const mbgl::style::PropertyExpression& value) const { + return std::move(*convert>>(env, value)); + } + +private: + jni::JNIEnv& env; +}; + +/** + * Convert core property values to java + */ +template +struct Converter>, mbgl::style::PropertyValue> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue& value) const { + PropertyValueEvaluator evaluator(env); + return value.evaluate(evaluator); + } +}; + +/** + * Convert core heat map color property value to java + */ +template <> +struct Converter>, mbgl::style::ColorRampPropertyValue> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue& value) const { + PropertyValueEvaluator evaluator(env); + return std::move(*convert>>(env, value.evaluate(evaluator))); + } +}; + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.cpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.cpp new file mode 100644 index 000000000..75d9b4cc0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.cpp @@ -0,0 +1,17 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result>> Converter>, mbgl::style::TransitionOptions>::operator()(jni::JNIEnv& env, const mbgl::style::TransitionOptions& value) const { + return TransitionOptions::fromTransitionOptions(env, + std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())).count(), + std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())).count(), + (jboolean) value.enablePlacementTransitions + ); +} + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.hpp new file mode 100644 index 000000000..06c042922 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/transition_options.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../conversion/conversion.hpp" +#include "../transition_options.hpp" + +#include + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template<> +struct Converter>, mbgl::style::TransitionOptions> { + Result>> operator()(jni::JNIEnv&, const mbgl::style::TransitionOptions&) const; +}; + +} +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.cpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.cpp new file mode 100644 index 000000000..2ec585675 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.cpp @@ -0,0 +1,30 @@ +#include "url_or_tileset.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +// This conversion is expected not to fail because it's used only in contexts where +// the value was originally a String or TileSet object on the Java side. If it fails +// to convert, it's a bug in our serialization or Java-side static typing. +variant convertURLOrTileset(mbgl::android::Value&& value) { + using namespace mbgl::style::conversion; + + const Convertible convertible(std::move(value)); + if (isObject(convertible)) { + Error error; + optional tileset = convert(convertible, error); + if (!tileset) { + throw std::logic_error(error.message); + } + return { *tileset }; + } else { + return { *toString(convertible) }; + } +} + +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.hpp b/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.hpp new file mode 100644 index 000000000..f42a9b9a2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/conversion/url_or_tileset.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +#include "../value.hpp" + +namespace mbgl { +namespace android { + +variant convertURLOrTileset(mbgl::android::Value&& value); + +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/style/formatted.cpp b/MapboxGLAndroidSDK/src/cpp/style/formatted.cpp new file mode 100644 index 000000000..69c3454e2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/formatted.cpp @@ -0,0 +1,54 @@ +#include "formatted.hpp" +#include "formatted_section.hpp" +#include "../conversion/conversion.hpp" +#include "../conversion/constant.hpp" + +namespace mbgl { +namespace android { + +void Formatted::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Formatted::New(jni::JNIEnv& env, const style::expression::Formatted& value) { + static auto& formatted = jni::Class::Singleton(env); + static auto formattedConstructor = formatted.GetConstructor>>(env); + static auto& formattedSectionClass = jni::Class::Singleton(env); + + auto sections = jni::Array>::New(env, value.sections.size()); + for (std::size_t i = 0; i < value.sections.size(); i++) { + auto section = value.sections.at(i); + auto text = jni::Make(env, section.text); + static auto formattedSectionConstructor = formattedSectionClass.GetConstructor(env); + auto formattedSection = formattedSectionClass.New(env, formattedSectionConstructor, text); + + if (section.fontScale) { + double fontScale = section.fontScale.value(); + static auto method = formattedSectionClass.GetMethod(env, "setFontScale"); + formattedSection.Call(env, method, jni::Box(env, fontScale)); + } + + if (section.fontStack) { + auto fontStack = jni::Array::New(env, section.fontStack.value().size()); + for (std::size_t j = 0; j < section.fontStack.value().size(); j++) { + fontStack.Set(env, j, jni::Make(env, section.fontStack.value().at(j))); + } + static auto method = formattedSectionClass.GetMethod)>(env, "setFontStack"); + formattedSection.Call(env, method, fontStack); + } + + if (section.textColor) { + using namespace mbgl::android::conversion; + auto textColor = std::move(*convert>>(env, *section.textColor)); + static auto method = formattedSectionClass.GetMethod)>(env, "setTextColor"); + formattedSection.Call(env, method, textColor); + } + + sections.Set(env, i, formattedSection); + } + + return formatted.New(env, formattedConstructor, sections); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/formatted.hpp b/MapboxGLAndroidSDK/src/cpp/style/formatted.hpp new file mode 100644 index 000000000..ca91f6562 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/formatted.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { + namespace android { + + using SuperTag = jni::ObjectTag; + class Formatted : private mbgl::util::noncopyable { + public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/Formatted"; }; + + static jni::Local> + New(jni::JNIEnv&, const style::expression::Formatted &value); + + static void registerNative(jni::JNIEnv &); + }; + + } // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/formatted_section.cpp b/MapboxGLAndroidSDK/src/cpp/style/formatted_section.cpp new file mode 100644 index 000000000..ddcf76f81 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/formatted_section.cpp @@ -0,0 +1,11 @@ +#include "formatted_section.hpp" + +namespace mbgl { +namespace android { + +void FormattedSection::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/formatted_section.hpp b/MapboxGLAndroidSDK/src/cpp/style/formatted_section.hpp new file mode 100644 index 000000000..f759a94e8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/formatted_section.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class FormattedSection : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/types/FormattedSection"; }; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp new file mode 100644 index 000000000..3eae30677 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp @@ -0,0 +1,148 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "background_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::BackgroundLayer& toBackgroundLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String& layerId) + : Layer(std::make_unique(jni::Make(env, layerId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + BackgroundLayer::BackgroundLayer(mbgl::style::BackgroundLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + BackgroundLayer::BackgroundLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) {} + + BackgroundLayer::~BackgroundLayer() = default; + + // Property getters + + jni::Local> BackgroundLayer::getBackgroundColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundColor())); + } + + jni::Local> BackgroundLayer::getBackgroundColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundColorTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundColorTransition(options); + } + + jni::Local> BackgroundLayer::getBackgroundPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundPattern())); + } + + jni::Local> BackgroundLayer::getBackgroundPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundPatternTransition(options); + } + + jni::Local> BackgroundLayer::getBackgroundOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toBackgroundLayer(layer).getBackgroundOpacity())); + } + + jni::Local> BackgroundLayer::getBackgroundOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toBackgroundLayer(layer).getBackgroundOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void BackgroundLayer::setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toBackgroundLayer(layer).setBackgroundOpacityTransition(options); + } + + + // BackgroundJavaLayerPeerFactory + + BackgroundJavaLayerPeerFactory::~BackgroundJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new BackgroundLayer(toBackgroundLayer(layer))); + } + + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new BackgroundLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void BackgroundJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&BackgroundLayer::getBackgroundColorTransition, "nativeGetBackgroundColorTransition"), + METHOD(&BackgroundLayer::setBackgroundColorTransition, "nativeSetBackgroundColorTransition"), + METHOD(&BackgroundLayer::getBackgroundColor, "nativeGetBackgroundColor"), + METHOD(&BackgroundLayer::getBackgroundPatternTransition, "nativeGetBackgroundPatternTransition"), + METHOD(&BackgroundLayer::setBackgroundPatternTransition, "nativeSetBackgroundPatternTransition"), + METHOD(&BackgroundLayer::getBackgroundPattern, "nativeGetBackgroundPattern"), + METHOD(&BackgroundLayer::getBackgroundOpacityTransition, "nativeGetBackgroundOpacityTransition"), + METHOD(&BackgroundLayer::setBackgroundOpacityTransition, "nativeSetBackgroundOpacityTransition"), + METHOD(&BackgroundLayer::getBackgroundOpacity, "nativeGetBackgroundOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp new file mode 100644 index 000000000..e402dc021 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp @@ -0,0 +1,58 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class BackgroundLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/BackgroundLayer"; }; + + BackgroundLayer(jni::JNIEnv&, jni::String&); + + BackgroundLayer(mbgl::style::BackgroundLayer&); + + BackgroundLayer(std::unique_ptr); + + ~BackgroundLayer(); + + // Properties + + jni::Local> getBackgroundColor(jni::JNIEnv&); + void setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundColorTransition(jni::JNIEnv&); + + jni::Local> getBackgroundPattern(jni::JNIEnv&); + void setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundPatternTransition(jni::JNIEnv&); + + jni::Local> getBackgroundOpacity(jni::JNIEnv&); + void setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBackgroundOpacityTransition(jni::JNIEnv&); + +}; // class BackgroundLayer + +class BackgroundJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::BackgroundLayerFactory { +public: + ~BackgroundJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class BackgroundJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp new file mode 100644 index 000000000..a7fae5e23 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp @@ -0,0 +1,270 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "circle_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::CircleLayer& toCircleLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + CircleLayer::CircleLayer(mbgl::style::CircleLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + CircleLayer::CircleLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + CircleLayer::~CircleLayer() = default; + + // Property getters + + jni::Local> CircleLayer::getCircleRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleRadius())); + } + + jni::Local> CircleLayer::getCircleRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleRadiusTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleRadiusTransition(options); + } + + jni::Local> CircleLayer::getCircleColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleColor())); + } + + jni::Local> CircleLayer::getCircleColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleColorTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleColorTransition(options); + } + + jni::Local> CircleLayer::getCircleBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleBlur())); + } + + jni::Local> CircleLayer::getCircleBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleBlurTransition(options); + } + + jni::Local> CircleLayer::getCircleOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleOpacity())); + } + + jni::Local> CircleLayer::getCircleOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleOpacityTransition(options); + } + + jni::Local> CircleLayer::getCircleTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslate())); + } + + jni::Local> CircleLayer::getCircleTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleTranslateTransition(options); + } + + jni::Local> CircleLayer::getCircleTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleTranslateAnchor())); + } + + jni::Local> CircleLayer::getCirclePitchScale(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchScale())); + } + + jni::Local> CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCirclePitchAlignment())); + } + + jni::Local> CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeWidth())); + } + + jni::Local> CircleLayer::getCircleStrokeWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeWidthTransition(options); + } + + jni::Local> CircleLayer::getCircleStrokeColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeColor())); + } + + jni::Local> CircleLayer::getCircleStrokeColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeColorTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeColorTransition(options); + } + + jni::Local> CircleLayer::getCircleStrokeOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleStrokeOpacity())); + } + + jni::Local> CircleLayer::getCircleStrokeOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toCircleLayer(layer).getCircleStrokeOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void CircleLayer::setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toCircleLayer(layer).setCircleStrokeOpacityTransition(options); + } + + + // CircleJavaLayerPeerFactory + + CircleJavaLayerPeerFactory::~CircleJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new CircleLayer(toCircleLayer(layer))); + } + + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new CircleLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void CircleJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&CircleLayer::getCircleRadiusTransition, "nativeGetCircleRadiusTransition"), + METHOD(&CircleLayer::setCircleRadiusTransition, "nativeSetCircleRadiusTransition"), + METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"), + METHOD(&CircleLayer::getCircleColorTransition, "nativeGetCircleColorTransition"), + METHOD(&CircleLayer::setCircleColorTransition, "nativeSetCircleColorTransition"), + METHOD(&CircleLayer::getCircleColor, "nativeGetCircleColor"), + METHOD(&CircleLayer::getCircleBlurTransition, "nativeGetCircleBlurTransition"), + METHOD(&CircleLayer::setCircleBlurTransition, "nativeSetCircleBlurTransition"), + METHOD(&CircleLayer::getCircleBlur, "nativeGetCircleBlur"), + METHOD(&CircleLayer::getCircleOpacityTransition, "nativeGetCircleOpacityTransition"), + METHOD(&CircleLayer::setCircleOpacityTransition, "nativeSetCircleOpacityTransition"), + METHOD(&CircleLayer::getCircleOpacity, "nativeGetCircleOpacity"), + METHOD(&CircleLayer::getCircleTranslateTransition, "nativeGetCircleTranslateTransition"), + METHOD(&CircleLayer::setCircleTranslateTransition, "nativeSetCircleTranslateTransition"), + METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"), + METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"), + METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"), + METHOD(&CircleLayer::getCirclePitchAlignment, "nativeGetCirclePitchAlignment"), + METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"), + METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"), + METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"), + METHOD(&CircleLayer::getCircleStrokeColorTransition, "nativeGetCircleStrokeColorTransition"), + METHOD(&CircleLayer::setCircleStrokeColorTransition, "nativeSetCircleStrokeColorTransition"), + METHOD(&CircleLayer::getCircleStrokeColor, "nativeGetCircleStrokeColor"), + METHOD(&CircleLayer::getCircleStrokeOpacityTransition, "nativeGetCircleStrokeOpacityTransition"), + METHOD(&CircleLayer::setCircleStrokeOpacityTransition, "nativeSetCircleStrokeOpacityTransition"), + METHOD(&CircleLayer::getCircleStrokeOpacity, "nativeGetCircleStrokeOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp new file mode 100644 index 000000000..40dca91e2 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp @@ -0,0 +1,84 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class CircleLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CircleLayer"; }; + + CircleLayer(jni::JNIEnv&, jni::String&, jni::String&); + + CircleLayer(mbgl::style::CircleLayer&); + + CircleLayer(std::unique_ptr); + + ~CircleLayer(); + + // Properties + + jni::Local> getCircleRadius(jni::JNIEnv&); + void setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleRadiusTransition(jni::JNIEnv&); + + jni::Local> getCircleColor(jni::JNIEnv&); + void setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleColorTransition(jni::JNIEnv&); + + jni::Local> getCircleBlur(jni::JNIEnv&); + void setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleBlurTransition(jni::JNIEnv&); + + jni::Local> getCircleOpacity(jni::JNIEnv&); + void setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleOpacityTransition(jni::JNIEnv&); + + jni::Local> getCircleTranslate(jni::JNIEnv&); + void setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleTranslateTransition(jni::JNIEnv&); + + jni::Local> getCircleTranslateAnchor(jni::JNIEnv&); + + jni::Local> getCirclePitchScale(jni::JNIEnv&); + + jni::Local> getCirclePitchAlignment(jni::JNIEnv&); + + jni::Local> getCircleStrokeWidth(jni::JNIEnv&); + void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeWidthTransition(jni::JNIEnv&); + + jni::Local> getCircleStrokeColor(jni::JNIEnv&); + void setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeColorTransition(jni::JNIEnv&); + + jni::Local> getCircleStrokeOpacity(jni::JNIEnv&); + void setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getCircleStrokeOpacityTransition(jni::JNIEnv&); + +}; // class CircleLayer + +class CircleJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CircleLayerFactory { +public: + ~CircleJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class CircleJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.cpp new file mode 100644 index 000000000..5a8b239a8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.cpp @@ -0,0 +1,61 @@ +#include "custom_layer.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + CustomLayer::CustomLayer(jni::JNIEnv& env, const jni::String& layerId, jni::jlong host) + : Layer(std::make_unique( + jni::Make(env, layerId), + std::unique_ptr(reinterpret_cast(host))) + ) { + } + + CustomLayer::CustomLayer(mbgl::style::CustomLayer& coreLayer) : Layer(coreLayer) {} + + CustomLayer::CustomLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + CustomLayer::~CustomLayer() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } + + CustomJavaLayerPeerFactory::~CustomJavaLayerPeerFactory() = default; + + jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + return createJavaPeer(env, new CustomLayer(static_cast(layer))); + } + + jni::Local> CustomJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + return createJavaPeer(env, + new CustomLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void CustomJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize"); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.hpp new file mode 100644 index 000000000..3856ea73a --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/custom_layer.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include "layer.hpp" + +namespace mbgl { +namespace android { + +class CustomLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CustomLayer"; }; + + static void registerNative(jni::JNIEnv&); + + CustomLayer(jni::JNIEnv&, const jni::String&, jni::jlong); + CustomLayer(mbgl::style::CustomLayer&); + CustomLayer(std::unique_ptr); + ~CustomLayer(); + + jni::Local> createJavaPeer(jni::JNIEnv&); +}; // class CustomLayer + +class CustomJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::CustomLayerFactory { +public: + ~CustomJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class CustomJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp new file mode 100644 index 000000000..55c3d2028 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp @@ -0,0 +1,225 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "fill_extrusion_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::FillExtrusionLayer& toFillExtrusionLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + FillExtrusionLayer::FillExtrusionLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + FillExtrusionLayer::FillExtrusionLayer(mbgl::style::FillExtrusionLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + FillExtrusionLayer::FillExtrusionLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) {} + + FillExtrusionLayer::~FillExtrusionLayer() = default; + + // Property getters + + jni::Local> FillExtrusionLayer::getFillExtrusionOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionOpacity())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionOpacityTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionColor())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionColorTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslate())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionTranslateTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionTranslateAnchor())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionPattern())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionPatternTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionHeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionHeight())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionHeightTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionHeightTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionHeightTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionBase(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionBase())); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionBaseTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillExtrusionLayer(layer).getFillExtrusionBaseTransition(); + return std::move(*convert>>(env, options)); + } + + void FillExtrusionLayer::setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillExtrusionLayer(layer).setFillExtrusionBaseTransition(options); + } + + jni::Local> FillExtrusionLayer::getFillExtrusionVerticalGradient(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillExtrusionLayer(layer).getFillExtrusionVerticalGradient())); + } + + + // FillExtrusionJavaLayerPeerFactory + + FillExtrusionJavaLayerPeerFactory::~FillExtrusionJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillExtrusionLayer(toFillExtrusionLayer(layer))); + } + + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new FillExtrusionLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void FillExtrusionJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FillExtrusionLayer::getFillExtrusionOpacityTransition, "nativeGetFillExtrusionOpacityTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionOpacityTransition, "nativeSetFillExtrusionOpacityTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionOpacity, "nativeGetFillExtrusionOpacity"), + METHOD(&FillExtrusionLayer::getFillExtrusionColorTransition, "nativeGetFillExtrusionColorTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionColorTransition, "nativeSetFillExtrusionColorTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionColor, "nativeGetFillExtrusionColor"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, + "nativeGetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, + "nativeSetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslate, "nativeGetFillExtrusionTranslate"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslateAnchor, "nativeGetFillExtrusionTranslateAnchor"), + METHOD(&FillExtrusionLayer::getFillExtrusionPatternTransition, "nativeGetFillExtrusionPatternTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionPatternTransition, "nativeSetFillExtrusionPatternTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionPattern, "nativeGetFillExtrusionPattern"), + METHOD(&FillExtrusionLayer::getFillExtrusionHeightTransition, "nativeGetFillExtrusionHeightTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionHeightTransition, "nativeSetFillExtrusionHeightTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionHeight, "nativeGetFillExtrusionHeight"), + METHOD(&FillExtrusionLayer::getFillExtrusionBaseTransition, "nativeGetFillExtrusionBaseTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionBaseTransition, "nativeSetFillExtrusionBaseTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionBase, "nativeGetFillExtrusionBase"), + METHOD(&FillExtrusionLayer::getFillExtrusionVerticalGradient, "nativeGetFillExtrusionVerticalGradient")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp new file mode 100644 index 000000000..6f0a24131 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp @@ -0,0 +1,74 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class FillExtrusionLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer"; }; + + FillExtrusionLayer(jni::JNIEnv&, jni::String&, jni::String&); + + FillExtrusionLayer(mbgl::style::FillExtrusionLayer&); + + FillExtrusionLayer(std::unique_ptr); + + ~FillExtrusionLayer(); + + // Properties + + jni::Local> getFillExtrusionOpacity(jni::JNIEnv&); + void setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionOpacityTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionColor(jni::JNIEnv&); + void setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionColorTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionTranslate(jni::JNIEnv&); + void setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionTranslateTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionTranslateAnchor(jni::JNIEnv&); + + jni::Local> getFillExtrusionPattern(jni::JNIEnv&); + void setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionPatternTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionHeight(jni::JNIEnv&); + void setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionHeightTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionBase(jni::JNIEnv&); + void setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillExtrusionBaseTransition(jni::JNIEnv&); + + jni::Local> getFillExtrusionVerticalGradient(jni::JNIEnv&); + +}; // class FillExtrusionLayer + +class FillExtrusionJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillExtrusionLayerFactory { +public: + ~FillExtrusionJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class FillExtrusionJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp new file mode 100644 index 000000000..6a646fdc7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp @@ -0,0 +1,207 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "fill_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::FillLayer& toFillLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + FillLayer::FillLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + FillLayer::FillLayer(mbgl::style::FillLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + FillLayer::FillLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + FillLayer::~FillLayer() = default; + + // Property getters + + jni::Local> FillLayer::getFillSortKey(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillSortKey())); + } + + jni::Local> FillLayer::getFillAntialias(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillAntialias())); + } + + jni::Local> FillLayer::getFillOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillOpacity())); + } + + jni::Local> FillLayer::getFillOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillOpacityTransition(options); + } + + jni::Local> FillLayer::getFillColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillColor())); + } + + jni::Local> FillLayer::getFillColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillColorTransition(options); + } + + jni::Local> FillLayer::getFillOutlineColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillOutlineColor())); + } + + jni::Local> FillLayer::getFillOutlineColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillOutlineColorTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillOutlineColorTransition(options); + } + + jni::Local> FillLayer::getFillTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillTranslate())); + } + + jni::Local> FillLayer::getFillTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillTranslateTransition(options); + } + + jni::Local> FillLayer::getFillTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillTranslateAnchor())); + } + + jni::Local> FillLayer::getFillPattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toFillLayer(layer).getFillPattern())); + } + + jni::Local> FillLayer::getFillPatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toFillLayer(layer).getFillPatternTransition(); + return std::move(*convert>>(env, options)); + } + + void FillLayer::setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toFillLayer(layer).setFillPatternTransition(options); + } + + + // FillJavaLayerPeerFactory + + FillJavaLayerPeerFactory::~FillJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new FillLayer(toFillLayer(layer))); + } + + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new FillLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void FillJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FillLayer::getFillSortKey, "nativeGetFillSortKey"), + METHOD(&FillLayer::getFillAntialias, "nativeGetFillAntialias"), + METHOD(&FillLayer::getFillOpacityTransition, "nativeGetFillOpacityTransition"), + METHOD(&FillLayer::setFillOpacityTransition, "nativeSetFillOpacityTransition"), + METHOD(&FillLayer::getFillOpacity, "nativeGetFillOpacity"), + METHOD(&FillLayer::getFillColorTransition, "nativeGetFillColorTransition"), + METHOD(&FillLayer::setFillColorTransition, "nativeSetFillColorTransition"), + METHOD(&FillLayer::getFillColor, "nativeGetFillColor"), + METHOD(&FillLayer::getFillOutlineColorTransition, "nativeGetFillOutlineColorTransition"), + METHOD(&FillLayer::setFillOutlineColorTransition, "nativeSetFillOutlineColorTransition"), + METHOD(&FillLayer::getFillOutlineColor, "nativeGetFillOutlineColor"), + METHOD(&FillLayer::getFillTranslateTransition, "nativeGetFillTranslateTransition"), + METHOD(&FillLayer::setFillTranslateTransition, "nativeSetFillTranslateTransition"), + METHOD(&FillLayer::getFillTranslate, "nativeGetFillTranslate"), + METHOD(&FillLayer::getFillTranslateAnchor, "nativeGetFillTranslateAnchor"), + METHOD(&FillLayer::getFillPatternTransition, "nativeGetFillPatternTransition"), + METHOD(&FillLayer::setFillPatternTransition, "nativeSetFillPatternTransition"), + METHOD(&FillLayer::getFillPattern, "nativeGetFillPattern")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp new file mode 100644 index 000000000..807b939a7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp @@ -0,0 +1,72 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class FillLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillLayer"; }; + + FillLayer(jni::JNIEnv&, jni::String&, jni::String&); + + FillLayer(mbgl::style::FillLayer&); + + FillLayer(std::unique_ptr); + + ~FillLayer(); + + // Properties + + jni::Local> getFillSortKey(jni::JNIEnv&); + + jni::Local> getFillAntialias(jni::JNIEnv&); + + jni::Local> getFillOpacity(jni::JNIEnv&); + void setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillOpacityTransition(jni::JNIEnv&); + + jni::Local> getFillColor(jni::JNIEnv&); + void setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillColorTransition(jni::JNIEnv&); + + jni::Local> getFillOutlineColor(jni::JNIEnv&); + void setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillOutlineColorTransition(jni::JNIEnv&); + + jni::Local> getFillTranslate(jni::JNIEnv&); + void setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillTranslateTransition(jni::JNIEnv&); + + jni::Local> getFillTranslateAnchor(jni::JNIEnv&); + + jni::Local> getFillPattern(jni::JNIEnv&); + void setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getFillPatternTransition(jni::JNIEnv&); + +}; // class FillLayer + +class FillJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::FillLayerFactory { +public: + ~FillJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class FillJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp new file mode 100644 index 000000000..dad3d25e6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp @@ -0,0 +1,163 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "heatmap_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::HeatmapLayer& toHeatmapLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HeatmapLayer::HeatmapLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HeatmapLayer::HeatmapLayer(mbgl::style::HeatmapLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HeatmapLayer::HeatmapLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + HeatmapLayer::~HeatmapLayer() = default; + + // Property getters + + jni::Local> HeatmapLayer::getHeatmapRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapRadius())); + } + + jni::Local> HeatmapLayer::getHeatmapRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapRadiusTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapRadiusTransition(options); + } + + jni::Local> HeatmapLayer::getHeatmapWeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapWeight())); + } + + jni::Local> HeatmapLayer::getHeatmapIntensity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapIntensity())); + } + + jni::Local> HeatmapLayer::getHeatmapIntensityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapIntensityTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapIntensityTransition(options); + } + + jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = toHeatmapLayer(layer).getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = toHeatmapLayer(layer).getDefaultHeatmapColor(); + } + return std::move(*convert>>(env, propertyValue)); + } + + jni::Local> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHeatmapLayer(layer).getHeatmapOpacity())); + } + + jni::Local> HeatmapLayer::getHeatmapOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHeatmapLayer(layer).getHeatmapOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void HeatmapLayer::setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHeatmapLayer(layer).setHeatmapOpacityTransition(options); + } + + + // HeatmapJavaLayerPeerFactory + + HeatmapJavaLayerPeerFactory::~HeatmapJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HeatmapLayer(toHeatmapLayer(layer))); + } + + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new HeatmapLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void HeatmapJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&HeatmapLayer::getHeatmapRadiusTransition, "nativeGetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::setHeatmapRadiusTransition, "nativeSetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::getHeatmapRadius, "nativeGetHeatmapRadius"), + METHOD(&HeatmapLayer::getHeatmapWeight, "nativeGetHeatmapWeight"), + METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), + METHOD(&HeatmapLayer::getHeatmapColor, "nativeGetHeatmapColor"), + METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp new file mode 100644 index 000000000..f56e3eb4a --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp @@ -0,0 +1,62 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class HeatmapLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HeatmapLayer"; }; + + HeatmapLayer(jni::JNIEnv&, jni::String&, jni::String&); + + HeatmapLayer(mbgl::style::HeatmapLayer&); + + HeatmapLayer(std::unique_ptr); + + ~HeatmapLayer(); + + // Properties + + jni::Local> getHeatmapRadius(jni::JNIEnv&); + void setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapRadiusTransition(jni::JNIEnv&); + + jni::Local> getHeatmapWeight(jni::JNIEnv&); + + jni::Local> getHeatmapIntensity(jni::JNIEnv&); + void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapIntensityTransition(jni::JNIEnv&); + + jni::Local> getHeatmapColor(jni::JNIEnv&); + + jni::Local> getHeatmapOpacity(jni::JNIEnv&); + void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHeatmapOpacityTransition(jni::JNIEnv&); + +}; // class HeatmapLayer + +class HeatmapJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HeatmapLayerFactory { +public: + ~HeatmapJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class HeatmapJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp new file mode 100644 index 000000000..1f5fe1912 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp @@ -0,0 +1,181 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "hillshade_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::HillshadeLayer& toHillshadeLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HillshadeLayer::HillshadeLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HillshadeLayer::HillshadeLayer(mbgl::style::HillshadeLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HillshadeLayer::HillshadeLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) {} + + HillshadeLayer::~HillshadeLayer() = default; + + // Property getters + + jni::Local> HillshadeLayer::getHillshadeIlluminationDirection(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationDirection())); + } + + jni::Local> HillshadeLayer::getHillshadeIlluminationAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeIlluminationAnchor())); + } + + jni::Local> HillshadeLayer::getHillshadeExaggeration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeExaggeration())); + } + + jni::Local> HillshadeLayer::getHillshadeExaggerationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeExaggerationTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeExaggerationTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeShadowColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeShadowColor())); + } + + jni::Local> HillshadeLayer::getHillshadeShadowColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeShadowColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeShadowColorTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeHighlightColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeHighlightColor())); + } + + jni::Local> HillshadeLayer::getHillshadeHighlightColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeHighlightColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeHighlightColorTransition(options); + } + + jni::Local> HillshadeLayer::getHillshadeAccentColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toHillshadeLayer(layer).getHillshadeAccentColor())); + } + + jni::Local> HillshadeLayer::getHillshadeAccentColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toHillshadeLayer(layer).getHillshadeAccentColorTransition(); + return std::move(*convert>>(env, options)); + } + + void HillshadeLayer::setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toHillshadeLayer(layer).setHillshadeAccentColorTransition(options); + } + + + // HillshadeJavaLayerPeerFactory + + HillshadeJavaLayerPeerFactory::~HillshadeJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new HillshadeLayer(toHillshadeLayer(layer))); + } + + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new HillshadeLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void HillshadeJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&HillshadeLayer::getHillshadeIlluminationDirection, "nativeGetHillshadeIlluminationDirection"), + METHOD(&HillshadeLayer::getHillshadeIlluminationAnchor, "nativeGetHillshadeIlluminationAnchor"), + METHOD(&HillshadeLayer::getHillshadeExaggerationTransition, "nativeGetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::setHillshadeExaggerationTransition, "nativeSetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::getHillshadeExaggeration, "nativeGetHillshadeExaggeration"), + METHOD(&HillshadeLayer::getHillshadeShadowColorTransition, "nativeGetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::setHillshadeShadowColorTransition, "nativeSetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::getHillshadeShadowColor, "nativeGetHillshadeShadowColor"), + METHOD(&HillshadeLayer::getHillshadeHighlightColorTransition, "nativeGetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::setHillshadeHighlightColorTransition, "nativeSetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::getHillshadeHighlightColor, "nativeGetHillshadeHighlightColor"), + METHOD(&HillshadeLayer::getHillshadeAccentColorTransition, "nativeGetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::setHillshadeAccentColorTransition, "nativeSetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::getHillshadeAccentColor, "nativeGetHillshadeAccentColor")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp new file mode 100644 index 000000000..bc210a998 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp @@ -0,0 +1,66 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class HillshadeLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HillshadeLayer"; }; + + HillshadeLayer(jni::JNIEnv&, jni::String&, jni::String&); + + HillshadeLayer(mbgl::style::HillshadeLayer&); + + HillshadeLayer(std::unique_ptr); + + ~HillshadeLayer(); + + // Properties + + jni::Local> getHillshadeIlluminationDirection(jni::JNIEnv&); + + jni::Local> getHillshadeIlluminationAnchor(jni::JNIEnv&); + + jni::Local> getHillshadeExaggeration(jni::JNIEnv&); + void setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeExaggerationTransition(jni::JNIEnv&); + + jni::Local> getHillshadeShadowColor(jni::JNIEnv&); + void setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeShadowColorTransition(jni::JNIEnv&); + + jni::Local> getHillshadeHighlightColor(jni::JNIEnv&); + void setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeHighlightColorTransition(jni::JNIEnv&); + + jni::Local> getHillshadeAccentColor(jni::JNIEnv&); + void setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getHillshadeAccentColorTransition(jni::JNIEnv&); + +}; // class HillshadeLayer + +class HillshadeJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::HillshadeLayerFactory { +public: + ~HillshadeJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class HillshadeJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp new file mode 100644 index 000000000..bc87a9d9b --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp @@ -0,0 +1,178 @@ +#include "layer.hpp" +#include "../android_conversion.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Java -> C++ conversion +#include +#include +#include +#include + +// C++ -> Java conversion +#include "../conversion/property_value.hpp" +#include "custom_layer.hpp" +#include "background_layer.hpp" +#include + +#include + +namespace mbgl { +namespace android { + + /** + * Invoked when the construction is initiated from the jvm through a subclass + */ + Layer::Layer(std::unique_ptr coreLayer) + : ownedLayer(std::move(coreLayer)) + , layer(*ownedLayer) { + } + + /** + * Takes a non-owning reference. For lookup methods + */ + Layer::Layer(mbgl::style::Layer& coreLayer) : layer(coreLayer) {} + + Layer::~Layer() { + } + + void Layer::addToStyle(mbgl::style::Style& style, mbgl::optional before) { + // Check to see if we own the layer first + if (!ownedLayer) { + throw std::runtime_error("Cannot add layer twice"); + } + + // Add layer to map + style.addLayer(releaseCoreLayer(), before); + } + + void Layer::setLayer(std::unique_ptr sourceLayer) { + this->ownedLayer = std::move(sourceLayer); + } + + std::unique_ptr Layer::releaseCoreLayer() { + assert(ownedLayer != nullptr); + return std::move(ownedLayer); + } + + jni::Local Layer::getId(jni::JNIEnv& env) { + return jni::Make(env, layer.getID()); + } + + style::Layer& Layer::get() { + return layer; + } + + void Layer::setProperty(jni::JNIEnv& env, const jni::String& jname, const jni::Object<>& jvalue) { + // Convert and set property + optional error = + layer.setProperty(jni::Make(env, jname), Value(env, jvalue)); + if (error) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); + return; + } + } + + void Layer::setFilter(jni::JNIEnv& env, const jni::Array>& jfilter) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Error error; + optional converted = convert(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message); + return; + } + + layer.setFilter(std::move(*converted)); + } + + jni::Local> Layer::getFilter(jni::JNIEnv& env) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Filter filter = layer.getFilter(); + if (filter.expression) { + mbgl::Value expressionValue = (*filter.expression)->serialize(); + return gson::JsonElement::New(env, expressionValue); + } else { + return jni::Local>(env, nullptr); + } + } + + void Layer::setSourceLayer(jni::JNIEnv& env, const jni::String& sourceLayer) { + layer.setSourceLayer(jni::Make(env, sourceLayer)); + } + + jni::Local Layer::getSourceLayer(jni::JNIEnv& env) { + return jni::Make(env, layer.getSourceLayer()); + } + + jni::Local Layer::getSourceId(jni::JNIEnv& env) { + return jni::Make(env, layer.getSourceID()); + } + + jni::jfloat Layer::getMinZoom(jni::JNIEnv&){ + return layer.getMinZoom(); + } + + jni::jfloat Layer::getMaxZoom(jni::JNIEnv&) { + return layer.getMaxZoom(); + } + + void Layer::setMinZoom(jni::JNIEnv&, jni::jfloat zoom) { + layer.setMinZoom(zoom); + } + + void Layer::setMaxZoom(jni::JNIEnv&, jni::jfloat zoom) { + layer.setMaxZoom(zoom); + } + + jni::Local> Layer::getVisibility(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, layer.getVisibility())); + } + + void Layer::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + METHOD(&Layer::getId, "nativeGetId"), + METHOD(&Layer::setProperty, + "nativeSetLayoutProperty"), // TODO : Export only nativeSetProperty() when #15970 lands. + METHOD(&Layer::setProperty, "nativeSetPaintProperty"), + METHOD(&Layer::setFilter, "nativeSetFilter"), + METHOD(&Layer::getFilter, "nativeGetFilter"), + METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"), + METHOD(&Layer::getSourceLayer, "nativeGetSourceLayer"), + METHOD(&Layer::getSourceId, "nativeGetSourceId"), + METHOD(&Layer::getMinZoom, "nativeGetMinZoom"), + METHOD(&Layer::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&Layer::setMinZoom, "nativeSetMinZoom"), + METHOD(&Layer::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&Layer::getVisibility, "nativeGetVisibility")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs new file mode 100644 index 000000000..5d241e9a3 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs @@ -0,0 +1,139 @@ +<% + const type = locals.type; + const properties = locals.properties; +-%> +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "<%- type.replace('-', '_') %>_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::<%- camelize(type) %>Layer& to<%- camelize(type) %>Layer(mbgl::style::Layer& layer) { + return static_castLayer&>(layer); + } + +<% if (type === 'background') { -%> + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId) + : Layer(std::make_uniqueLayer>(jni::Make(env, layerId))) { +<% } else { -%> + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_uniqueLayer>(jni::Make(env, layerId), jni::Make(env, sourceId))) { +<% } -%> + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::style::<%- camelize(type) %>Layer& coreLayer) + : Layer(coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(std::unique_ptrLayer> coreLayer) + : Layer(std::move(coreLayer)) { + } + + <%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; + + // Property getters + +<% for (const property of properties) { -%> +<% if (property.name != 'heatmap-color') { -%> + jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>())); + } + +<% } else { -%> + jni::Local> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = to<%- camelize(type) %>Layer(layer).getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = to<%- camelize(type) %>Layer(layer).getDefaultHeatmapColor(); + } + return std::move(*convert>>(env, propertyValue)); + } + +<% } -%> +<% if (property.transition) { -%> + jni::Local> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = to<%- camelize(type) %>Layer(layer).get<%- camelize(property.name) %>Transition(); + return std::move(*convert>>(env, options)); + } + + void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + to<%- camelize(type) %>Layer(layer).set<%- camelize(property.name) %>Transition(options); + } + +<% } -%> +<% } -%> + + // <%- camelize(type) %>JavaLayerPeerFactory + + <%- camelize(type) %>JavaLayerPeerFactory::~<%- camelize(type) %>JavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new <%- camelize(type) %>Layer(to<%- camelize(type) %>Layer(layer))); + } + + jni::Local> <%- camelize(type) %>JavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new <%- camelize(type) %>Layer(std::unique_ptrLayer>(static_castLayer*>(layer.release())))); + } + + void <%- camelize(type) %>JavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class<<%- camelize(type) %>Layer>::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer<<%- camelize(type) %>Layer>( + env, + javaClass, + "nativePtr", +<% if (type === 'background') { -%> + jni::MakePeer<<%- camelize(type) %>Layer, jni::String&>, +<% } else { -%> + jni::MakePeer<<%- camelize(type) %>Layer, jni::String&, jni::String&>, +<% } -%> + "initialize", + "finalize",<% for(var i = 0; i < properties.length; i++) {%> +<% if (properties[i].transition) { -%> + METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"), + METHOD(&<%- camelize(type) %>Layer::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"), +<% } -%> + METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp new file mode 100644 index 000000000..557990844 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include +#include "../../gson/json_array.hpp" +#include "../../gson/json_element.hpp" +#include "../value.hpp" + +#include + +namespace mbgl { + +namespace android { + +class Layer { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/Layer"; }; + + static void registerNative(jni::JNIEnv&); + + virtual ~Layer(); + + /** + * Set core layer (ie return ownership after remove) + */ + void setLayer(std::unique_ptr); + + void addToStyle(mbgl::style::Style&, mbgl::optional); + + // Release the owned view and return it + std::unique_ptr releaseCoreLayer(); + + jni::Local getId(jni::JNIEnv&); + + jni::Local getSourceId(jni::JNIEnv&); + + style::Layer& get(); + + void setProperty(jni::JNIEnv&, const jni::String&, const jni::Object<>& value); + + // Zoom + + jni::jfloat getMinZoom(jni::JNIEnv&); + + jni::jfloat getMaxZoom(jni::JNIEnv&); + + void setMinZoom(jni::JNIEnv&, jni::jfloat zoom); + + void setMaxZoom(jni::JNIEnv&, jni::jfloat zoom); + + /* common properties, but not shared by all */ + + void setFilter(jni::JNIEnv&, const jni::Array>&); + + jni::Local> getFilter(jni::JNIEnv&); + + void setSourceLayer(jni::JNIEnv&, const jni::String&); + + jni::Local getSourceLayer(jni::JNIEnv&); + + // Property getters + + jni::Local> getVisibility(jni::JNIEnv&); + +protected: + /* + * Called when a non-owning peer object is created on the c++ side + */ + Layer(mbgl::style::Layer&); + + /* + * Called when a owning peer object is created on the c++ side + */ + Layer(std::unique_ptr); + + // Owned layer is set when creating a new layer, before adding it to the map + std::unique_ptr ownedLayer; + + // Raw reference to the layer + mbgl::style::Layer& layer; +}; + +/** + * @brief A factory class for a layer Java peer objects of a certain type. + */ +class JavaLayerPeerFactory { +public: + virtual ~JavaLayerPeerFactory() = default; + /** + * @brief Create a non-owning peer. + */ + virtual jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) = 0; + + /** + * @brief Create an owning peer. + */ + virtual jni::Local> createJavaLayerPeer(jni::JNIEnv& env, + std::unique_ptr) = 0; + + /** + * @brief Register peer methods. + */ + virtual void registerNative(jni::JNIEnv&) = 0; + + /** + * @brief Get the corresponding layer factory. + * + * @return style::LayerFactory* must not be \c nullptr. + */ + virtual LayerFactory* getLayerFactory() = 0; +}; + + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs new file mode 100644 index 000000000..eb8db0620 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs @@ -0,0 +1,62 @@ +<% + const type = locals.type; + const properties = locals.properties; +-%> +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include _layer_factory.hpp> +#include _layer.hpp> +#include + +namespace mbgl { +namespace android { + +class <%- camelize(type) %>Layer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; }; + +<% if (type === 'background') { -%> + <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&); +<% } else { -%> + <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&, jni::String&); +<% } -%> + + <%- camelize(type) %>Layer(mbgl::style::<%- camelize(type) %>Layer&); + + <%- camelize(type) %>Layer(std::unique_ptrLayer>); + + ~<%- camelize(type) %>Layer(); + + // Properties +<% for (const property of properties) { -%> + + jni::Local> get<%- camelize(property.name) %>(jni::JNIEnv&); +<% if (property.transition) { -%> + void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> get<%- camelize(property.name) %>Transition(jni::JNIEnv&); +<% } -%> +<% } -%> + +}; // class <%- camelize(type) %>Layer + +class <%- camelize(type) %>JavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::<%- camelize(type) %>LayerFactory { +public: + ~<%- camelize(type) %>JavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class <%- camelize(type) %>JavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp new file mode 100644 index 000000000..2d4172a23 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp @@ -0,0 +1,173 @@ +#include "layer_manager.hpp" + +#include + +#include +#include +#include + +#include "background_layer.hpp" +#include "circle_layer.hpp" +#include "custom_layer.hpp" +#include "fill_extrusion_layer.hpp" +#include "fill_layer.hpp" +#include "heatmap_layer.hpp" +#include "hillshade_layer.hpp" +#include "line_layer.hpp" +#include "raster_layer.hpp" +#include "symbol_layer.hpp" +#include "fill_extrusion_layer.hpp" + +namespace mbgl { + +namespace android { + +LayerManagerAndroid::LayerManagerAndroid() { +#if defined(MBGL_LAYER_FILL_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_FILL_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_LINE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_LINE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_CIRCLE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_CIRCLE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_SYMBOL_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_RASTER_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_RASTER_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_BACKGROUND_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_BACKGROUND_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_HILLSHADE_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_HILLSHADE_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_FILL_EXTRUSION_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_HEATMAP_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_HEATMAP_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +#if defined(MBGL_LAYER_CUSTOM_DISABLE_RUNTIME) + addLayerTypeCoreOnly(std::make_unique()); +#elif !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif +} + +LayerManagerAndroid::~LayerManagerAndroid() = default; + +jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { + if (JavaLayerPeerFactory* factory = getPeerFactory(layer.getTypeInfo())) { + return factory->createJavaLayerPeer(env, layer); + } + return jni::Local>(); +} + +jni::Local> LayerManagerAndroid::createJavaLayerPeer(jni::JNIEnv& env, + std::unique_ptr layer) { + if (JavaLayerPeerFactory* factory = getPeerFactory(layer->getTypeInfo())) { + return factory->createJavaLayerPeer(env, std::move(layer)); + } + return jni::Local>(); +} + +void LayerManagerAndroid::registerNative(jni::JNIEnv& env) { + if (peerFactories.empty()) { + return; + } + + Layer::registerNative(env); + for (const auto& factory: peerFactories) { + factory->registerNative(env); + } +} + +void LayerManagerAndroid::addLayerType(std::unique_ptr factory) { + assert(getFactory(factory->getLayerFactory()->getTypeInfo()) == nullptr); + registerCoreFactory(factory->getLayerFactory()); + peerFactories.emplace_back(std::move(factory)); +} + +void LayerManagerAndroid::addLayerTypeCoreOnly(std::unique_ptr factory) { + assert(getFactory(factory->getTypeInfo()) == nullptr); + registerCoreFactory(factory.get()); + coreFactories.emplace_back(std::move(factory)); +} + +void LayerManagerAndroid::registerCoreFactory(mbgl::LayerFactory* factory) { + std::string type{factory->getTypeInfo()->type}; + if (!type.empty()) { + assert(typeToFactory.find(type) == typeToFactory.end()); + typeToFactory.emplace(std::make_pair(std::move(type), factory)); + } +} + +JavaLayerPeerFactory* LayerManagerAndroid::getPeerFactory(const mbgl::style::LayerTypeInfo* typeInfo) { + assert(typeInfo); + for (const auto& factory: peerFactories) { + if (factory->getLayerFactory()->getTypeInfo() == typeInfo) { + return factory.get(); + } + } + return nullptr; +} + +LayerFactory* LayerManagerAndroid::getFactory(const std::string& type) noexcept { + auto search = typeToFactory.find(type); + return (search != typeToFactory.end()) ? search->second : nullptr; +} + +LayerFactory* LayerManagerAndroid::getFactory(const mbgl::style::LayerTypeInfo* info) noexcept { + if (JavaLayerPeerFactory* peerFactory = getPeerFactory(info)) { + return peerFactory->getLayerFactory(); + } + + for (const auto& factory: coreFactories) { + if (factory->getTypeInfo() == info) { + return factory.get(); + } + } + + return nullptr; +} + +// static +LayerManagerAndroid* LayerManagerAndroid::get() noexcept { + static LayerManagerAndroid impl; + return &impl; +} + +} // namespace android + +LayerManager* LayerManager::get() noexcept { + return android::LayerManagerAndroid::get(); +} + +#if defined(MBGL_LAYER_LINE_DISABLE_ALL) || defined(MBGL_LAYER_SYMBOL_DISABLE_ALL) || defined(MBGL_LAYER_FILL_DISABLE_ALL) +const bool LayerManager::annotationsEnabled = false; +#else +const bool LayerManager::annotationsEnabled = true; +#endif + +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.hpp new file mode 100644 index 000000000..f7379f6de --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include "layer.hpp" + +#include + +#include +#include + +namespace mbgl { +namespace android { + +/** + * @brief A singleton class forwarding calls to the corresponding \c JavaLayerPeerFactory instance. + */ +class LayerManagerAndroid final : public mbgl::LayerManager { +public: + ~LayerManagerAndroid() final; + static LayerManagerAndroid* get() noexcept; + + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&); + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr); + + void registerNative(jni::JNIEnv&); + +private: + LayerManagerAndroid(); + /** + * @brief Enables a layer type for both JSON style and runtime API. + */ + void addLayerType(std::unique_ptr); + /** + * @brief Enables a layer type for JSON style only. + * + * We might not want to expose runtime API for some layer types + * in order to save binary size - JNI glue code for these layer types + * won't be added to the binary. + */ + void addLayerTypeCoreOnly(std::unique_ptr); + + void registerCoreFactory(mbgl::LayerFactory*); + JavaLayerPeerFactory* getPeerFactory(const mbgl::style::LayerTypeInfo*); + // mbgl::LayerManager overrides. + LayerFactory* getFactory(const std::string& type) noexcept final; + LayerFactory* getFactory(const mbgl::style::LayerTypeInfo* info) noexcept final; + + std::vector> peerFactories; + std::vector> coreFactories; + std::map typeToFactory; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp new file mode 100644 index 000000000..89c6cb532 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp @@ -0,0 +1,315 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "line_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::LineLayer& toLineLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + LineLayer::LineLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + LineLayer::LineLayer(mbgl::style::LineLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + LineLayer::LineLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + LineLayer::~LineLayer() = default; + + // Property getters + + jni::Local> LineLayer::getLineCap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineCap())); + } + + jni::Local> LineLayer::getLineJoin(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineJoin())); + } + + jni::Local> LineLayer::getLineMiterLimit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineMiterLimit())); + } + + jni::Local> LineLayer::getLineRoundLimit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineRoundLimit())); + } + + jni::Local> LineLayer::getLineSortKey(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineSortKey())); + } + + jni::Local> LineLayer::getLineOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineOpacity())); + } + + jni::Local> LineLayer::getLineOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineOpacityTransition(options); + } + + jni::Local> LineLayer::getLineColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineColor())); + } + + jni::Local> LineLayer::getLineColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineColorTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineColorTransition(options); + } + + jni::Local> LineLayer::getLineTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineTranslate())); + } + + jni::Local> LineLayer::getLineTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineTranslateTransition(options); + } + + jni::Local> LineLayer::getLineTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineTranslateAnchor())); + } + + jni::Local> LineLayer::getLineWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineWidth())); + } + + jni::Local> LineLayer::getLineWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineWidthTransition(options); + } + + jni::Local> LineLayer::getLineGapWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineGapWidth())); + } + + jni::Local> LineLayer::getLineGapWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineGapWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineGapWidthTransition(options); + } + + jni::Local> LineLayer::getLineOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineOffset())); + } + + jni::Local> LineLayer::getLineOffsetTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineOffsetTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineOffsetTransition(options); + } + + jni::Local> LineLayer::getLineBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineBlur())); + } + + jni::Local> LineLayer::getLineBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineBlurTransition(options); + } + + jni::Local> LineLayer::getLineDasharray(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineDasharray())); + } + + jni::Local> LineLayer::getLineDasharrayTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLineDasharrayTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLineDasharrayTransition(options); + } + + jni::Local> LineLayer::getLinePattern(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLinePattern())); + } + + jni::Local> LineLayer::getLinePatternTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLineLayer(layer).getLinePatternTransition(); + return std::move(*convert>>(env, options)); + } + + void LineLayer::setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLineLayer(layer).setLinePatternTransition(options); + } + + jni::Local> LineLayer::getLineGradient(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLineLayer(layer).getLineGradient())); + } + + + // LineJavaLayerPeerFactory + + LineJavaLayerPeerFactory::~LineJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new LineLayer(toLineLayer(layer))); + } + + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new LineLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void LineJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&LineLayer::getLineCap, "nativeGetLineCap"), + METHOD(&LineLayer::getLineJoin, "nativeGetLineJoin"), + METHOD(&LineLayer::getLineMiterLimit, "nativeGetLineMiterLimit"), + METHOD(&LineLayer::getLineRoundLimit, "nativeGetLineRoundLimit"), + METHOD(&LineLayer::getLineSortKey, "nativeGetLineSortKey"), + METHOD(&LineLayer::getLineOpacityTransition, "nativeGetLineOpacityTransition"), + METHOD(&LineLayer::setLineOpacityTransition, "nativeSetLineOpacityTransition"), + METHOD(&LineLayer::getLineOpacity, "nativeGetLineOpacity"), + METHOD(&LineLayer::getLineColorTransition, "nativeGetLineColorTransition"), + METHOD(&LineLayer::setLineColorTransition, "nativeSetLineColorTransition"), + METHOD(&LineLayer::getLineColor, "nativeGetLineColor"), + METHOD(&LineLayer::getLineTranslateTransition, "nativeGetLineTranslateTransition"), + METHOD(&LineLayer::setLineTranslateTransition, "nativeSetLineTranslateTransition"), + METHOD(&LineLayer::getLineTranslate, "nativeGetLineTranslate"), + METHOD(&LineLayer::getLineTranslateAnchor, "nativeGetLineTranslateAnchor"), + METHOD(&LineLayer::getLineWidthTransition, "nativeGetLineWidthTransition"), + METHOD(&LineLayer::setLineWidthTransition, "nativeSetLineWidthTransition"), + METHOD(&LineLayer::getLineWidth, "nativeGetLineWidth"), + METHOD(&LineLayer::getLineGapWidthTransition, "nativeGetLineGapWidthTransition"), + METHOD(&LineLayer::setLineGapWidthTransition, "nativeSetLineGapWidthTransition"), + METHOD(&LineLayer::getLineGapWidth, "nativeGetLineGapWidth"), + METHOD(&LineLayer::getLineOffsetTransition, "nativeGetLineOffsetTransition"), + METHOD(&LineLayer::setLineOffsetTransition, "nativeSetLineOffsetTransition"), + METHOD(&LineLayer::getLineOffset, "nativeGetLineOffset"), + METHOD(&LineLayer::getLineBlurTransition, "nativeGetLineBlurTransition"), + METHOD(&LineLayer::setLineBlurTransition, "nativeSetLineBlurTransition"), + METHOD(&LineLayer::getLineBlur, "nativeGetLineBlur"), + METHOD(&LineLayer::getLineDasharrayTransition, "nativeGetLineDasharrayTransition"), + METHOD(&LineLayer::setLineDasharrayTransition, "nativeSetLineDasharrayTransition"), + METHOD(&LineLayer::getLineDasharray, "nativeGetLineDasharray"), + METHOD(&LineLayer::getLinePatternTransition, "nativeGetLinePatternTransition"), + METHOD(&LineLayer::setLinePatternTransition, "nativeSetLinePatternTransition"), + METHOD(&LineLayer::getLinePattern, "nativeGetLinePattern"), + METHOD(&LineLayer::getLineGradient, "nativeGetLineGradient")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp new file mode 100644 index 000000000..25b270fbc --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp @@ -0,0 +1,96 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class LineLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LineLayer"; }; + + LineLayer(jni::JNIEnv&, jni::String&, jni::String&); + + LineLayer(mbgl::style::LineLayer&); + + LineLayer(std::unique_ptr); + + ~LineLayer(); + + // Properties + + jni::Local> getLineCap(jni::JNIEnv&); + + jni::Local> getLineJoin(jni::JNIEnv&); + + jni::Local> getLineMiterLimit(jni::JNIEnv&); + + jni::Local> getLineRoundLimit(jni::JNIEnv&); + + jni::Local> getLineSortKey(jni::JNIEnv&); + + jni::Local> getLineOpacity(jni::JNIEnv&); + void setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineOpacityTransition(jni::JNIEnv&); + + jni::Local> getLineColor(jni::JNIEnv&); + void setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineColorTransition(jni::JNIEnv&); + + jni::Local> getLineTranslate(jni::JNIEnv&); + void setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineTranslateTransition(jni::JNIEnv&); + + jni::Local> getLineTranslateAnchor(jni::JNIEnv&); + + jni::Local> getLineWidth(jni::JNIEnv&); + void setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineWidthTransition(jni::JNIEnv&); + + jni::Local> getLineGapWidth(jni::JNIEnv&); + void setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineGapWidthTransition(jni::JNIEnv&); + + jni::Local> getLineOffset(jni::JNIEnv&); + void setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineOffsetTransition(jni::JNIEnv&); + + jni::Local> getLineBlur(jni::JNIEnv&); + void setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineBlurTransition(jni::JNIEnv&); + + jni::Local> getLineDasharray(jni::JNIEnv&); + void setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLineDasharrayTransition(jni::JNIEnv&); + + jni::Local> getLinePattern(jni::JNIEnv&); + void setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLinePatternTransition(jni::JNIEnv&); + + jni::Local> getLineGradient(jni::JNIEnv&); + +}; // class LineLayer + +class LineJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::LineLayerFactory { +public: + ~LineJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class LineJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp new file mode 100644 index 000000000..d9cce949c --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp @@ -0,0 +1,222 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "raster_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::RasterLayer& toRasterLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + RasterLayer::RasterLayer(mbgl::style::RasterLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + RasterLayer::RasterLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + RasterLayer::~RasterLayer() = default; + + // Property getters + + jni::Local> RasterLayer::getRasterOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterOpacity())); + } + + jni::Local> RasterLayer::getRasterOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterOpacityTransition(options); + } + + jni::Local> RasterLayer::getRasterHueRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterHueRotate())); + } + + jni::Local> RasterLayer::getRasterHueRotateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterHueRotateTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterHueRotateTransition(options); + } + + jni::Local> RasterLayer::getRasterBrightnessMin(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMin())); + } + + jni::Local> RasterLayer::getRasterBrightnessMinTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMinTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterBrightnessMinTransition(options); + } + + jni::Local> RasterLayer::getRasterBrightnessMax(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterBrightnessMax())); + } + + jni::Local> RasterLayer::getRasterBrightnessMaxTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterBrightnessMaxTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterBrightnessMaxTransition(options); + } + + jni::Local> RasterLayer::getRasterSaturation(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterSaturation())); + } + + jni::Local> RasterLayer::getRasterSaturationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterSaturationTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterSaturationTransition(options); + } + + jni::Local> RasterLayer::getRasterContrast(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterContrast())); + } + + jni::Local> RasterLayer::getRasterContrastTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toRasterLayer(layer).getRasterContrastTransition(); + return std::move(*convert>>(env, options)); + } + + void RasterLayer::setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toRasterLayer(layer).setRasterContrastTransition(options); + } + + jni::Local> RasterLayer::getRasterResampling(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterResampling())); + } + + jni::Local> RasterLayer::getRasterFadeDuration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toRasterLayer(layer).getRasterFadeDuration())); + } + + + // RasterJavaLayerPeerFactory + + RasterJavaLayerPeerFactory::~RasterJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new RasterLayer(toRasterLayer(layer))); + } + + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new RasterLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void RasterJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&RasterLayer::getRasterOpacityTransition, "nativeGetRasterOpacityTransition"), + METHOD(&RasterLayer::setRasterOpacityTransition, "nativeSetRasterOpacityTransition"), + METHOD(&RasterLayer::getRasterOpacity, "nativeGetRasterOpacity"), + METHOD(&RasterLayer::getRasterHueRotateTransition, "nativeGetRasterHueRotateTransition"), + METHOD(&RasterLayer::setRasterHueRotateTransition, "nativeSetRasterHueRotateTransition"), + METHOD(&RasterLayer::getRasterHueRotate, "nativeGetRasterHueRotate"), + METHOD(&RasterLayer::getRasterBrightnessMinTransition, "nativeGetRasterBrightnessMinTransition"), + METHOD(&RasterLayer::setRasterBrightnessMinTransition, "nativeSetRasterBrightnessMinTransition"), + METHOD(&RasterLayer::getRasterBrightnessMin, "nativeGetRasterBrightnessMin"), + METHOD(&RasterLayer::getRasterBrightnessMaxTransition, "nativeGetRasterBrightnessMaxTransition"), + METHOD(&RasterLayer::setRasterBrightnessMaxTransition, "nativeSetRasterBrightnessMaxTransition"), + METHOD(&RasterLayer::getRasterBrightnessMax, "nativeGetRasterBrightnessMax"), + METHOD(&RasterLayer::getRasterSaturationTransition, "nativeGetRasterSaturationTransition"), + METHOD(&RasterLayer::setRasterSaturationTransition, "nativeSetRasterSaturationTransition"), + METHOD(&RasterLayer::getRasterSaturation, "nativeGetRasterSaturation"), + METHOD(&RasterLayer::getRasterContrastTransition, "nativeGetRasterContrastTransition"), + METHOD(&RasterLayer::setRasterContrastTransition, "nativeSetRasterContrastTransition"), + METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"), + METHOD(&RasterLayer::getRasterResampling, "nativeGetRasterResampling"), + METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp new file mode 100644 index 000000000..bbda2e0c5 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp @@ -0,0 +1,74 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class RasterLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/RasterLayer"; }; + + RasterLayer(jni::JNIEnv&, jni::String&, jni::String&); + + RasterLayer(mbgl::style::RasterLayer&); + + RasterLayer(std::unique_ptr); + + ~RasterLayer(); + + // Properties + + jni::Local> getRasterOpacity(jni::JNIEnv&); + void setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterOpacityTransition(jni::JNIEnv&); + + jni::Local> getRasterHueRotate(jni::JNIEnv&); + void setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterHueRotateTransition(jni::JNIEnv&); + + jni::Local> getRasterBrightnessMin(jni::JNIEnv&); + void setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterBrightnessMinTransition(jni::JNIEnv&); + + jni::Local> getRasterBrightnessMax(jni::JNIEnv&); + void setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterBrightnessMaxTransition(jni::JNIEnv&); + + jni::Local> getRasterSaturation(jni::JNIEnv&); + void setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterSaturationTransition(jni::JNIEnv&); + + jni::Local> getRasterContrast(jni::JNIEnv&); + void setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getRasterContrastTransition(jni::JNIEnv&); + + jni::Local> getRasterResampling(jni::JNIEnv&); + + jni::Local> getRasterFadeDuration(jni::JNIEnv&); + +}; // class RasterLayer + +class RasterJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::RasterLayerFactory { +public: + ~RasterJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class RasterJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp new file mode 100644 index 000000000..f24fb3542 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp @@ -0,0 +1,594 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "symbol_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::SymbolLayer& toSymbolLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String& layerId, jni::String& sourceId) + : Layer(std::make_unique(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + SymbolLayer::SymbolLayer(mbgl::style::SymbolLayer& coreLayer) : Layer(coreLayer) {} + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + SymbolLayer::SymbolLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + + SymbolLayer::~SymbolLayer() = default; + + // Property getters + + jni::Local> SymbolLayer::getSymbolPlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolPlacement())); + } + + jni::Local> SymbolLayer::getSymbolSpacing(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSpacing())); + } + + jni::Local> SymbolLayer::getSymbolAvoidEdges(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolAvoidEdges())); + } + + jni::Local> SymbolLayer::getSymbolSortKey(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolSortKey())); + } + + jni::Local> SymbolLayer::getSymbolZOrder(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getSymbolZOrder())); + } + + jni::Local> SymbolLayer::getIconAllowOverlap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconAllowOverlap())); + } + + jni::Local> SymbolLayer::getIconIgnorePlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconIgnorePlacement())); + } + + jni::Local> SymbolLayer::getIconOptional(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOptional())); + } + + jni::Local> SymbolLayer::getIconRotationAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotationAlignment())); + } + + jni::Local> SymbolLayer::getIconSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconSize())); + } + + jni::Local> SymbolLayer::getIconTextFit(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFit())); + } + + jni::Local> SymbolLayer::getIconTextFitPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTextFitPadding())); + } + + jni::Local> SymbolLayer::getIconImage(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconImage())); + } + + jni::Local> SymbolLayer::getIconRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconRotate())); + } + + jni::Local> SymbolLayer::getIconPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconPadding())); + } + + jni::Local> SymbolLayer::getIconKeepUpright(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconKeepUpright())); + } + + jni::Local> SymbolLayer::getIconOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOffset())); + } + + jni::Local> SymbolLayer::getIconAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconAnchor())); + } + + jni::Local> SymbolLayer::getIconPitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconPitchAlignment())); + } + + jni::Local> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextPitchAlignment())); + } + + jni::Local> SymbolLayer::getTextRotationAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotationAlignment())); + } + + jni::Local> SymbolLayer::getTextField(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextField())); + } + + jni::Local> SymbolLayer::getTextFont(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextFont())); + } + + jni::Local> SymbolLayer::getTextSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextSize())); + } + + jni::Local> SymbolLayer::getTextMaxWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxWidth())); + } + + jni::Local> SymbolLayer::getTextLineHeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextLineHeight())); + } + + jni::Local> SymbolLayer::getTextLetterSpacing(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextLetterSpacing())); + } + + jni::Local> SymbolLayer::getTextJustify(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextJustify())); + } + + jni::Local> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRadialOffset())); + } + + jni::Local> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextVariableAnchor())); + } + + jni::Local> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextAnchor())); + } + + jni::Local> SymbolLayer::getTextMaxAngle(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextMaxAngle())); + } + + jni::Local> SymbolLayer::getTextWritingMode(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextWritingMode())); + } + + jni::Local> SymbolLayer::getTextRotate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextRotate())); + } + + jni::Local> SymbolLayer::getTextPadding(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextPadding())); + } + + jni::Local> SymbolLayer::getTextKeepUpright(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextKeepUpright())); + } + + jni::Local> SymbolLayer::getTextTransform(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTransform())); + } + + jni::Local> SymbolLayer::getTextOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOffset())); + } + + jni::Local> SymbolLayer::getTextAllowOverlap(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextAllowOverlap())); + } + + jni::Local> SymbolLayer::getTextIgnorePlacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextIgnorePlacement())); + } + + jni::Local> SymbolLayer::getTextOptional(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOptional())); + } + + jni::Local> SymbolLayer::getIconOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconOpacity())); + } + + jni::Local> SymbolLayer::getIconOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconOpacityTransition(options); + } + + jni::Local> SymbolLayer::getIconColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconColor())); + } + + jni::Local> SymbolLayer::getIconColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconColorTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloColor())); + } + + jni::Local> SymbolLayer::getIconHaloColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloColorTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloWidth())); + } + + jni::Local> SymbolLayer::getIconHaloWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloWidthTransition(options); + } + + jni::Local> SymbolLayer::getIconHaloBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconHaloBlur())); + } + + jni::Local> SymbolLayer::getIconHaloBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconHaloBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconHaloBlurTransition(options); + } + + jni::Local> SymbolLayer::getIconTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslate())); + } + + jni::Local> SymbolLayer::getIconTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getIconTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setIconTranslateTransition(options); + } + + jni::Local> SymbolLayer::getIconTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getIconTranslateAnchor())); + } + + jni::Local> SymbolLayer::getTextOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextOpacity())); + } + + jni::Local> SymbolLayer::getTextOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextOpacityTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextOpacityTransition(options); + } + + jni::Local> SymbolLayer::getTextColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextColor())); + } + + jni::Local> SymbolLayer::getTextColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextColorTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloColor())); + } + + jni::Local> SymbolLayer::getTextHaloColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloColorTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloColorTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloWidth(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloWidth())); + } + + jni::Local> SymbolLayer::getTextHaloWidthTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloWidthTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloWidthTransition(options); + } + + jni::Local> SymbolLayer::getTextHaloBlur(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextHaloBlur())); + } + + jni::Local> SymbolLayer::getTextHaloBlurTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextHaloBlurTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextHaloBlurTransition(options); + } + + jni::Local> SymbolLayer::getTextTranslate(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslate())); + } + + jni::Local> SymbolLayer::getTextTranslateTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toSymbolLayer(layer).getTextTranslateTransition(); + return std::move(*convert>>(env, options)); + } + + void SymbolLayer::setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toSymbolLayer(layer).setTextTranslateTransition(options); + } + + jni::Local> SymbolLayer::getTextTranslateAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toSymbolLayer(layer).getTextTranslateAnchor())); + } + + + // SymbolJavaLayerPeerFactory + + SymbolJavaLayerPeerFactory::~SymbolJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, + mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new SymbolLayer(toSymbolLayer(layer))); + } + + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer( + jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, + new SymbolLayer(std::unique_ptr( + static_cast(layer.release())))); + } + + void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&SymbolLayer::getSymbolPlacement, "nativeGetSymbolPlacement"), + METHOD(&SymbolLayer::getSymbolSpacing, "nativeGetSymbolSpacing"), + METHOD(&SymbolLayer::getSymbolAvoidEdges, "nativeGetSymbolAvoidEdges"), + METHOD(&SymbolLayer::getSymbolSortKey, "nativeGetSymbolSortKey"), + METHOD(&SymbolLayer::getSymbolZOrder, "nativeGetSymbolZOrder"), + METHOD(&SymbolLayer::getIconAllowOverlap, "nativeGetIconAllowOverlap"), + METHOD(&SymbolLayer::getIconIgnorePlacement, "nativeGetIconIgnorePlacement"), + METHOD(&SymbolLayer::getIconOptional, "nativeGetIconOptional"), + METHOD(&SymbolLayer::getIconRotationAlignment, "nativeGetIconRotationAlignment"), + METHOD(&SymbolLayer::getIconSize, "nativeGetIconSize"), + METHOD(&SymbolLayer::getIconTextFit, "nativeGetIconTextFit"), + METHOD(&SymbolLayer::getIconTextFitPadding, "nativeGetIconTextFitPadding"), + METHOD(&SymbolLayer::getIconImage, "nativeGetIconImage"), + METHOD(&SymbolLayer::getIconRotate, "nativeGetIconRotate"), + METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"), + METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"), + METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"), + METHOD(&SymbolLayer::getIconAnchor, "nativeGetIconAnchor"), + METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"), + METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"), + METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"), + METHOD(&SymbolLayer::getTextField, "nativeGetTextField"), + METHOD(&SymbolLayer::getTextFont, "nativeGetTextFont"), + METHOD(&SymbolLayer::getTextSize, "nativeGetTextSize"), + METHOD(&SymbolLayer::getTextMaxWidth, "nativeGetTextMaxWidth"), + METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"), + METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"), + METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), + METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), + METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), + METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), + METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), + METHOD(&SymbolLayer::getTextWritingMode, "nativeGetTextWritingMode"), + METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"), + METHOD(&SymbolLayer::getTextPadding, "nativeGetTextPadding"), + METHOD(&SymbolLayer::getTextKeepUpright, "nativeGetTextKeepUpright"), + METHOD(&SymbolLayer::getTextTransform, "nativeGetTextTransform"), + METHOD(&SymbolLayer::getTextOffset, "nativeGetTextOffset"), + METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"), + METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"), + METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"), + METHOD(&SymbolLayer::getIconOpacityTransition, "nativeGetIconOpacityTransition"), + METHOD(&SymbolLayer::setIconOpacityTransition, "nativeSetIconOpacityTransition"), + METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"), + METHOD(&SymbolLayer::getIconColorTransition, "nativeGetIconColorTransition"), + METHOD(&SymbolLayer::setIconColorTransition, "nativeSetIconColorTransition"), + METHOD(&SymbolLayer::getIconColor, "nativeGetIconColor"), + METHOD(&SymbolLayer::getIconHaloColorTransition, "nativeGetIconHaloColorTransition"), + METHOD(&SymbolLayer::setIconHaloColorTransition, "nativeSetIconHaloColorTransition"), + METHOD(&SymbolLayer::getIconHaloColor, "nativeGetIconHaloColor"), + METHOD(&SymbolLayer::getIconHaloWidthTransition, "nativeGetIconHaloWidthTransition"), + METHOD(&SymbolLayer::setIconHaloWidthTransition, "nativeSetIconHaloWidthTransition"), + METHOD(&SymbolLayer::getIconHaloWidth, "nativeGetIconHaloWidth"), + METHOD(&SymbolLayer::getIconHaloBlurTransition, "nativeGetIconHaloBlurTransition"), + METHOD(&SymbolLayer::setIconHaloBlurTransition, "nativeSetIconHaloBlurTransition"), + METHOD(&SymbolLayer::getIconHaloBlur, "nativeGetIconHaloBlur"), + METHOD(&SymbolLayer::getIconTranslateTransition, "nativeGetIconTranslateTransition"), + METHOD(&SymbolLayer::setIconTranslateTransition, "nativeSetIconTranslateTransition"), + METHOD(&SymbolLayer::getIconTranslate, "nativeGetIconTranslate"), + METHOD(&SymbolLayer::getIconTranslateAnchor, "nativeGetIconTranslateAnchor"), + METHOD(&SymbolLayer::getTextOpacityTransition, "nativeGetTextOpacityTransition"), + METHOD(&SymbolLayer::setTextOpacityTransition, "nativeSetTextOpacityTransition"), + METHOD(&SymbolLayer::getTextOpacity, "nativeGetTextOpacity"), + METHOD(&SymbolLayer::getTextColorTransition, "nativeGetTextColorTransition"), + METHOD(&SymbolLayer::setTextColorTransition, "nativeSetTextColorTransition"), + METHOD(&SymbolLayer::getTextColor, "nativeGetTextColor"), + METHOD(&SymbolLayer::getTextHaloColorTransition, "nativeGetTextHaloColorTransition"), + METHOD(&SymbolLayer::setTextHaloColorTransition, "nativeSetTextHaloColorTransition"), + METHOD(&SymbolLayer::getTextHaloColor, "nativeGetTextHaloColor"), + METHOD(&SymbolLayer::getTextHaloWidthTransition, "nativeGetTextHaloWidthTransition"), + METHOD(&SymbolLayer::setTextHaloWidthTransition, "nativeSetTextHaloWidthTransition"), + METHOD(&SymbolLayer::getTextHaloWidth, "nativeGetTextHaloWidth"), + METHOD(&SymbolLayer::getTextHaloBlurTransition, "nativeGetTextHaloBlurTransition"), + METHOD(&SymbolLayer::setTextHaloBlurTransition, "nativeSetTextHaloBlurTransition"), + METHOD(&SymbolLayer::getTextHaloBlur, "nativeGetTextHaloBlur"), + METHOD(&SymbolLayer::getTextTranslateTransition, "nativeGetTextTranslateTransition"), + METHOD(&SymbolLayer::setTextTranslateTransition, "nativeSetTextTranslateTransition"), + METHOD(&SymbolLayer::getTextTranslate, "nativeGetTextTranslate"), + METHOD(&SymbolLayer::getTextTranslateAnchor, "nativeGetTextTranslateAnchor")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp new file mode 100644 index 000000000..4898c830d --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp @@ -0,0 +1,180 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class SymbolLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/SymbolLayer"; }; + + SymbolLayer(jni::JNIEnv&, jni::String&, jni::String&); + + SymbolLayer(mbgl::style::SymbolLayer&); + + SymbolLayer(std::unique_ptr); + + ~SymbolLayer(); + + // Properties + + jni::Local> getSymbolPlacement(jni::JNIEnv&); + + jni::Local> getSymbolSpacing(jni::JNIEnv&); + + jni::Local> getSymbolAvoidEdges(jni::JNIEnv&); + + jni::Local> getSymbolSortKey(jni::JNIEnv&); + + jni::Local> getSymbolZOrder(jni::JNIEnv&); + + jni::Local> getIconAllowOverlap(jni::JNIEnv&); + + jni::Local> getIconIgnorePlacement(jni::JNIEnv&); + + jni::Local> getIconOptional(jni::JNIEnv&); + + jni::Local> getIconRotationAlignment(jni::JNIEnv&); + + jni::Local> getIconSize(jni::JNIEnv&); + + jni::Local> getIconTextFit(jni::JNIEnv&); + + jni::Local> getIconTextFitPadding(jni::JNIEnv&); + + jni::Local> getIconImage(jni::JNIEnv&); + + jni::Local> getIconRotate(jni::JNIEnv&); + + jni::Local> getIconPadding(jni::JNIEnv&); + + jni::Local> getIconKeepUpright(jni::JNIEnv&); + + jni::Local> getIconOffset(jni::JNIEnv&); + + jni::Local> getIconAnchor(jni::JNIEnv&); + + jni::Local> getIconPitchAlignment(jni::JNIEnv&); + + jni::Local> getTextPitchAlignment(jni::JNIEnv&); + + jni::Local> getTextRotationAlignment(jni::JNIEnv&); + + jni::Local> getTextField(jni::JNIEnv&); + + jni::Local> getTextFont(jni::JNIEnv&); + + jni::Local> getTextSize(jni::JNIEnv&); + + jni::Local> getTextMaxWidth(jni::JNIEnv&); + + jni::Local> getTextLineHeight(jni::JNIEnv&); + + jni::Local> getTextLetterSpacing(jni::JNIEnv&); + + jni::Local> getTextJustify(jni::JNIEnv&); + + jni::Local> getTextRadialOffset(jni::JNIEnv&); + + jni::Local> getTextVariableAnchor(jni::JNIEnv&); + + jni::Local> getTextAnchor(jni::JNIEnv&); + + jni::Local> getTextMaxAngle(jni::JNIEnv&); + + jni::Local> getTextWritingMode(jni::JNIEnv&); + + jni::Local> getTextRotate(jni::JNIEnv&); + + jni::Local> getTextPadding(jni::JNIEnv&); + + jni::Local> getTextKeepUpright(jni::JNIEnv&); + + jni::Local> getTextTransform(jni::JNIEnv&); + + jni::Local> getTextOffset(jni::JNIEnv&); + + jni::Local> getTextAllowOverlap(jni::JNIEnv&); + + jni::Local> getTextIgnorePlacement(jni::JNIEnv&); + + jni::Local> getTextOptional(jni::JNIEnv&); + + jni::Local> getIconOpacity(jni::JNIEnv&); + void setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconOpacityTransition(jni::JNIEnv&); + + jni::Local> getIconColor(jni::JNIEnv&); + void setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconColorTransition(jni::JNIEnv&); + + jni::Local> getIconHaloColor(jni::JNIEnv&); + void setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloColorTransition(jni::JNIEnv&); + + jni::Local> getIconHaloWidth(jni::JNIEnv&); + void setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloWidthTransition(jni::JNIEnv&); + + jni::Local> getIconHaloBlur(jni::JNIEnv&); + void setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconHaloBlurTransition(jni::JNIEnv&); + + jni::Local> getIconTranslate(jni::JNIEnv&); + void setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIconTranslateTransition(jni::JNIEnv&); + + jni::Local> getIconTranslateAnchor(jni::JNIEnv&); + + jni::Local> getTextOpacity(jni::JNIEnv&); + void setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextOpacityTransition(jni::JNIEnv&); + + jni::Local> getTextColor(jni::JNIEnv&); + void setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextColorTransition(jni::JNIEnv&); + + jni::Local> getTextHaloColor(jni::JNIEnv&); + void setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloColorTransition(jni::JNIEnv&); + + jni::Local> getTextHaloWidth(jni::JNIEnv&); + void setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloWidthTransition(jni::JNIEnv&); + + jni::Local> getTextHaloBlur(jni::JNIEnv&); + void setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextHaloBlurTransition(jni::JNIEnv&); + + jni::Local> getTextTranslate(jni::JNIEnv&); + void setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTextTranslateTransition(jni::JNIEnv&); + + jni::Local> getTextTranslateAnchor(jni::JNIEnv&); + +}; // class SymbolLayer + +class SymbolJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::SymbolLayerFactory { +public: + ~SymbolJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class SymbolJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/light.cpp b/MapboxGLAndroidSDK/src/cpp/style/light.cpp new file mode 100644 index 000000000..d8ed4d9d9 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/light.cpp @@ -0,0 +1,143 @@ +#include +#include "light.hpp" +#include "conversion/transition_options.hpp" +#include "conversion/position.hpp" + +namespace mbgl { +namespace android { + +Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight) + : light(coreLight) , map(&coreMap) { +} + +static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) { + return new Light(map, coreLight); +} + +jni::Local> Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) { + std::unique_ptr peerLight = std::unique_ptr(initializeLightPeer(map, coreLight)); + auto result = peerLight->createJavaPeer(env); + peerLight.release(); + return result; +} + +jni::Local> Light::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); +} + +void Light::setAnchor(jni::JNIEnv& env, const jni::String& property) { + std::string anchorStr = jni::Make(env, property); + if (anchorStr.compare("map") == 0) { + light.setAnchor(LightAnchorType::Map); + } else if (anchorStr.compare("viewport") == 0) { + light.setAnchor(LightAnchorType::Viewport); + } +} + +jni::Local Light::getAnchor(jni::JNIEnv& env) { + auto anchorType = light.getAnchor(); + if (anchorType == LightAnchorType::Map) { + return jni::Make(env, "map"); + } else { + return jni::Make(env, "viewport"); + } +} + +void Light::setPosition(jni::JNIEnv& env, const jni::Object& jposition) { + using namespace mbgl::android::conversion; + auto position = *convert(env, jposition); + light.setPosition(position); +} + +jni::Local> Light::getPosition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::Position position = light.getPosition().asConstant(); + return std::move(*convert>>(env, position)); +} + +jni::Local> Light::getPositionTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getPositionTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setPositionTransition(options); +} + +void Light::setColor(jni::JNIEnv& env, const jni::String& property) { + auto color = Color::parse(jni::Make(env, property)); + if (color) { + light.setColor(color.value()); + } +} + +jni::Local Light::getColor(jni::JNIEnv &env) { + auto color = light.getColor().asConstant(); + return jni::Make(env, color.stringify()); +} + +jni::Local> Light::getColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getColorTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setColorTransition(options); +} + +void Light::setIntensity(jni::JNIEnv&, jni::jfloat property) { + light.setIntensity(property); +} + +jni::jfloat Light::getIntensity(jni::JNIEnv&) { + return light.getIntensity().asConstant(); +} + +jni::Local> Light::getIntensityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = light.getIntensityTransition(); + return std::move(*convert>>(env, options)); +} + +void Light::setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + light.setIntensityTransition(options); +} + +void Light::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + +#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + // Register the peer + jni::RegisterNativePeer(env, javaClass, "nativePtr", + METHOD(&Light::getAnchor, "nativeGetAnchor"), + METHOD(&Light::setAnchor, "nativeSetAnchor"), + METHOD(&Light::getPositionTransition, "nativeGetPositionTransition"), + METHOD(&Light::setPositionTransition, "nativeSetPositionTransition"), + METHOD(&Light::getPosition, "nativeGetPosition"), + METHOD(&Light::setPosition, "nativeSetPosition"), + METHOD(&Light::getColorTransition, "nativeGetColorTransition"), + METHOD(&Light::setColorTransition, "nativeSetColorTransition"), + METHOD(&Light::getColor, "nativeGetColor"), + METHOD(&Light::setColor, "nativeSetColor"), + METHOD(&Light::getIntensityTransition, "nativeGetIntensityTransition"), + METHOD(&Light::setIntensityTransition, "nativeSetIntensityTransition"), + METHOD(&Light::getIntensity, "nativeGetIntensity"), + METHOD(&Light::setIntensity, "nativeSetIntensity")); +} + +} // namespace android +} // namespace mb diff --git a/MapboxGLAndroidSDK/src/cpp/style/light.hpp b/MapboxGLAndroidSDK/src/cpp/style/light.hpp new file mode 100644 index 000000000..97767c4f7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/light.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include +#include +#include "transition_options.hpp" +#include "position.hpp" +#include +#include + +namespace mbgl { +namespace android { + +using namespace style; + +class Light : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; }; + + static void registerNative(jni::JNIEnv&); + + static jni::Local> createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&); + + Light(mbgl::Map&, mbgl::style::Light&); + + void setAnchor(jni::JNIEnv&, const jni::String&); + jni::Local getAnchor(jni::JNIEnv&); + void setPosition(jni::JNIEnv&, const jni::Object&); + jni::Local> getPosition(jni::JNIEnv&); + void setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getPositionTransition(jni::JNIEnv&); + void setColor(jni::JNIEnv&, const jni::String&); + jni::Local getColor(jni::JNIEnv&); + void setColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getColorTransition(jni::JNIEnv&); + void setIntensity(jni::JNIEnv&, jni::jfloat); + jni::jfloat getIntensity(jni::JNIEnv&); + void setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getIntensityTransition(jni::JNIEnv&); + jni::Local> createJavaPeer(jni::JNIEnv&); + +protected: + + // Raw reference to the light + mbgl::style::Light& light; + + // Map is set when the light is retrieved + mbgl::Map* map; +}; +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/position.cpp b/MapboxGLAndroidSDK/src/cpp/style/position.cpp new file mode 100644 index 000000000..326310be0 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/position.cpp @@ -0,0 +1,35 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { + +jni::Local> Position::fromPosition(jni::JNIEnv& env, jfloat radialCoordinate, jfloat azimuthalAngle, jfloat polarAngle) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jfloat, jfloat, jfloat)>(env, "fromPosition"); + return javaClass.Call(env, method, radialCoordinate, azimuthalAngle, polarAngle); +} + +void Position::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +float Position::getRadialCoordinate(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "radialCoordinate"); + return position.Get(env, field); +} + +float Position::getAzimuthalAngle(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "azimuthalAngle"); + return position.Get(env, field); +} + +float Position::getPolarAngle(jni::JNIEnv& env, const jni::Object& position) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "polarAngle"); + return position.Get(env, field); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/position.hpp b/MapboxGLAndroidSDK/src/cpp/style/position.hpp new file mode 100644 index 000000000..eb4f5ac67 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/position.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class Position : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Position"; }; + + static jni::Local> fromPosition(jni::JNIEnv&, jfloat, jfloat, jfloat); + + static void registerNative(jni::JNIEnv&); + + static float getRadialCoordinate(jni::JNIEnv&, const jni::Object&); + static float getAzimuthalAngle(jni::JNIEnv&, const jni::Object&); + static float getPolarAngle(jni::JNIEnv&, const jni::Object&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.cpp new file mode 100644 index 000000000..e43bf8fa1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.cpp @@ -0,0 +1,209 @@ +#include "custom_geometry_source.hpp" +#include "attach_env.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include + +#include + +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a CustomGeometrySourceOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. + static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env, + const jni::Object<>& options, + style::TileFunction fetchFn, + style::TileFunction cancelFn) { + using namespace mbgl::style::conversion; + if (!options) { + return style::CustomGeometrySource::Options(); + } + Error error; + optional result = convert(Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + result->fetchTileFunction = fetchFn; + result->cancelTileFunction = cancelFn; + return *result; + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + const jni::String& sourceId, + const jni::Object<>& options) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + convertCustomGeometrySourceOptions(env, options, + std::bind(&CustomGeometrySource::fetchTile, this, std::placeholders::_1), + std::bind(&CustomGeometrySource::cancelTile, this, std::placeholders::_1)))) { + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + + CustomGeometrySource::~CustomGeometrySource() { + releaseThreads(); + } + + void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto fetchTile = javaClass.GetMethod(*_env, "fetchTile"); + + // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. + // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. + // See https://github.com/mapbox/mapbox-gl-native/issues/12551. + if(!javaPeer) { + return; + } + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::cancelTile(const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto cancelTile = javaClass.GetMethod(*_env, "cancelTile"); + + // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete. + // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released. + // See https://github.com/mapbox/mapbox-gl-native/issues/12551. + if(!javaPeer) { + return; + } + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::startThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto startThreads = javaClass.GetMethod(*_env, "startThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, startThreads); + } + + void CustomGeometrySource::releaseThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto releaseThreads = javaClass.GetMethod(*_env, "releaseThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + peer.Call(*_env, releaseThreads); + }; + + bool CustomGeometrySource::isCancelled(jni::jint z, + jni::jint x, + jni::jint y) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto& javaClass = jni::Class::Singleton(*_env); + static auto isCancelled = javaClass.GetMethod(*_env, "isCancelled"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, javaClass, javaPeer); + return peer.Call(*_env, isCancelled, z, x, y); + }; + + void CustomGeometrySource::setTileData(jni::JNIEnv& env, + jni::jint z, + jni::jint x, + jni::jint y, + const jni::Object& jFeatures) { + using namespace mbgl::android::geojson; + + // Convert the jni object + auto geometry = geojson::FeatureCollection::convert(env, jFeatures); + + // Update the core source if not cancelled + if (!isCancelled(z, x ,y)) { + source.as()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); + } + } + + void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) { + source.as()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); + } + + void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, const jni::Object& jBounds) { + auto bounds = LatLngBounds::getLatLngBounds(env, jBounds); + source.as()->CustomGeometrySource::invalidateRegion(bounds); + } + + jni::Local>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local> CustomGeometrySource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void CustomGeometrySource::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + Source::addToMap(env, obj, map, frontend); + startThreads(); + } + + bool CustomGeometrySource::removeFromMap(JNIEnv& env, const jni::Object& source, mbgl::Map& map) { + bool successfullyRemoved = Source::removeFromMap(env, source, map); + if (successfullyRemoved) { + releaseThreads(); + } + return successfullyRemoved; + } + + void CustomGeometrySource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&CustomGeometrySource::querySourceFeatures, "querySourceFeatures"), + METHOD(&CustomGeometrySource::setTileData, "nativeSetTileData"), + METHOD(&CustomGeometrySource::invalidateTile, "nativeInvalidateTile"), + METHOD(&CustomGeometrySource::invalidateBounds, "nativeInvalidateBounds") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.hpp new file mode 100644 index 000000000..6979ecc25 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/custom_geometry_source.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "source.hpp" +#include +#include +#include +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include "../../geometry/lat_lng_bounds.hpp" +#include + +namespace mbgl { +namespace android { + +class CustomGeometrySource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/CustomGeometrySource"; }; + + static void registerNative(jni::JNIEnv&); + + CustomGeometrySource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + CustomGeometrySource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + ~CustomGeometrySource(); + + bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&) override; + void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&) override; + + void fetchTile(const mbgl::CanonicalTileID& tileID); + void cancelTile(const mbgl::CanonicalTileID& tileID); + bool isCancelled(jni::jint z, jni::jint x, jni::jint y); + void startThreads(); + void releaseThreads(); + +private: + void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, const jni::Object& jf); + + void invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y); + void invalidateBounds(jni::JNIEnv& env, const jni::Object& bounds); + + jni::Local>> querySourceFeatures(jni::JNIEnv&, + const jni::Array>& ); + + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class CustomGeometrySource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.cpp new file mode 100644 index 000000000..5b699e9c6 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.cpp @@ -0,0 +1,259 @@ +#include "geojson_source.hpp" +#include +#include "attach_env.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" +#include +#include +#include + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +// GeoJSONSource uses a "coalescing" model for high frequency asynchronous data update calls, +// which in practice means, that any update that started processing is going to finish +// and the last scheduled update is going to finish as well. Any updates scheduled during processing can be canceled. +// Conversion from Java features to core ones is done on a worker thread and once finished, +// the ownership of the converted features is returned to the calling thread. +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a GeoJsonOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. +static Immutable convertGeoJSONOptions(jni::JNIEnv& env, const jni::Object<>& options) { + using namespace mbgl::style::conversion; + if (!options) { + return style::GeoJSONOptions::defaultOptions(); + } + Error error; + optional result = convert(mbgl::android::Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + return makeMutable(std::move(*result)); +} + +GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& options) + : Source(env, + std::make_unique(jni::Make(env, sourceId), + convertGeoJSONOptions(env, options))), + converter(std::make_unique>(Scheduler::GetBackground(), + source.as()->impl().getOptions())) {} + +GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend), + converter(std::make_unique>(Scheduler::GetBackground(), + source.as()->impl().getOptions())) {} + +GeoJSONSource::~GeoJSONSource() = default; + +void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, const jni::String& jString) { + std::shared_ptr json = std::make_shared(jni::Make(env, jString)); + + Update::Converter converterFn = [this, json](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertJson, json, _callback); + }; + + setAsync(converterFn); +} + + void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, const jni::Object& jFeatures) { + setCollectionAsync(env, jFeatures); + } + + void GeoJSONSource::setFeature(jni::JNIEnv& env, const jni::Object& jFeature) { + setCollectionAsync(env, jFeature); + } + + void GeoJSONSource::setGeometry(jni::JNIEnv& env, const jni::Object& jGeometry) { + setCollectionAsync(env, jGeometry); + } + + void GeoJSONSource::setURL(jni::JNIEnv& env, const jni::String& url) { + // Update the core source + source.as()->setURL(jni::Make(env, url)); + } + + jni::Local GeoJSONSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local>> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), + { {}, toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local>> GeoJSONSource::getClusterChildren(jni::JNIEnv& env, const jni::Object& feature) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + const auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "children", {}); + if (featureExtension.is()) { + return Feature::convert(env, featureExtension.get()); + } + } + return jni::Array>::New(env, 0); + } + + jni::Local>> GeoJSONSource::getClusterLeaves(jni::JNIEnv& env, const jni::Object& feature, jni::jlong limit, jni::jlong offset) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + const std::map options = { {"limit", static_cast(limit)}, + {"offset", static_cast(offset)} }; + auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "leaves", options); + if (featureExtension.is()) { + return Feature::convert(env, featureExtension.get()); + } + } + return jni::Array>::New(env, 0);; + } + + jint GeoJSONSource::getClusterExpansionZoom(jni::JNIEnv& env, const jni::Object& feature) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + if (rendererFrontend) { + mbgl::Feature _feature = Feature::convert(env, feature); + _feature.properties["cluster_id"] = static_cast(_feature.properties["cluster_id"].get()); + auto featureExtension = rendererFrontend->queryFeatureExtensions(source.getID(), _feature, "supercluster", "expansion-zoom", {}); + if (featureExtension.is()) { + auto value = featureExtension.get(); + if (value.is()) { + return value.get(); + } + } + } + return 0; + } + + jni::Local> GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + template + void GeoJSONSource::setCollectionAsync(jni::JNIEnv& env, const jni::Object& jObject) { + auto global = jni::NewGlobal(env, jObject); + auto object = std::make_shared(std::move(global)); + + Update::Converter converterFn = [this, object](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertObject, object, _callback); + }; + + setAsync(converterFn); + } + + void GeoJSONSource::setAsync(Update::Converter converterFn) { + awaitingUpdate = std::make_unique( + std::move(converterFn), + std::make_unique>( + *Scheduler::GetCurrent(), [this](std::shared_ptr geoJSONData) { + // conversion from Java features to core ones finished + android::UniqueEnv _env = android::AttachEnv(); + + // Update the core source + source.as()->setGeoJSONData(std::move(geoJSONData)); + + // if there is an awaiting update, execute it, otherwise, release resources + if (awaitingUpdate) { + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } else { + update.reset(); + } + })); + + // If another update is running, wait + if (update) { + return; + } + + // no updates are being processed, execute this one + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } + + void GeoJSONSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&GeoJSONSource::setGeoJSONString, "nativeSetGeoJsonString"), + METHOD(&GeoJSONSource::setFeatureCollection, "nativeSetFeatureCollection"), + METHOD(&GeoJSONSource::setFeature, "nativeSetFeature"), + METHOD(&GeoJSONSource::setGeometry, "nativeSetGeometry"), + METHOD(&GeoJSONSource::setURL, "nativeSetUrl"), + METHOD(&GeoJSONSource::getURL, "nativeGetUrl"), + METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures"), + METHOD(&GeoJSONSource::getClusterChildren, "nativeGetClusterChildren"), + METHOD(&GeoJSONSource::getClusterLeaves, "nativeGetClusterLeaves"), + METHOD(&GeoJSONSource::getClusterExpansionZoom, "nativeGetClusterExpansionZoom") + ); + } + + void FeatureConverter::convertJson(std::shared_ptr json, ActorRef callback) { + using namespace mbgl::style::conversion; + + android::UniqueEnv _env = android::AttachEnv(); + // Convert the jni object + Error error; + optional converted = parseGeoJSON(*json, error); + if(!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); + return; + } + + callback.invoke(&GeoJSONDataCallback::operator(), style::GeoJSONData::create(*converted, options)); + } + + template + void FeatureConverter::convertObject( + std::shared_ptr, jni::EnvAttachingDeleter>> jObject, + ActorRef callback) { + using namespace mbgl::android::geojson; + + android::UniqueEnv _env = android::AttachEnv(); + // Convert the jni object + auto geometry = JNIType::convert(*_env, *jObject); + callback.invoke(&GeoJSONDataCallback::operator(), style::GeoJSONData::create(geometry, options)); + } + + Update::Update(Converter _converterFn, std::unique_ptr> _callback) + : converterFn(std::move(_converterFn)), callback(std::move(_callback)) {} + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.hpp new file mode 100644 index 000000000..c7ef6e54d --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/geojson_source.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include "source.hpp" +#include +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include "../../android_renderer_frontend.hpp" +#include + +namespace mbgl { +namespace android { + +using GeoJSONDataCallback = std::function)>; + +class FeatureConverter { +public: + explicit FeatureConverter(Immutable options_) : options(std::move(options_)) {} + void convertJson(std::shared_ptr, ActorRef); + + template + void convertObject(std::shared_ptr, jni::EnvAttachingDeleter>>, + ActorRef); + +private: + Immutable options; +}; + +struct Update { + using Converter = std::function)>; + Converter converterFn; + + std::unique_ptr> callback; + + Update(Converter, std::unique_ptr>); +}; + +class GeoJSONSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/GeoJsonSource"; }; + + static void registerNative(jni::JNIEnv&); + + GeoJSONSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + GeoJSONSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + ~GeoJSONSource(); + +private: + void setGeoJSONString(jni::JNIEnv&, const jni::String&); + void setFeatureCollection(jni::JNIEnv&, const jni::Object&); + void setFeature(jni::JNIEnv&, const jni::Object&); + void setGeometry(jni::JNIEnv&, const jni::Object&); + void setURL(jni::JNIEnv&, const jni::String&); + + jni::Local>> querySourceFeatures(jni::JNIEnv&, + const jni::Array>&); + + jni::Local>> getClusterChildren(jni::JNIEnv&, const jni::Object&); + jni::Local>> getClusterLeaves(jni::JNIEnv&, const jni::Object&, jni::jlong, jni::jlong); + jint getClusterExpansionZoom(jni::JNIEnv&, const jni::Object&); + + jni::Local getURL(jni::JNIEnv&); + + jni::Local> createJavaPeer(jni::JNIEnv&); + std::unique_ptr awaitingUpdate; + std::unique_ptr update; + std::shared_ptr threadPool; + std::unique_ptr> converter; + + template + void setCollectionAsync(jni::JNIEnv&, const jni::Object&); + + void setAsync(Update::Converter); + +}; // class GeoJSONSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.cpp new file mode 100644 index 000000000..614c39c21 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.cpp @@ -0,0 +1,76 @@ +#include "image_source.hpp" + +// Java -> C++ conversion +#include "../android_conversion.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include +#include + +#include "bitmap.hpp" +#include +#include + +namespace mbgl { +namespace android { + + ImageSource::ImageSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object& coordinatesObject) + : Source(env, std::make_unique( + jni::Make(env, sourceId), + LatLngQuad::getLatLngArray(env, coordinatesObject) + ) + ) { + } + + ImageSource::ImageSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + + ImageSource::~ImageSource() = default; + + void ImageSource::setURL(jni::JNIEnv& env, const jni::String& url) { + // Update the core source + source.as()->ImageSource::setURL(jni::Make(env, url)); + } + + jni::Local ImageSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->ImageSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + void ImageSource::setImage(jni::JNIEnv& env, const jni::Object& bitmap) { + source.as()->setImage(Bitmap::GetImage(env, bitmap)); + } + + void ImageSource::setCoordinates(jni::JNIEnv& env, const jni::Object& coordinatesObject) { + source.as()->setCoordinates( + LatLngQuad::getLatLngArray(env, coordinatesObject)); + } + + jni::Local> ImageSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void ImageSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&ImageSource::setURL, "nativeSetUrl"), + METHOD(&ImageSource::getURL, "nativeGetUrl"), + METHOD(&ImageSource::setImage, "nativeSetImage"), + METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.hpp new file mode 100644 index 000000000..da88feac7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/image_source.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "source.hpp" +#include "../../geometry/lat_lng_quad.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class Bitmap; + +class ImageSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; }; + + static void registerNative(jni::JNIEnv&); + + ImageSource(jni::JNIEnv&, const jni::String&, const jni::Object&); + + ImageSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + + ~ImageSource(); + + void setURL(jni::JNIEnv&, const jni::String&); + jni::Local getURL(jni::JNIEnv&); + + void setImage(jni::JNIEnv&, const jni::Object&); + + void setCoordinates(jni::JNIEnv&, const jni::Object&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class ImageSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.cpp new file mode 100644 index 000000000..a33e00259 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.cpp @@ -0,0 +1,61 @@ +#include "raster_dem_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" +#include "source.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + + RasterDEMSource::~RasterDEMSource() = default; + + jni::Local RasterDEMSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->RasterDEMSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local> RasterDEMSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void RasterDEMSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&, jni::jint>, + "initialize", + "finalize", + METHOD(&RasterDEMSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.hpp new file mode 100644 index 000000000..581e8f8bc --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_dem_source.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class RasterDEMSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterDemSource"; }; + + static void registerNative(jni::JNIEnv&); + + RasterDEMSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); + RasterDEMSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + ~RasterDEMSource(); + + jni::Local getURL(jni::JNIEnv&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class RasterDEMSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.cpp new file mode 100644 index 000000000..67603e74c --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.cpp @@ -0,0 +1,58 @@ +#include "raster_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +#include + +namespace mbgl { +namespace android { + + RasterSource::RasterSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterSource::RasterSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + + RasterSource::~RasterSource() = default; + + jni::Local RasterSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->RasterSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local> RasterSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void RasterSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&, jni::jint>, + "initialize", + "finalize", + METHOD(&RasterSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.hpp new file mode 100644 index 000000000..e1bc5ca7a --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/raster_source.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class RasterSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterSource"; }; + + static void registerNative(jni::JNIEnv&); + + RasterSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&, jni::jint); + RasterSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + ~RasterSource(); + + jni::Local getURL(jni::JNIEnv&); + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class RasterSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp new file mode 100644 index 000000000..29e41976c --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp @@ -0,0 +1,230 @@ +#include "source.hpp" +#include "../android_conversion.hpp" +#include "attach_env.hpp" + +#include + +#include +#include + +// Java -> C++ conversion +#include +#include + +// C++ -> Java conversion +#include "../conversion/property_value.hpp" + +#include + +// Core Sources +#include +#include +#include +#include + +// Android Source peers +#include "geojson_source.hpp" +#include "image_source.hpp" +#include "raster_source.hpp" +#include "unknown_source.hpp" +#include "vector_source.hpp" +#include "custom_geometry_source.hpp" +#include "raster_dem_source.hpp" + +namespace mbgl { +namespace android { + +static std::unique_ptr createSourcePeer(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend* frontend) { + if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else if (coreSource.is()) { + return std::make_unique(env, *coreSource.as(), frontend); + } else { + return std::make_unique(env, coreSource, frontend); + } +} + + const jni::Object& Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (!coreSource.peer.has_value()) { + coreSource.peer = createSourcePeer(env, coreSource, &frontend); + } + return coreSource.peer.get>()->javaPeer; + } + + const jni::Object& Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource) { + if (!coreSource.peer.has_value()) { + coreSource.peer = createSourcePeer(env, coreSource, nullptr); + } + return coreSource.peer.get>()->javaPeer; + } + + Source::Source(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + const jni::Object& obj, + AndroidRendererFrontend* frontend) + : source(coreSource), javaPeer(jni::NewGlobal(env, obj)), rendererFrontend(frontend) {} + + Source::Source(jni::JNIEnv&, std::unique_ptr coreSource) + : ownedSource(std::move(coreSource)) + , source(*ownedSource) { + } + + Source::~Source() { + // Before being added to a map, the Java peer owns this C++ peer and cleans + // up after itself correctly through the jni native peer bindings. + // After being added to the map, the ownership is flipped and the C++ peer has a strong reference + // to it's Java peer, preventing the Java peer from being GC'ed. + // In this case, the core source initiates the destruction, which requires releasing the Java peer, + // while also resetting it's nativePtr to 0 to prevent the subsequent GC of the Java peer from + // re-entering this dtor. + if (ownedSource.get() == nullptr && javaPeer.get() != nullptr) { + // Manually clear the java peer + android::UniqueEnv env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*env); + static auto nativePtrField = javaClass.GetField(*env, "nativePtr"); + javaPeer.Set(*env, nativePtrField, (jlong) 0); + javaPeer.reset(); + } + } + + jni::Local Source::getId(jni::JNIEnv& env) { + return jni::Make(env, source.getID()); + } + + jni::Local Source::getAttribution(jni::JNIEnv& env) { + auto attribution = source.getAttribution(); + return attribution ? jni::Make(env, attribution.value()) : jni::Make(env,""); + } + + void Source::setPrefetchZoomDelta(jni::JNIEnv& env, jni::Integer& delta) { + if (!delta) { + source.setPrefetchZoomDelta(nullopt); + } else { + source.setPrefetchZoomDelta(jni::Unbox(env, delta)); + } + } + + jni::Local Source::getPrefetchZoomDelta(jni::JNIEnv& env) { + auto delta = source.getPrefetchZoomDelta(); + if (delta.has_value()) { + return jni::Box(env, jni::jint(delta.value())); + } + return jni::Local(env, nullptr); + } + + void Source::setMaxOverscaleFactorForParentTiles(jni::JNIEnv& env, jni::Integer& maxOverscaleFactor) { + if (!maxOverscaleFactor) { + source.setMaxOverscaleFactorForParentTiles(nullopt); + } else { + source.setMaxOverscaleFactorForParentTiles(jni::Unbox(env, maxOverscaleFactor)); + } + } + + jni::Local Source::getMaxOverscaleFactorForParentTiles(jni::JNIEnv& env) { + auto maxOverscaleFactor = source.getMaxOverscaleFactorForParentTiles(); + if (maxOverscaleFactor) { + return jni::Box(env, jni::jint(*maxOverscaleFactor)); + } + return jni::Local(env, nullptr); + } + + void Source::addToStyle(JNIEnv& env, const jni::Object& obj, mbgl::style::Style& style) { + if (!ownedSource) { + throw std::runtime_error("Cannot add source twice"); + } + + // Add source to style and release ownership + style.addSource(std::move(ownedSource)); + + // Add peer to core source + source.peer = std::unique_ptr(this); + + // Add strong reference to java source + javaPeer = jni::NewGlobal(env, obj); + } + + void Source::addToMap(JNIEnv& env, const jni::Object& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + // Check to see if we own the source first + if (!ownedSource) { + throw std::runtime_error("Cannot add source twice"); + } + + // Add source to map and release ownership + map.getStyle().addSource(std::move(ownedSource)); + + // Add peer to core source + source.peer = std::unique_ptr(this); + + // Add strong reference to java source + javaPeer = jni::NewGlobal(env, obj); + + rendererFrontend = &frontend; + } + + bool Source::removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map& map) { + // Cannot remove if not attached yet + if (ownedSource) { + throw std::runtime_error("Cannot remove detached source"); + } + + // Remove the source from the map and take ownership + ownedSource = map.getStyle().removeSource(source.getID()); + + // The source may not be removed if any layers still reference it + return ownedSource != nullptr; + } + + void Source::releaseJavaPeer() { + // We can't release the peer if the source was not removed from the map + if (!ownedSource) { + return; + } + + // Release the peer relationships. These will be re-established when the source is added to a map + assert(ownedSource->peer.has_value()); + ownedSource->peer.get>().release(); + ownedSource->peer = mapbox::base::TypeWrapper(); + + // Release the strong reference to the java peer + assert(javaPeer); + javaPeer.release(); + + rendererFrontend = nullptr; + } + + void Source::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + METHOD(&Source::getId, "nativeGetId"), + METHOD(&Source::getAttribution, "nativeGetAttribution"), + METHOD(&Source::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), + METHOD(&Source::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta"), + METHOD(&Source::setMaxOverscaleFactorForParentTiles, "nativeSetMaxOverscaleFactorForParentTiles"), + METHOD(&Source::getMaxOverscaleFactorForParentTiles, "nativeGetMaxOverscaleFactorForParentTiles")); + + // Register subclasses + GeoJSONSource::registerNative(env); + ImageSource::registerNative(env); + RasterSource::registerNative(env); + UnknownSource::registerNative(env); + VectorSource::registerNative(env); + CustomGeometrySource::registerNative(env); + RasterDEMSource::registerNative(env); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp new file mode 100644 index 000000000..fbeb201c7 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + +#include "../value.hpp" +#include "../../android_renderer_frontend.hpp" + +#include + +namespace mbgl { +namespace android { + +class Source : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/Source"; }; + + static void registerNative(jni::JNIEnv&); + + static const jni::Object& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&); + static const jni::Object& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + /* + * Called when a Java object is created for a core source that belongs to a map. + */ + Source(jni::JNIEnv&, mbgl::style::Source&, const jni::Object&, AndroidRendererFrontend*); + + /* + * Called when a Java object is created for a new core source that does not belong to a map. + */ + Source(jni::JNIEnv&, std::unique_ptr); + + virtual ~Source(); + + virtual void addToMap(JNIEnv&, const jni::Object&, mbgl::Map&, AndroidRendererFrontend&); + + virtual bool removeFromMap(JNIEnv&, const jni::Object&, mbgl::Map&); + + void releaseJavaPeer(); + + jni::Local getId(jni::JNIEnv&); + + jni::Local getAttribution(jni::JNIEnv&); + + void setPrefetchZoomDelta(jni::JNIEnv& env, jni::Integer& delta); + + jni::Local getPrefetchZoomDelta(jni::JNIEnv&); + + void setMaxOverscaleFactorForParentTiles(jni::JNIEnv& env, jni::Integer& delta); + + jni::Local getMaxOverscaleFactorForParentTiles(jni::JNIEnv&); + + void addToStyle(JNIEnv& env, const jni::Object& obj, mbgl::style::Style& style); + +protected: + // Set on newly created sources until added to the map. + std::unique_ptr ownedSource; + + // Raw pointer that is valid at all times. + mbgl::style::Source& source; + + // Set when the source is added to a map. + jni::Global> javaPeer; + + // RendererFrontend pointer is valid only when added to the map. + AndroidRendererFrontend* rendererFrontend { nullptr }; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.cpp new file mode 100644 index 000000000..acfd52db8 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.cpp @@ -0,0 +1,40 @@ +#include "unknown_source.hpp" + +namespace { + + // Dummy initializer (We don't support initializing this from the JVM) + std::unique_ptr init(jni::JNIEnv&) { + throw std::runtime_error("UnknownSource should not be initialized from the JVM"); + } + +} // namespace + +namespace mbgl { +namespace android { + +UnknownSource::UnknownSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + +jni::Local> UnknownSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); +} + + void UnknownSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + init, + "initialize", + "finalize" + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.hpp new file mode 100644 index 000000000..ab5a2da82 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/unknown_source.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "source.hpp" +#include +#include + +namespace mbgl { +namespace android { + +class UnknownSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/UnknownSource"; }; + + static void registerNative(jni::JNIEnv&); + + UnknownSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + + ~UnknownSource() = default; + +private: + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class UnknownSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.cpp new file mode 100644 index 000000000..2be1a7811 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.cpp @@ -0,0 +1,81 @@ +#include "vector_source.hpp" + +#include + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/feature.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include + +#include +#include + +namespace mbgl { +namespace android { + + VectorSource::VectorSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& urlOrTileSet) + : Source( + env, + std::make_unique( + jni::Make(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)) + ) + ) { + } + + VectorSource::VectorSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend* frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) {} + + VectorSource::~VectorSource() = default; + + jni::Local VectorSource::getURL(jni::JNIEnv& env) { + optional url = source.as()->VectorSource::getURL(); + return url ? jni::Make(env, *url) : jni::Local(); + } + + jni::Local>> VectorSource::querySourceFeatures(jni::JNIEnv& env, + const jni::Array& jSourceLayerIds, + const jni::Array>& jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), + { toVector(env, jSourceLayerIds), toFilter(env, jfilter) }); + } + return Feature::convert(env, features); + } + + jni::Local> VectorSource::createJavaPeer(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void VectorSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, javaClass, "nativePtr", + jni::MakePeer&>, + "initialize", + "finalize", + METHOD(&VectorSource::querySourceFeatures, "querySourceFeatures"), + METHOD(&VectorSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.hpp new file mode 100644 index 000000000..7ae2e8c9e --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/vector_source.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "source.hpp" +#include +#include "../../geojson/feature.hpp" +#include + +namespace mbgl { +namespace android { + +class VectorSource : public Source { +public: + using SuperTag = Source; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/VectorSource"; }; + + static void registerNative(jni::JNIEnv&); + + VectorSource(jni::JNIEnv&, const jni::String&, const jni::Object<>&); + VectorSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend*); + ~VectorSource(); + +private: + jni::Local>> querySourceFeatures(jni::JNIEnv&, const jni::Array&, + const jni::Array>& jfilter); + + jni::Local getURL(jni::JNIEnv&); + + jni::Local> createJavaPeer(jni::JNIEnv&); + +}; // class VectorSource + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/transition_options.cpp b/MapboxGLAndroidSDK/src/cpp/style/transition_options.cpp new file mode 100644 index 000000000..d70a04e0d --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/transition_options.cpp @@ -0,0 +1,35 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { + +jni::Local> TransitionOptions::fromTransitionOptions(jni::JNIEnv& env, jlong duration, jlong delay, jboolean enablePlacementTransitions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jlong, jlong, jboolean)>(env, "fromTransitionOptions"); + return javaClass.Call(env, method, duration, delay, enablePlacementTransitions); +} + +long TransitionOptions::getDuration(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "duration"); + return transitionOptions.Get(env, field); +} + +long TransitionOptions::getDelay(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "delay"); + return transitionOptions.Get(env, field); +} + +bool TransitionOptions::isEnablePlacementTransitions(jni::JNIEnv& env, const jni::Object& transitionOptions) { + static auto& javaClass = jni::Class::Singleton(env); + static auto field = javaClass.GetField(env, "enablePlacementTransitions"); + return transitionOptions.Get(env, field); +} + +void TransitionOptions::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/transition_options.hpp b/MapboxGLAndroidSDK/src/cpp/style/transition_options.hpp new file mode 100644 index 000000000..58656a946 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/transition_options.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class TransitionOptions : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TransitionOptions"; }; + + static jni::Local> fromTransitionOptions(jni::JNIEnv&, jlong duration, jlong delay, jboolean enablePlacementTransitions); + + static long getDuration(jni::JNIEnv&, const jni::Object&); + + static long getDelay(jni::JNIEnv&, const jni::Object&); + + static bool isEnablePlacementTransitions(jni::JNIEnv&, const jni::Object&); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/cpp/style/value.cpp b/MapboxGLAndroidSDK/src/cpp/style/value.cpp new file mode 100644 index 000000000..2f0484072 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/value.cpp @@ -0,0 +1,83 @@ +#include "value.hpp" + +#include "../java_types.hpp" + +namespace mbgl { +namespace android { + // Instance + + Value::Value(jni::JNIEnv& _env, jni::Local> _value) + : env(_env), + value(std::move(_value)) {} + + Value::Value(jni::JNIEnv& _env, const jni::Object<>& _value) + : env(_env), + value(jni::NewLocal(_env, _value)) {} + + bool Value::isNull() const { + return !value; + } + + bool Value::isArray() const { + return jni::IsInstanceOf(env, value.get(), *java::ObjectArray::jclass); + } + + bool Value::isObject() const { + return jni::IsInstanceOf(env, value.get(), *java::Map::jclass); + } + + bool Value::isString() const { + return jni::IsInstanceOf(env, value.get(), *java::String::jclass); + } + + bool Value::isBool() const { + return jni::IsInstanceOf(env, value.get(), *java::Boolean::jclass); + } + + bool Value::isNumber() const { + return jni::IsInstanceOf(env, value.get(), *java::Number::jclass); + } + + std::string Value::toString() const { + return jni::Make(env, jni::Cast(env, jni::Class::Singleton(env), value)); + } + + float Value::toFloat() const { + return jni::CallMethod(env, value.get(), *java::Number::floatValueMethodId); + } + + double Value::toDouble() const { + return jni::CallMethod(env, value.get(), *java::Number::doubleValueMethodId); + } + + long Value::toLong() const { + return jni::CallMethod(env, value.get(), *java::Number::longValueMethodId); + } + + bool Value::toBool() const { + return jni::CallMethod(env, value.get(), *java::Boolean::booleanValueMethodId); + } + + Value Value::get(const char* key) const { + jni::jobject* member = jni::CallMethod(env, value.get(), *java::Map::getMethodId, jni::Make(env, std::string(key)).get()); + return Value(env, jni::Local>(env, member)); + } + + Value Value::keyArray() const{ + jni::jobject* set = jni::CallMethod(env, value.get(), *java::Map::keySetMethodId); + jni::jobject* array = jni::CallMethod(env, set, *java::Set::toArrayMethodId); + return Value(env, jni::Local>(env, array)); + } + + int Value::getLength() const { + auto array = (jni::jarray*) value.get(); + return jni::GetArrayLength(env, *array); + } + + Value Value::get(const int index) const { + auto array = (jni::jarray*) value.get(); + return Value(env, jni::Local>(env, jni::GetObjectArrayElement(env, *array, index))); + } +} +} + diff --git a/MapboxGLAndroidSDK/src/cpp/style/value.hpp b/MapboxGLAndroidSDK/src/cpp/style/value.hpp new file mode 100644 index 000000000..b507c5ed1 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/value.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class Value { +public: + Value(jni::JNIEnv&, jni::Local>); + Value(jni::JNIEnv&, const jni::Object<>&); + + Value(Value&&) = default; + Value& operator=(Value&&) = delete; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; + + bool isNull() const; + bool isArray() const; + bool isObject() const; + bool isString() const; + bool isBool() const; + bool isNumber() const; + + std::string toString() const; + float toFloat() const; + double toDouble() const; + long toLong() const; + bool toBool() const; + Value get(const char* key) const; + Value keyArray() const; + int getLength() const; + Value get(const int index ) const; + + jni::JNIEnv& env; + jni::Local> value; +}; + +} +} diff --git a/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer.cpp b/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer.cpp new file mode 100644 index 000000000..3c30175bd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer.cpp @@ -0,0 +1,131 @@ +#include +#include +#include + +#include + +#include "attach_env.hpp" +#include "bitmap.hpp" + +#include "local_glyph_rasterizer_jni.hpp" + +/* + Android implementation of LocalGlyphRasterizer: + Draws CJK glyphs using locally available fonts. + + Follows pattern of GL JS implementation in that: + - Only CJK glyphs are drawn locally (because we can guess their metrics effectively) + * Render size/metrics determined experimentally using Noto Sans + - Configuration is done at map creation time by setting a "font family" + * JS uses a CSS font-family, this uses android.graphics.Typeface + https://developer.android.com/reference/android/graphics/Typeface.html + - We use heuristics to extract a font-weight based on the incoming font stack + * JS tries to extract multiple weights, this implementation only looks for + "bold" + + mbgl::LocalGlyphRasterizer is the portable interface + mbgl::LocalGlyphRasterizer::Impl stores platform-specific configuration data + mbgl::android::LocalGlyphRasterizer is the JNI wrapper + com.mapbox.mapboxsdk.text.LocalGlyphRasterizer is the Java implementation that + actually does the drawing + */ + +namespace mbgl { +namespace android { + +LocalGlyphRasterizer::LocalGlyphRasterizer() { + UniqueEnv env { AttachEnv() }; + + static auto& javaClass = jni::Class::Singleton(*env); + static auto constructor = javaClass.GetConstructor(*env); + + javaObject = jni::NewGlobal(*env, javaClass.New(*env, constructor)); +} + +PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& fontFamily, const bool bold, const GlyphID glyphID) { + UniqueEnv env { AttachEnv() }; + + static auto& javaClass = jni::Class::Singleton(*env); + static auto drawGlyphBitmap = javaClass.GetMethod (jni::String, jni::jboolean, jni::jchar)>(*env, "drawGlyphBitmap"); + + return Bitmap::GetImage(*env, + javaObject.Call(*env, + drawGlyphBitmap, + jni::Make(*env, fontFamily), + static_cast(bold), + static_cast(glyphID))); +} + +void LocalGlyphRasterizer::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android + +class LocalGlyphRasterizer::Impl { +public: + Impl(const optional fontFamily_) + : fontFamily(fontFamily_) + {} + + bool isConfigured() const { + return bool(fontFamily); + } + + PremultipliedImage drawGlyphBitmap(const FontStack& fontStack, GlyphID glyphID) { + bool bold = false; + for (auto font : fontStack) { + std::string lowercaseFont = platform::lowercase(font); + if (lowercaseFont.find("bold") != std::string::npos) { + bold = true; + break; + } + } + return androidLocalGlyphRasterizer.drawGlyphBitmap(*fontFamily, bold, glyphID); + } + +private: + optional fontFamily; + android::LocalGlyphRasterizer androidLocalGlyphRasterizer; +}; + +LocalGlyphRasterizer::LocalGlyphRasterizer(const optional& fontFamily) + : impl(std::make_unique(fontFamily)) {} + +LocalGlyphRasterizer::~LocalGlyphRasterizer() +{} + +bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) { + return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured(); +} + +Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) { + Glyph fixedMetrics; + if (!impl->isConfigured()) { + return fixedMetrics; + } + + fixedMetrics.id = glyphID; + + Size size(35, 35); + + fixedMetrics.metrics.width = size.width; + fixedMetrics.metrics.height = size.height; + fixedMetrics.metrics.left = 3; + fixedMetrics.metrics.top = -10; + fixedMetrics.metrics.advance = 24; + + PremultipliedImage rgbaBitmap = impl->drawGlyphBitmap(fontStack, glyphID); + + // Copy alpha values from RGBA bitmap into the AlphaImage output + fixedMetrics.bitmap = AlphaImage(size); + for (uint32_t i = 0; i < size.width * size.height; i++) { + fixedMetrics.bitmap.data[i] = + 0xff - round(0.2126 * rgbaBitmap.data[4 * i] + 0.7152 * rgbaBitmap.data[4 * i + 1] + + 0.0722 * rgbaBitmap.data[4 * i + 2]); + } + + return fixedMetrics; +} + +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer_jni.hpp b/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer_jni.hpp new file mode 100644 index 000000000..e80e84833 --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/text/local_glyph_rasterizer_jni.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +/* + android::LocalGlyphRasterizer is the JNI wrapper of + com/mapbox/mapboxsdk/text/LocalGlyphRasterizer + + mbgl::LocalGlyphRasterizer is the portable interface + Both implementations are in local_glyph_rasterizer.cpp + */ + +namespace mbgl { +namespace android { + +class LocalGlyphRasterizer { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/text/LocalGlyphRasterizer"; }; + + static void registerNative(jni::JNIEnv&); + + LocalGlyphRasterizer(); + + PremultipliedImage drawGlyphBitmap(const std::string& fontFamily, const bool bold, const char16_t glyphID); + +private: + jni::Global> javaObject; +}; + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index bc70cb70a..70485a726 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -117,6 +117,14 @@ public abstract class Source { @Keep protected native void nativeSetPrefetchZoomDelta(Integer delta); + @NonNull + @Keep + protected native void nativeSetMaxOverscaleFactorForParentTiles(Integer maxOverscaleFactor); + + @NonNull + @Keep + protected native Integer nativeGetMaxOverscaleFactorForParentTiles(); + public void setDetached() { detached = true; } diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index 31813cbe2..8aa760892 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -21,7 +21,7 @@ ext.nativeBuild = { nativeTargets -> if (abi != 'none') { externalNativeBuild { cmake { - path "../vendor/mapbox-gl-native/CMakeLists.txt" + path "../MapboxGLAndroidSDK/src/cpp/CMakeLists.txt" version "3.10.2" } } diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 77466d23d..338cfd1b3 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 77466d23d6b2f524c104373d546ac458035b0ec0 +Subproject commit 338cfd1b33dfe26b9402d79cc64609b944a9f1d1 From 4fcae9e2bb9b69fc345c3b41d68f451abec69447 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 3 Apr 2020 16:32:02 +0800 Subject: [PATCH 114/185] Make mapview unable to intercept scroll event. (#308) --- .../testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt index 2be42a542..750af7cac 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt @@ -75,6 +75,7 @@ open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { super.onViewAttachedToWindow(holder) if (holder is MapHolder) { val mapView = holder.mapView + mapView.isEnabled = false mapView.onStart() mapView.onResume() } From cedd2afecc7da4bb4f2ff73ca219555b9a6f903f Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 3 Apr 2020 16:32:51 +0800 Subject: [PATCH 115/185] Add log for canceled request. (#304) --- .../module/http/HttpRequestImpl.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java index 8903bbdf1..e2616360c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/http/HttpRequestImpl.java @@ -1,11 +1,9 @@ package com.mapbox.mapboxsdk.module.http; import android.os.Build; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; + import com.mapbox.mapboxsdk.BuildConfig; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.http.HttpIdentifier; @@ -13,6 +11,19 @@ import com.mapbox.mapboxsdk.http.HttpLogger; import com.mapbox.mapboxsdk.http.HttpRequest; import com.mapbox.mapboxsdk.http.HttpRequestUrl; import com.mapbox.mapboxsdk.http.HttpResponder; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.NoRouteToHostException; +import java.net.ProtocolException; +import java.net.SocketException; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Dispatcher; @@ -22,14 +33,6 @@ import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import javax.net.ssl.SSLException; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.NoRouteToHostException; -import java.net.ProtocolException; -import java.net.SocketException; -import java.net.UnknownHostException; - import static com.mapbox.mapboxsdk.module.http.HttpRequestUtil.toHumanReadableAscii; public class HttpRequestImpl implements HttpRequest { @@ -87,6 +90,7 @@ public class HttpRequestImpl implements HttpRequest { public void cancelRequest() { // call can be null if the constructor gets aborted (e.g, under a NoRouteToHostException). if (call != null) { + HttpLogger.log(Log.DEBUG, String.format("[HTTP] Cancel request %s", call.request().url())); call.cancel(); } } From f27b16562d3d15c8a0426134eaf52ad35a3d4c86 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 7 Apr 2020 14:35:39 +0800 Subject: [PATCH 116/185] Update change log for 9.1.0 (#309) * Update change log for 9.1.0 * Update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b488193..434860bc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [`Con - Added `in` expression for testing whether an item exists in an array or a substring exists in a string. ([#171](https://github.com/mapbox/mapbox-gl-native-android/pull/171)) - Introduced APIs and callbacks for customizing the style used in a `MapSnapshotter` snapshotter with runtime styling methods. ([#268](https://www.github.com/mapbox/mapbox-gl-native-android/pull/268), [#292](https://www.github.com/mapbox/mapbox-gl-native-android/pull/292)) - Added methods to set and get the sort key of features in a `FillLayer` and `LineLayer` at runtime. Features with a higher sort key will appear above features with a lower sort key. ([#209](https://github.com/mapbox/mapbox-gl-native-android/pull/209)) - - Introduced option to set the minimum and maximum pitch of a map. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) + - Introduced `MapboxMap.setMaxPitchPreference` and `MapboxMap.setMinPitchPreference` to constrain a map's pitch. ([#199](https://github.com/mapbox/mapbox-gl-native-android/pull/199)) - Introduced ability to configure the zoom level(s) that tiles are prefetched from by `Source`. This overrides the tile prefetch setting defined by the `Map` instance. ([#184](https://github.com/mapbox/mapbox-gl-native-android/pull/184)) ### Performance improvements @@ -22,7 +22,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [`Con - Fixed conversion of a `Map` object into a GeoJSON object. ([#16243](https://github.com/mapbox/mapbox-gl-native/pull/16243)) - Fixed issues that would cause an offline region to stop downloading before completion. ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230), [#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) - Fixed an issue where a `LineDasharray` value of `[1, 0]` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) - - Fixed Proguard configuration to prevent obfuscation of telemetry event classes. ([#195](https://github.com/mapbox/mapbox-gl-native-android/pull/195)) + - Fixed Proguard configuration to prevent obfuscation of telemetry event classes. ([#306](https://github.com/mapbox/mapbox-gl-native-android/pull/306)) - Fixed a crash that might occur during EGL window surface creation. ([#278](https://github.com/mapbox/mapbox-gl-native-android/pull/278)) - Fixed a bug that would cause local CJK glyphs to be rendered incorrectly when generated on a device with the high-contrast accessibility setting enabled. ([#289](https://github.com/mapbox/mapbox-gl-native-android/pull/289)) From 414e155af33d3a01ba0b7658fc119ca1756e6e65 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 10 Apr 2020 21:31:32 +0800 Subject: [PATCH 117/185] Not rebuild all files (#318) --- MapboxGLAndroidSDK/src/cpp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt index d031fafcd..f59a10e4d 100644 --- a/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt +++ b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -add_subdirectory(../../../vendor/mapbox-gl-native ../../../vendor/mapbox-gl-native) +add_subdirectory(../../../vendor/mapbox-gl-native ../../../vendor/mapbox-gl-native/${ANDROID_ABI}) add_library( mapbox-gl SHARED From 7ca1bcf821c06b6362526b6709bfca07c2c43bd5 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 14 Apr 2020 17:58:23 +0800 Subject: [PATCH 118/185] Fix onStyleImageMissing not fired in Snapshotter (#317) * Modify example to trigger OnStyleMissing callback * Fix onStyleImageMissing callback not works in snapshotter. * Update gl-native * Update doc * Fix android check --- .../mapboxsdk/snapshotter/MapSnapshotter.java | 17 ++++++++-- .../snapshot/MapSnapshotterActivity.java | 32 ++++++++++++++----- .../turf/MapSnapshotterWithinExpression.kt | 3 ++ vendor/mapbox-gl-native | 2 +- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index dcbcb22b9..fc9ad758b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -108,9 +108,18 @@ public class MapSnapshotter { public interface Observer { /** - * Called when snapshotter finishes loading it's style. + * Called when snapshotter finishes loading its style. */ void onDidFinishLoadingStyle(); + + /** + * Called when the map is missing an icon.The icon should be added synchronously with + * {@link MapSnapshotter#addImage(String, Bitmap, boolean)} to be rendered on the current zoom level. + * When loading icons asynchronously, you can load a placeholder image and replace it when you icon has loaded. + * + * @param imageName the id of the icon that is missing + */ + void onStyleImageMissing(String imageName); } /** @@ -513,7 +522,7 @@ public class MapSnapshotter { * @param bitmap the pre-multiplied Bitmap * @param sdf the flag indicating image is an SDF or template image */ - private void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { + public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf) { nativeAddImages(new Image[] {toImage(new Style.Builder.ImageWrapper(name, bitmap, sdf))}); } @@ -797,7 +806,9 @@ public class MapSnapshotter { */ @Keep protected void onStyleImageMissing(String imageName) { - onSnapshotFailed("style image is missing: " + imageName); + if (observer != null) { + observer.onStyleImageMissing(imageName); + } } private void checkThread() { diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java index c01254862..6db147653 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java @@ -138,7 +138,8 @@ public class MapSnapshotterActivity extends AppCompatActivity { // marker source FeatureCollection markerCollection = FeatureCollection.fromFeatures(new Feature[] { - Feature.fromGeometry(Point.fromLngLat(4.91638, 52.34673), featureProperties("2", "Car")) + Feature.fromGeometry(Point.fromLngLat(4.91638, 52.35673), featureProperties("1", "Android")), + Feature.fromGeometry(Point.fromLngLat(4.91638, 12.34673), featureProperties("2", "Car")) }); Source markerSource = new GeoJsonSource(MARKER_SOURCE, markerCollection); @@ -156,17 +157,32 @@ public class MapSnapshotterActivity extends AppCompatActivity { builder.withImage("Car", Objects.requireNonNull(carBitmap), false) .withSources(markerSource) .withLayers(markerSymbolLayer); - options.withCameraPosition(new CameraPosition.Builder() - .target(new LatLng(5.537109374999999, - 52.07950600379697)) - .zoom(1) - .padding(1, 1, 1, 1) - .build() - ); + options + .withRegion(null) + .withCameraPosition(new CameraPosition.Builder() + .target(new LatLng(5.537109374999999, + 52.07950600379697)) + .zoom(1) + .padding(1, 1, 1, 1) + .build() + ); } options.withStyleBuilder(builder); MapSnapshotter snapshotter = new MapSnapshotter(MapSnapshotterActivity.this, options); + snapshotter.setObserver(new MapSnapshotter.Observer() { + @Override + public void onDidFinishLoadingStyle() { + Timber.i("onDidFinishLoadingStyle"); + } + + @Override + public void onStyleImageMissing(String imageName) { + Bitmap androidIcon = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.ic_android_2)); + snapshotter.addImage(imageName, androidIcon, false); + } + }); + snapshotter.start(snapshot -> { Timber.i("Got the snapshot"); ImageView imageView = new ImageView(MapSnapshotterActivity.this); diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/MapSnapshotterWithinExpression.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/MapSnapshotterWithinExpression.kt index 0d2c04818..4f1200a7e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/MapSnapshotterWithinExpression.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/turf/MapSnapshotterWithinExpression.kt @@ -48,6 +48,9 @@ class MapSnapshotterWithinExpression : AppCompatActivity() { } private val snapshotterObserver = object : MapSnapshotter.Observer { + override fun onStyleImageMissing(imageName: String?) { + } + override fun onDidFinishLoadingStyle() { // Show only POI labels inside geometry using within expression (snapshotter.getLayer("poi-label") as SymbolLayer).setFilter( diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 338cfd1b3..be9ca95e9 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 338cfd1b33dfe26b9402d79cc64609b944a9f1d1 +Subproject commit be9ca95e9ab3be296177bf6ec0f1b05f7ade8749 From d32133790c0ede1d4d88e0075d0393bba48c8f8d Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 15 Apr 2020 17:53:30 +0800 Subject: [PATCH 119/185] Export all activities. (#323) --- .../src/main/AndroidManifest.xml | 225 ++++++++++++------ 1 file changed, 158 insertions(+), 67 deletions(-) diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 66435115e..c5d2cb098 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ - + @@ -8,6 +8,7 @@ @@ -28,6 +30,7 @@ + android:exported="true" + android:label="@string/activity_camera_position" + android:theme="@style/NoActionBar"> @@ -140,6 +152,7 @@ + android:name=".activity.fragment.FragmentBackStackActivity" + android:description="@string/description_map_fragment_backstack" + android:exported="true" + android:label="@string/activity_map_fragment_backstack" + android:launchMode="singleInstance"> + android:name="@string/category" + android:value="@string/category_integration" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.style.GradientLineActivity" + android:description="@string/description_gradient_line" + android:exported="true" + android:label="@string/activity_gradient_line"> + android:name="@string/category" + android:value="@string/category_style" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.storage.CacheManagementActivity" + android:description="@string/description_cache_management" + android:exported="true" + android:label="@string/activity_cache_management"> + android:name="@string/category" + android:value="@string/category_storage" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.maplayout.OverlayMapActivity" + android:description="@string/description_overlay" + android:exported="true" + android:label="@string/activity_overlay"> + android:name="@string/category" + android:value="@string/category_maplayout" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.maplayout.TextureRecyclerViewActivity" + android:description="@string/description_recyclerview_textureview" + android:exported="true" + android:label="@string/activity_recyclerview_textureview"> + android:name="@string/category" + android:value="@string/category_integration" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.maplayout.GLSurfaceRecyclerViewActivity" + android:description="@string/description_recyclerview_glsurfaceview" + android:exported="true" + android:label="@string/activity_recyclerview_glsurfaceview"> + android:name="@string/category" + android:value="@string/category_integration" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.fragment.NestedViewPagerActivity" + android:description="@string/description_nested_viewpager" + android:exported="true" + android:label="@string/activity_nested_viewpager"> + android:name="@string/category" + android:value="@string/category_integration" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.offline.DownloadRegionActivity" + android:description="@string/description_region" + android:exported="true" + android:label="@string/activity_region"> + android:name="@string/category" + android:value="@string/category_offline" /> + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + android:name=".activity.espresso.PixelTestActivity" + android:screenOrientation="portrait" /> @@ -1065,10 +1156,10 @@ - - + + From 77d0d5e5cf625679c7439c07deaed7e6d8bd5b3e Mon Sep 17 00:00:00 2001 From: Chloe Krawczyk Date: Wed, 15 Apr 2020 02:56:54 -0700 Subject: [PATCH 120/185] Add bindings for circle-sort-key (#322) * Update generate-style-code.js * add jni bindings for circle-sort-key * update mapbox-gl-native to latest * Revert "add jni bindings for circle-sort-key" This reverts commit cdd6049d Co-authored-by: kevin --- .../src/cpp/style/layers/circle_layer.cpp | 6 +++++ .../src/cpp/style/layers/circle_layer.hpp | 2 ++ .../mapboxsdk/style/layers/CircleLayer.java | 16 ++++++++++++ .../style/layers/PropertyFactory.java | 24 +++++++++++++++-- .../testapp/style/CircleLayerTest.java | 26 +++++++++++++++++++ scripts/generate-style-code.js | 10 +++---- vendor/mapbox-gl-native | 2 +- 7 files changed, 78 insertions(+), 8 deletions(-) diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp index a7fae5e23..2be603360 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp @@ -37,6 +37,11 @@ namespace android { // Property getters + jni::Local> CircleLayer::getCircleSortKey(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toCircleLayer(layer).getCircleSortKey())); + } + jni::Local> CircleLayer::getCircleRadius(jni::JNIEnv& env) { using namespace mbgl::android::conversion; return std::move(*convert>>(env, toCircleLayer(layer).getCircleRadius())); @@ -237,6 +242,7 @@ namespace android { jni::MakePeer, "initialize", "finalize", + METHOD(&CircleLayer::getCircleSortKey, "nativeGetCircleSortKey"), METHOD(&CircleLayer::getCircleRadiusTransition, "nativeGetCircleRadiusTransition"), METHOD(&CircleLayer::setCircleRadiusTransition, "nativeSetCircleRadiusTransition"), METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"), diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp index 40dca91e2..daa28571b 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp @@ -26,6 +26,8 @@ public: // Properties + jni::Local> getCircleSortKey(jni::JNIEnv&); + jni::Local> getCircleRadius(jni::JNIEnv&); void setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Local> getCircleRadiusTransition(jni::JNIEnv&); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index 03f926ed5..d9845634c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -143,6 +143,18 @@ public class CircleLayer extends Layer { // Property getters + /** + * Get the CircleSortKey property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getCircleSortKey() { + checkThread(); + return (PropertyValue) new PropertyValue("circle-sort-key", nativeGetCircleSortKey()); + } + /** * Get the CircleRadius property * @@ -477,6 +489,10 @@ public class CircleLayer extends Layer { nativeSetCircleStrokeOpacityTransition(options.getDuration(), options.getDelay()); } + @NonNull + @Keep + private native Object nativeGetCircleSortKey(); + @NonNull @Keep private native Object nativeGetCircleRadius(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index b7a90c656..b3ae7a325 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -1826,7 +1826,7 @@ public class PropertyFactory { } /** - * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key when they overlap. Features with a lower sort key will have priority over other features when doing placement. + * Sorts features in ascending order based on this value. Features with lower sort keys are drawn and placed first. When {@link PropertyFactory#iconAllowOverlap} or {@link PropertyFactory#textAllowOverlap} is `false`, features with a lower sort key will have priority during placement. When {@link PropertyFactory#iconAllowOverlap} or {@link PropertyFactory#textAllowOverlap} is set to `true`, features with a higher sort key will overlap over features with a lower sort key. * * @param value a Float value * @return property wrapper around Float @@ -1836,7 +1836,7 @@ public class PropertyFactory { } /** - * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key when they overlap. Features with a lower sort key will have priority over other features when doing placement. + * Sorts features in ascending order based on this value. Features with lower sort keys are drawn and placed first. When {@link PropertyFactory#iconAllowOverlap} or {@link PropertyFactory#textAllowOverlap} is `false`, features with a lower sort key will have priority during placement. When {@link PropertyFactory#iconAllowOverlap} or {@link PropertyFactory#textAllowOverlap} is set to `true`, features with a higher sort key will overlap over features with a lower sort key. * * @param value a Float value * @return property wrapper around Float @@ -2595,4 +2595,24 @@ public class PropertyFactory { return new LayoutPropertyValue<>("text-optional", value); } + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue circleSortKey(Float value) { + return new LayoutPropertyValue<>("circle-sort-key", value); + } + + /** + * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue circleSortKey(Expression value) { + return new LayoutPropertyValue<>("circle-sort-key", value); + } + } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java index fbe812c7d..1430f304c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java @@ -99,6 +99,32 @@ public class CircleLayerTest extends BaseLayerTest { + @Test + @UiThreadTest + public void testCircleSortKeyAsConstant() { + Timber.i("circle-sort-key"); + assertNotNull(layer); + assertNull(layer.getCircleSortKey().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(circleSortKey(propertyValue)); + assertEquals(layer.getCircleSortKey().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testCircleSortKeyAsExpression() { + Timber.i("circle-sort-key-expression"); + assertNotNull(layer); + assertNull(layer.getCircleSortKey().getExpression()); + + // Set and Get + Expression expression = number(Expression.get("undefined")); + layer.setProperties(circleSortKey(expression)); + assertEquals(layer.getCircleSortKey().getExpression(), expression); + } + @Test @UiThreadTest public void testCircleRadiusTransition() { diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index bc3f67c9a..3ed77405a 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -7,7 +7,7 @@ const spec = require('../vendor/mapbox-gl-native/scripts/style-spec'); const _ = require('lodash'); // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 -delete spec.layout_circle["circle-sort-key"] +//delete spec.layout_circle["circle-sort-key"] //delete spec.layout_line["line-sort-key"] //delete spec.layout_fill["fill-sort-key"] @@ -384,14 +384,14 @@ for (const layer of layers) { } // Jni -const layerHpp = ejs.compile(fs.readFileSync('vendor/mapbox-gl-native/platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); -const layerCpp = ejs.compile(fs.readFileSync('vendor/mapbox-gl-native/platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); +const layerHpp = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs', 'utf8'), {strict: true}); +const layerCpp = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs', 'utf8'), {strict: true}); for (const layer of layers) { const layerFileName = layer.type.replace('-', '_'); - writeIfModified(`vendor/mapbox-gl-native/platform/android/src/style/layers/${layerFileName}_layer.hpp`, layerHpp(layer)); - writeIfModified(`vendor/mapbox-gl-native/platform/android/src/style/layers/${layerFileName}_layer.cpp`, layerCpp(layer)); + writeIfModified(`MapboxGLAndroidSDK/src/cpp/style/layers/${layerFileName}_layer.hpp`, layerHpp(layer)); + writeIfModified(`MapboxGLAndroidSDK/src/cpp/style/layers/${layerFileName}_layer.cpp`, layerCpp(layer)); } // Java PropertyFactory diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index be9ca95e9..66ac55445 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit be9ca95e9ab3be296177bf6ec0f1b05f7ade8749 +Subproject commit 66ac55445998718b28a6fbd4a4094a10426627a9 From 1cb8fb7a017039108b7aa454a1112014fcbc0321 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 16 Apr 2020 14:31:38 +0800 Subject: [PATCH 121/185] Add interface for stretchable image (#314) * Add interface for stretch image * Add demo for stretch image api * Add stretchable image demp * Update stretchable image test activity. * Revert change for SymbolLayerActivity This reverts commit 22bbb798 --- MapboxGLAndroidSDK/src/cpp/map/image.cpp | 41 ++- .../java/com/mapbox/mapboxsdk/maps/Image.java | 11 + .../mapbox/mapboxsdk/maps/ImageContent.java | 66 ++++ .../mapbox/mapboxsdk/maps/ImageStretches.java | 54 +++ .../java/com/mapbox/mapboxsdk/maps/Style.java | 320 +++++++++++++++++- .../src/main/AndroidManifest.xml | 12 + .../src/main/assets/stretchable_image.geojson | 49 +++ .../style/StretchableImageActivity.java | 198 +++++++++++ .../src/main/res/drawable-hdpi/popup.png | Bin 0 -> 1677 bytes .../main/res/drawable-hdpi/popup_debug.png | Bin 0 -> 1915 bytes .../res/layout/activity_stretchable_image.xml | 14 + .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/titles.xml | 1 + 13 files changed, 760 insertions(+), 7 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/assets/stretchable_image.geojson create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StretchableImageActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml diff --git a/MapboxGLAndroidSDK/src/cpp/map/image.cpp b/MapboxGLAndroidSDK/src/cpp/map/image.cpp index 10c32d257..04f5b1a35 100644 --- a/MapboxGLAndroidSDK/src/cpp/map/image.cpp +++ b/MapboxGLAndroidSDK/src/cpp/map/image.cpp @@ -13,6 +13,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i static auto bufferField = javaClass.GetField>(env, "buffer"); static auto nameField = javaClass.GetField(env, "name"); static auto sdfField = javaClass.GetField(env, "sdf"); + static auto contentField = javaClass.GetField>(env, "content"); + static auto stretchXField = javaClass.GetField>(env, "stretchX"); + static auto stretchYField = javaClass.GetField>(env, "stretchY"); auto height = image.Get(env, heightField); auto width = image.Get(env, widthField); @@ -20,7 +23,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i auto pixels = image.Get(env, bufferField); auto name = jni::Make(env, image.Get(env, nameField)); auto sdf = (bool) image.Get(env, sdfField); - + auto content = image.Get(env, contentField); + auto stretchX = image.Get(env, stretchXField); + auto stretchY = image.Get(env, stretchYField); jni::NullCheck(env, pixels.get()); std::size_t size = pixels.Length(env); @@ -29,8 +34,38 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i throw mbgl::util::StyleImageException("Image pixel count mismatch"); } - jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); - return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf}; + jni::GetArrayRegion(env, *pixels, 0, size, + reinterpret_cast(premultipliedImage.data.get())); + + style::ImageStretches imageStretchesX = {}; + style::ImageStretches imageStretchesY = {}; + if (stretchX.get()) { + std::size_t sizeX = stretchX.Length(env); + for (jni::jsize i = 0; i < sizeX - 1; i += 2) { + imageStretchesX.push_back({stretchX.Get(env, i), stretchX.Get(env, i + 1)}); + } + } + if (stretchY.get()) { + std::size_t sizeY = stretchY.Length(env); + for (jni::jsize i = 0; i < sizeY - 1; i += 2) { + imageStretchesY.push_back({stretchY.Get(env, i), stretchY.Get(env, i + 1)}); + } + } + + if (content) { + const style::ImageContent imageContent = style::ImageContent{content.Get(env, 0), + content.Get(env, 1), + content.Get(env, 2), + content.Get(env, 3)}; + return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf, + imageStretchesX, + imageStretchesY, + std::move(imageContent)}; + } + + return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf, + imageStretchesX, + imageStretchesY}; } void Image::registerNative(jni::JNIEnv &env) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java index 380f78b07..8a648de31 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java @@ -10,13 +10,24 @@ public class Image { private final int width; private final int height; private final boolean sdf; + private final float[] content; + private final float[] stretchX; + private final float[] stretchY; public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf) { + this(buffer, pixelRatio, name, width, height, sdf, null, null, null); + } + + public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf, + float[] stretchX, float[] stretchY, float[] content) { this.buffer = buffer; this.pixelRatio = pixelRatio; this.name = name; this.width = width; this.height = height; this.sdf = sdf; + this.content = content; + this.stretchX = stretchX; + this.stretchY = stretchY; } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java new file mode 100644 index 000000000..4b72280c4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.maps; + +/** + * Describes the image content, e.g. where text can be fit into an image. + *

    + * When sizing icons with icon-text-fit, + * the icon size will be adjusted so that the this content box fits exactly around the text. + */ +public final class ImageContent { + + private final float left; + private final float top; + private final float right; + private final float bottom; + + public ImageContent(float left, + float top, + float right, + float bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /** + * Get the array for this content, sorted by left, top, right, bottom. + * + * @return the content array. + */ + public float[] getContentArray() { + float[] array = new float[4]; + array[0] = left; + array[1] = top; + array[2] = right; + array[3] = bottom; + return array; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ImageContent)) { + return false; + } + ImageContent other = (ImageContent) obj; + return this.left == other.left + && this.top == other.top + && this.right == other.right + && this.bottom == other.bottom; + } + + @Override + public int hashCode() { + int result = (left != +0.0f ? Float.floatToIntBits(left) : 0); + result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0); + result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0); + result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0); + return result; + } + + @Override + public String toString() { + return "[ " + "left: " + left + ", " + "top: " + top + ", " + "right: " + right + ", " + "bottom: " + bottom + " ]"; + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java new file mode 100644 index 000000000..ec3357167 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java @@ -0,0 +1,54 @@ +package com.mapbox.mapboxsdk.maps; + + +/** + * Describes the image stretch areas. + */ +public final class ImageStretches { + + private final float first; + private final float second; + + public ImageStretches(float first, + float second) { + this.first = first; + this.second = second; + } + + /** + * The first stretchable part in pixel units. + */ + public float getFirst() { + return first; + } + + /** + * The second stretchable part in pixel units. + */ + public float getSecond() { + return second; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ImageStretches)) { + return false; + } + ImageStretches other = (ImageStretches) obj; + return this.first == other.first + && this.second == other.second; + } + + @Override + public int hashCode() { + int result = (first != +0.0f ? Float.floatToIntBits(first) : 0); + result = 31 * result + (second != +0.0f ? Float.floatToIntBits(second) : 0); + return result; + } + + @Override + public String toString() { + return "[ " + "first: " + first + ", " + "second: " + second + " ]"; + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index fe88e081a..3a9c0cd4f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -3,12 +3,9 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringDef; import android.util.DisplayMetrics; import android.util.Pair; + import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; @@ -26,6 +23,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringDef; + /** * The proxy object for current map style. *

    @@ -317,6 +319,20 @@ public class Style { addImage(name, image, false); } + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull String name, @NonNull Bitmap image, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImage(name, image, false, stretchX, stretchY, content); + } + /** * Adds an drawable to be converted into a bitmap to be used in the map's style * @@ -331,6 +347,26 @@ public class Style { addImage(name, bitmap, false); } + /** + * Adds an drawable to be converted into a bitmap to be used in the map's style + * + * @param name the name of the image + * @param drawable the drawable instance to convert + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull String name, @NonNull Drawable drawable, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImage(name, bitmap, false, stretchX, stretchY, content); + } + /** * Adds an image to be used in the map's style * @@ -343,6 +379,25 @@ public class Style { nativeMap.addImages(new Image[] {toImage(new Builder.ImageWrapper(name, bitmap, sdf))}); } + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + nativeMap.addImages(new Image[] { + toImage(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content))}); + } + /** * Adds an image asynchronously, to be used in the map's style. * @@ -353,6 +408,22 @@ public class Style { addImageAsync(name, image, false); } + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull String name, @NonNull Bitmap image, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + addImageAsync(name, image, false, stretchX, stretchY, content); + } + /** * Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style. * @@ -367,6 +438,27 @@ public class Style { addImageAsync(name, bitmap, false); } + + /** + * Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style. + * + * @param name the name of the image + * @param drawable the drawable instance to convert + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull String name, @NonNull Drawable drawable, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImageAsync(name, bitmap, false, stretchX, stretchY, content); + } + /** * Adds an image asynchronously, to be used in the map's style. * @@ -379,6 +471,25 @@ public class Style { new BitmapImageConversionTask(nativeMap).execute(new Builder.ImageWrapper(name, bitmap, sdf)); } + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + new BitmapImageConversionTask(nativeMap) + .execute(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content)); + } + /** * Adds images to be used in the map's style. * @@ -388,6 +499,19 @@ public class Style { addImages(images, false); } + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImages(@NonNull HashMap images, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImages(images, false, stretchX, stretchY, content); + } + /** * Adds images to be used in the map's style. * @@ -406,6 +530,31 @@ public class Style { nativeMap.addImages(convertedImages); } + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImages(@NonNull HashMap images, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + Image[] convertedImages = new Image[images.size()]; + int index = 0; + for (Builder.ImageWrapper imageWrapper + : Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content)) { + convertedImages[index] = toImage(imageWrapper); + index++; + } + + nativeMap.addImages(convertedImages); + } + /** * Adds images asynchronously, to be used in the map's style. * @@ -415,6 +564,19 @@ public class Style { addImagesAsync(images, false); } + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImagesAsync(@NonNull HashMap images, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImagesAsync(images, false, stretchX, stretchY, content); + } + /** * Adds images asynchronously, to be used in the map's style. * @@ -426,6 +588,24 @@ public class Style { new BitmapImageConversionTask(nativeMap).execute(Builder.ImageWrapper.convertToImageArray(images, sdf)); } + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImagesAsync(@NonNull HashMap images, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImages"); + new BitmapImageConversionTask(nativeMap) + .execute(Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content)); + } + /** * Removes an image from the map's style. * @@ -830,6 +1010,26 @@ public class Style { return this.withImage(id, bitmap, false); } + /** + * Will add the drawable as image when the map style has loaded. + * + * @param id the id for the image + * @param drawable the drawable to be converted and added + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Drawable drawable, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + return this.withImage(id, bitmap, false, stretchX, stretchY, content); + } + /** * Will add the drawables as images when the map style has loaded. * @@ -853,6 +1053,22 @@ public class Style { return this.withImage(id, image, false); } + /** + * Will add the image when the map style has loaded. + * + * @param id the id for the image + * @param image the image to be added + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Bitmap image, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + return this.withImage(id, image, false, stretchX, stretchY, content); + } + /** * Will add the images when the map style has loaded. * @@ -884,6 +1100,29 @@ public class Style { return this.withImage(id, bitmap, sdf); } + /** + * Will add the drawable as image when the map style has loaded. + * + * @param id the id for the image + * @param drawable the drawable to be converted and added + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Drawable drawable, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + return this.withImage(id, bitmap, sdf, stretchX, stretchY, content); + } + /** * Will add the drawables as images when the map style has loaded. * @@ -917,6 +1156,25 @@ public class Style { return this; } + /** + * Will add the image when the map style has loaded. + * + * @param id the id for the image + * @param image the image to be added + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Bitmap image, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + images.add(new ImageWrapper(id, image, sdf, stretchX, stretchY, content)); + return this; + } + /** * Will add the images when the map style has loaded. * @@ -967,11 +1225,22 @@ public class Style { Bitmap bitmap; String id; boolean sdf; + List stretchX; + List stretchY; + ImageContent content; public ImageWrapper(String id, Bitmap bitmap, boolean sdf) { + this(id, bitmap, sdf, null, null, null); + } + + public ImageWrapper(String id, Bitmap bitmap, boolean sdf, List stretchX, + List stretchY, ImageContent content) { this.id = id; this.bitmap = bitmap; this.sdf = sdf; + this.stretchX = stretchX; + this.stretchY = stretchY; + this.content = content; } public Bitmap getBitmap() { @@ -986,6 +1255,18 @@ public class Style { return sdf; } + public List getStretchX() { + return stretchX; + } + + public List getStretchY() { + return stretchY; + } + + public ImageContent getContent() { + return content; + } + public static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf) { ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()]; List keyList = new ArrayList<>(bitmapHashMap.keySet()); @@ -995,6 +1276,19 @@ public class Style { } return images; } + + public static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf, + List stretchX, + List stretchY, + ImageContent content) { + ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()]; + List keyList = new ArrayList<>(bitmapHashMap.keySet()); + for (int i = 0; i < bitmapHashMap.size(); i++) { + String id = keyList.get(i); + images[i] = new ImageWrapper(id, bitmapHashMap.get(id), sdf, stretchX, stretchY, content); + } + return images; + } } public class LayerWrapper { @@ -1059,6 +1353,24 @@ public class Style { bitmap.copyPixelsToBuffer(buffer); float pixelRatio = (float) bitmap.getDensity() / DisplayMetrics.DENSITY_DEFAULT; + if (imageWrapper.getStretchX() != null && imageWrapper.getStretchY() != null) { + float[] arrayX = new float[imageWrapper.getStretchX().size() * 2]; + for (int i = 0; i < imageWrapper.getStretchX().size(); i++) { + arrayX[i * 2] = imageWrapper.getStretchX().get(i).getFirst(); + arrayX[i * 2 + 1] = imageWrapper.getStretchX().get(i).getSecond(); + } + + float[] arrayY = new float[imageWrapper.getStretchY().size() * 2]; + for (int i = 0; i < imageWrapper.getStretchY().size(); i++) { + arrayY[i * 2] = imageWrapper.getStretchY().get(i).getFirst(); + arrayY[i * 2 + 1] = imageWrapper.getStretchY().get(i).getSecond(); + } + return new Image(buffer.array(), pixelRatio, imageWrapper.id, + bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf, arrayX, arrayY, + imageWrapper.getContent() == null ? null : imageWrapper.getContent().getContentArray() + ); + } + return new Image(buffer.array(), pixelRatio, imageWrapper.id, bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf ); diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index c5d2cb098..e89902d7e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1123,6 +1123,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + { + Bitmap popup = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup)); + Bitmap popupDebug = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup_debug)); + + // The two (blue) columns of pixels that can be stretched horizontally: + // - the pixels between x: 25 and x: 55 can be stretched + // - the pixels between x: 85 and x: 115 can be stretched. + List stretchX = new ArrayList<>(); + stretchX.add(new ImageStretches(25, 55)); + stretchX.add(new ImageStretches(85, 115)); + + // The one (red) row of pixels that can be stretched vertically: + // - the pixels between y: 25 and y: 100 can be stretched + List stretchY = new ArrayList<>(); + stretchY.add(new ImageStretches(25, 100)); + + // This part of the image that can contain text ([x1, y1, x2, y2]): + ImageContent content = new ImageContent(25, 25, 115, 100); + + style.addImage(NAME_POPUP, popup, stretchX, stretchY, content); + style.addImage(NAME_POPUP_DEBUG, popupDebug, stretchX, stretchY, content); + new LoadFeatureTask(StretchableImageActivity.this).execute(); + }); + } + + private void onFeatureLoaded(String json) { + if (json == null) { + Timber.e("json is null."); + return; + } + + Style style = mapboxMap.getStyle(); + if (style != null) { + FeatureCollection featureCollection = FeatureCollection.fromJson(json); + GeoJsonSource stretchSource = new GeoJsonSource(STRETCH_SOURCE, featureCollection); + SymbolLayer stretchLayer = new SymbolLayer(STRETCH_LAYER, STRETCH_SOURCE) + .withProperties( + textField(get("name")), + iconImage(get("image-name")), + iconAllowOverlap(true), + textAllowOverlap(true), + iconTextFit(ICON_TEXT_FIT_BOTH)); + + // the original, unstretched image for comparison + Point point = Point.fromLngLat(-70, 0); + Feature feature = Feature.fromGeometry(point); + FeatureCollection originalCollection = FeatureCollection.fromFeature(feature); + GeoJsonSource originalSource = new GeoJsonSource(ORIGINAL_SOURCE, originalCollection); + SymbolLayer originalLayer = new SymbolLayer(ORIGINAL_LAYER, ORIGINAL_SOURCE); + + style.addSource(stretchSource); + style.addSource(originalSource); + style.addLayer(stretchLayer); + style.addLayer(originalLayer); + } + } + + private static class LoadFeatureTask extends AsyncTask { + + private WeakReference activity; + + private LoadFeatureTask(StretchableImageActivity activity) { + this.activity = new WeakReference<>(activity); + } + + @Override + protected String doInBackground(Void... params) { + StretchableImageActivity activity = this.activity.get(); + if (activity != null) { + String json = null; + try { + json = GeoParseUtil.loadStringFromAssets(activity.getApplicationContext(), "stretchable_image.geojson"); + } catch (IOException exception) { + Timber.e(exception, "Could not read feature"); + } + + return json; + } + return null; + } + + @Override + protected void onPostExecute(String json) { + super.onPostExecute(json); + StretchableImageActivity activity = this.activity.get(); + if (activity != null) { + activity.onFeatureLoaded(json); + } + } + } + + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + +} diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png new file mode 100644 index 0000000000000000000000000000000000000000..41f38e873ad1271b7d20c0ab9202ba2aafafc8c5 GIT binary patch literal 1677 zcmeAS@N?(olHy`uVBq!ia0vp^Js`}%3?ygDZRBBKU|JmD6XFWw4t2o9#02yLBO@ck zBM=6JWCjBkFo1g#$O8%kxeyXA4p9u}LKtv05LqAzu@0^b$OQsXQBg%jMWCg;yuAGU z{30SEQc_Yt5hW!hZEbBfHa2#4b}lY1Jv}`$Gc!j=N1#feE}&`N-rhbwKH=fvKm*}| zK*by!9Gsk-KrO<;!a&nxWo6~$|=IQAP zG|J!KKQuHnEG#TCGBP?kIyE&lEiElQJv}osGdnvwFE6jOw6w9Yv9-0ex3_ola=Oorca+fd-m)(bLPyOH*dj$1&bCfTD*Aik|j%)E?v58*|L=@S8my|W&8H+ zJ9qBfzkmOM0|yQtK78cJk>kgYpEz;iQ zQ895zX&G4+buC>}GYcz6pWu+N@QAdG+@j)=@`~z)=9c!3&fdQMiIb;Jn=yOA@)avr zuUQB3$IgR?&Rn>7>B^1UckexX{N(Ag=PzEq0=nq!yH8)fe*69d=m?-2{y+iHEfD7b zU36e;kUS`|lDyqr9%%6YHvlFiPEQxdkcwMx@1zF{2THIe97s6Yq$DPA^j(MUJ zH(d>?+Y;X25cv9ltBJMR`DmYL^-;D!#~g(f3!eNFX-_n4ZF#`+X7{;0&)HS{jm&53 zf0torKlfik{row`gHgJxOrmlxOz@NQE7R!xeXb#C=Dp)}d!;E`^*hd` z$vfn_56qe-=Bps|rAguCM~Rgi5Ae7+O;hkpv#HTJr}yX{$D%!5t=m^FJt%WWFlA@& zhhJ(E^>YMTEcxsgAGLKlwd_dEgpyehf~hD>{)*7g`iIIvxm~AYV4a+eOS0w8nRwEDd8}I zJ%J}#;;_UqgEqsSMADe24(lA$&+7ijwQiN3`s!D=wyo0JvijAk{o+EMx@~_y=&beg zJM0~GhTEqwB)Ra|L0|W1%~O-a%#Fn6)D%wnbVTMD!{le-dkgL?IUM6Wqr1{kf7-eQ z+i&k#uzcOCMZ3J_9xc7TBf5=i?)FnQyUo{JjrHz2aNJJo_tqO)Ou->b{NFpR*#7s^ zj)h(Gb-tZ`{6ApzbUx7=b*tZZ2B}_o)!WQm7O(NF>1}_l*0Fz&90D5t9&F@V&K{JT z7<9q+<>{n>Ia?+GKbC%B1~yVa~fe#m+Ci z?fdT(kM*>z3uHPn`?cN9gqAFsyZU2)RZv!?l*c?GgwFTYi4XH%;kft7W4rRh z{Yj_KpZz@h!h5c*F*`R)OqRLo#jEWeJ3+}st7=tpapsF{>5>x{&%M&P(zx2F3_m{VORnD~M-CFS9(pF<3sC@Kv^>bP0l+XkK%@v8) literal 0 HcmV?d00001 diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png new file mode 100644 index 0000000000000000000000000000000000000000..f6667408f107c2d54cabe20be933220aaeda9d85 GIT binary patch literal 1915 zcmcIji8qvM7#}0c48sVMZETUGn7In=W=58iB>SLg8rRU3lC6y_GbDT0psqEtj3ln) zO2i<`jHMbG+@vg(y{A8`##U}dw%cld(ZdXvbVEBz*XQ72n1nc zZQ%gc#BYzJD2R8}tE3?iXt%ws(=m|#NNjBUNcI0~L!nTRiin5^i^7dCihjqI@7Npx z87PBP7&q%e@@6XBY;uHM5QWEW(m)EJsHmu=r3DT}AP};$vI+_cDk>_VqOGlMU|=9F zE-oP<0f)m44Gm39OmH|HV1g;2cKrBpTU%RKSJ&@?=E6D@iU%z)A}J{egTcU{yu3Wn zM5EE_>gt-Bnm}1cM@Lsz*J!&j5HyEC%+1Y#EFO<15D1o*mNqsvK=$Oxlg`f0E-o%a zBGJRcSVo134XUrB#zw*O zl-}pxu+h}i)Y8(@+S=OQ-rmvC(b?JA)z!sjvpF12cXxMBPfu@e@9WpExm<34fB(S1 z0FTET92^`T9v&GP86O{?nwpxPo}QVRnVXxNpP&Eo<;&vYBA?G+T3T9OUS3&QSzTRS zUtbpp1RLP6jSU+pBNE(TOt6EUBSZu$x9g}{&q<+zo_TyO0wQ}DU5 zZ7gt3SB7T)9B_5SAtlIh&H}kRuF62AEjC{9 zy4CqeI7JjEraSYFjE{zmkDS2VX}Cru@pbFNvV$(?@=Z~wFy}mX6!#}@BTAzFZ7&1a zi&aWwA$o)X&tAMbH`^K@Zr0RwA|r0lFanqG(cn`cD@HSMtY-ceo0MZ5evx+ zojxhESB#*LNocMPyOfZwXK^1{?ImdgzZvDyhB>UMomAPB$_)tE!=J_T3|Qg>5jA_im5+}A3%RTfRhb~ERnT6IRzjwGkRN%?c{{m-H=?(w@ literal 0 HcmV?d00001 diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml new file mode 100644 index 000000000..09b10bf1d --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index f90653ffe..6f61fb649 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -20,6 +20,7 @@ Offline Map example Download an offline region. Usage of the within expression on a buffered geometry + Usage of the stretchable image as a background for text. Update metadata example Delete region example Change resources cache path example diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 637d3b774..23c227f23 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -90,4 +90,5 @@ Physical Unit Circle Download region Within expression + Stretchable Image \ No newline at end of file From 69b7b1077638cecdaa1f5085492d80e2c3c8d710 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 17 Apr 2020 18:00:39 +0300 Subject: [PATCH 122/185] Bump Mapbox GL Native mapbox-gl-native @ c4b061bd959a0efa5d0202d16d39e92e4f416abb --- MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp | 2 +- vendor/mapbox-gl-native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp index d1a2624f0..b8e07d0f9 100644 --- a/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp +++ b/MapboxGLAndroidSDK/src/cpp/android_renderer_frontend.cpp @@ -50,7 +50,7 @@ public: delegate.invoke(&RendererObserver::onDidFinishRenderingMap); } - void onStyleImageMissing(const std::string& id, StyleImageMissingCallback done) override { + void onStyleImageMissing(const std::string& id, const StyleImageMissingCallback& done) override { delegate.invoke(&RendererObserver::onStyleImageMissing, id, done); } diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 66ac55445..c4b061bd9 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 66ac55445998718b28a6fbd4a4094a10426627a9 +Subproject commit c4b061bd959a0efa5d0202d16d39e92e4f416abb From d7161fca1ffb2300d5b48a419dd680effa47c54f Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 20 Apr 2020 04:16:59 -0400 Subject: [PATCH 123/185] Add bindings for max overscale factor for parent tiles (#299) --- .../mapboxsdk/style/sources/Source.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index 70485a726..f19544922 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -92,6 +92,29 @@ public abstract class Source { nativeSetPrefetchZoomDelta(delta); } + /** + * When a set of tiles for a current zoom level is being rendered and some of the + * ideal tiles that cover the screen are not yet loaded, parent tile could be + * used instead. This might introduce unwanted rendering side-effects, especially + * for raster tiles that are overscaled multiple times. This method sets the maximum + * limit for how much a parent tile can be overscaled. + * + * @param maxOverscaleFactor maximum overscale factor + */ + public void setMaxOverscaleFactorForParentTiles(@Nullable Integer maxOverscaleFactor) { + nativeSetMaxOverscaleFactorForParentTiles(maxOverscaleFactor); + } + + /** + * Retrieve current maximum overscale factor for parent tiles. + * + * @return current maximum overscale factor or null if not set. + */ + @Nullable + public Integer getMaxOverscaleFactorForParentTiles() { + return nativeGetMaxOverscaleFactorForParentTiles(); + } + /** * Internal use * From 6bb456882a2287bf0dea7e55a4c65d6f40798a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 8 Apr 2020 15:07:47 +0200 Subject: [PATCH 124/185] expose LocationIndicatorLayer and an alternative rendering mode based on it --- MapboxGLAndroidSDK/src/cpp/CMakeLists.txt | 2 + .../src/cpp/conversion/constant.cpp | 14 + .../src/cpp/conversion/constant.hpp | 22 + .../src/cpp/style/layers/background_layer.cpp | 17 +- .../src/cpp/style/layers/circle_layer.cpp | 18 +- .../cpp/style/layers/fill_extrusion_layer.cpp | 23 +- .../src/cpp/style/layers/fill_layer.cpp | 18 +- .../src/cpp/style/layers/heatmap_layer.cpp | 18 +- .../src/cpp/style/layers/hillshade_layer.cpp | 17 +- .../src/cpp/style/layers/layer.cpp | 10 - .../src/cpp/style/layers/layer.cpp.ejs | 4 +- .../src/cpp/style/layers/layer.hpp.ejs | 2 +- .../src/cpp/style/layers/layer_manager.cpp | 4 + .../src/cpp/style/layers/line_layer.cpp | 18 +- .../style/layers/location_indicator_layer.cpp | 267 +++++++++ .../style/layers/location_indicator_layer.hpp | 86 +++ .../src/cpp/style/layers/raster_layer.cpp | 18 +- .../src/cpp/style/layers/symbol_layer.cpp | 18 +- .../IndicatorLocationLayerRenderer.java | 211 +++++++ .../location/LayerFeatureProvider.java | 4 +- .../location/LayerSourceProvider.java | 19 + .../mapboxsdk/location/LocationComponent.java | 42 +- .../LocationComponentActivationOptions.java | 72 ++- .../location/LocationComponentConstants.java | 1 + .../location/LocationLayerController.java | 322 +++------- .../location/LocationLayerRenderer.java | 47 ++ .../location/SymbolLocationLayerRenderer.java | 293 +++++++++ .../style/layers/LocationIndicatorLayer.java | 565 ++++++++++++++++++ .../style/layers/PropertyFactory.java | 280 +++++++++ .../mapboxsdk/style/layers/layer.java.ejs | 2 +- .../mapbox/mapboxsdk/utils/BitmapUtils.java | 15 +- .../location/LocationLayerControllerTest.java | 80 ++- .../style/LocationIndicatorLayerTest.java | 330 ++++++++++ .../mapboxsdk/testapp/style/layer.junit.ejs | 6 +- .../location/LocationModesActivity.java | 1 + core-files.json | 195 ------ filesource-files.json | 27 - scripts/generate-style-code.js | 24 +- vendor/mapbox-gl-native | 2 +- 39 files changed, 2479 insertions(+), 635 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp create mode 100644 MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java create mode 100644 MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java delete mode 100644 core-files.json delete mode 100644 filesource-files.json diff --git a/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt index f59a10e4d..2107533ea 100644 --- a/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt +++ b/MapboxGLAndroidSDK/src/cpp/CMakeLists.txt @@ -156,6 +156,8 @@ add_library( ${PROJECT_SOURCE_DIR}/style/layers/raster_layer.hpp ${PROJECT_SOURCE_DIR}/style/layers/symbol_layer.cpp ${PROJECT_SOURCE_DIR}/style/layers/symbol_layer.hpp + ${PROJECT_SOURCE_DIR}/style/layers/location_indicator_layer.cpp + ${PROJECT_SOURCE_DIR}/style/layers/location_indicator_layer.hpp ${PROJECT_SOURCE_DIR}/style/light.cpp ${PROJECT_SOURCE_DIR}/style/light.hpp ${PROJECT_SOURCE_DIR}/style/position.cpp diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp b/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp index 46a91026d..292e1a4ac 100644 --- a/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp +++ b/MapboxGLAndroidSDK/src/cpp/conversion/constant.cpp @@ -52,11 +52,25 @@ Result>> Converter>, std::vect return result; } +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + auto result = jni::Array::New(env, value.size()); + + for (std::size_t i = 0; i < value.size(); i++) { + result.Set(env, i, jni::Box(env, value.at(i))); + } + + return result; +} + Result>> Converter>, style::expression::Image>::operator()( jni::JNIEnv& env, const style::expression::Image& value) const { return jni::Make(env, value.id()); } +Result>> Converter>, mbgl::style::Rotation>::operator()(jni::JNIEnv& env, const mbgl::style::Rotation& value) const { + return jni::Box(env, value.getAngle()); +} + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp b/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp index a9239fe84..dc78d6f36 100644 --- a/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp +++ b/MapboxGLAndroidSDK/src/cpp/conversion/constant.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace mbgl { namespace android { @@ -72,6 +73,17 @@ struct Converter>, std::array> { } }; +template +struct Converter>, std::array> { + Result>> operator()(jni::JNIEnv& env, const std::array& value) const { + std::vector v; + for (const double& id : value) { + v.push_back(id); + } + return convert>, std::vector>(env, v); + } +}; + template <> struct Converter>, std::vector> { Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; @@ -82,6 +94,11 @@ struct Converter>, std::vector> { Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; }; +template <> +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; +}; + template struct Converter>, T, typename std::enable_if_t::value>> { Result>> operator()(jni::JNIEnv& env, const T& value) const { @@ -105,6 +122,11 @@ struct Converter>, style::expression::Image> { Result>> operator()(jni::JNIEnv& env, const style::expression::Image& value) const; }; +template <> +struct Converter>, mbgl::style::Rotation> { + Result>> operator()(jni::JNIEnv& env, const mbgl::style::Rotation& value) const; +}; + } // namespace conversion } // namespace android } // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp index 3eae30677..d0084dc2d 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp @@ -26,13 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - BackgroundLayer::BackgroundLayer(mbgl::style::BackgroundLayer& coreLayer) : Layer(coreLayer) {} + BackgroundLayer::BackgroundLayer(mbgl::style::BackgroundLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ BackgroundLayer::BackgroundLayer(std::unique_ptr coreLayer) - : Layer(std::move(coreLayer)) {} + : Layer(std::move(coreLayer)) { + } BackgroundLayer::~BackgroundLayer() = default; @@ -105,18 +108,14 @@ namespace android { } } // namespace - jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new BackgroundLayer(toBackgroundLayer(layer))); } - jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> BackgroundJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new BackgroundLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new BackgroundLayer(std::unique_ptr(static_cast(layer.release())))); } void BackgroundJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp index 2be603360..705bb9136 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - CircleLayer::CircleLayer(mbgl::style::CircleLayer& coreLayer) : Layer(coreLayer) {} + CircleLayer::CircleLayer(mbgl::style::CircleLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - CircleLayer::CircleLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + CircleLayer::CircleLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } CircleLayer::~CircleLayer() = default; @@ -214,18 +218,14 @@ namespace android { } } // namespace - jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new CircleLayer(toCircleLayer(layer))); } - jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> CircleJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new CircleLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new CircleLayer(std::unique_ptr(static_cast(layer.release())))); } void CircleJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp index 55c3d2028..9b7c66a0a 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp @@ -26,13 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - FillExtrusionLayer::FillExtrusionLayer(mbgl::style::FillExtrusionLayer& coreLayer) : Layer(coreLayer) {} + FillExtrusionLayer::FillExtrusionLayer(mbgl::style::FillExtrusionLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ FillExtrusionLayer::FillExtrusionLayer(std::unique_ptr coreLayer) - : Layer(std::move(coreLayer)) {} + : Layer(std::move(coreLayer)) { + } FillExtrusionLayer::~FillExtrusionLayer() = default; @@ -169,18 +172,14 @@ namespace android { } } // namespace - jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new FillExtrusionLayer(toFillExtrusionLayer(layer))); } - jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> FillExtrusionJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new FillExtrusionLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new FillExtrusionLayer(std::unique_ptr(static_cast(layer.release())))); } void FillExtrusionJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { @@ -203,10 +202,8 @@ namespace android { METHOD(&FillExtrusionLayer::getFillExtrusionColorTransition, "nativeGetFillExtrusionColorTransition"), METHOD(&FillExtrusionLayer::setFillExtrusionColorTransition, "nativeSetFillExtrusionColorTransition"), METHOD(&FillExtrusionLayer::getFillExtrusionColor, "nativeGetFillExtrusionColor"), - METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, - "nativeGetFillExtrusionTranslateTransition"), - METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, - "nativeSetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, "nativeGetFillExtrusionTranslateTransition"), + METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, "nativeSetFillExtrusionTranslateTransition"), METHOD(&FillExtrusionLayer::getFillExtrusionTranslate, "nativeGetFillExtrusionTranslate"), METHOD(&FillExtrusionLayer::getFillExtrusionTranslateAnchor, "nativeGetFillExtrusionTranslateAnchor"), METHOD(&FillExtrusionLayer::getFillExtrusionPatternTransition, "nativeGetFillExtrusionPatternTransition"), diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp index 6a646fdc7..ba6ed2179 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - FillLayer::FillLayer(mbgl::style::FillLayer& coreLayer) : Layer(coreLayer) {} + FillLayer::FillLayer(mbgl::style::FillLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - FillLayer::FillLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + FillLayer::FillLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } FillLayer::~FillLayer() = default; @@ -155,18 +159,14 @@ namespace android { } } // namespace - jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new FillLayer(toFillLayer(layer))); } - jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> FillJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new FillLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new FillLayer(std::unique_ptr(static_cast(layer.release())))); } void FillJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp index dad3d25e6..dfb8bbb4b 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - HeatmapLayer::HeatmapLayer(mbgl::style::HeatmapLayer& coreLayer) : Layer(coreLayer) {} + HeatmapLayer::HeatmapLayer(mbgl::style::HeatmapLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - HeatmapLayer::HeatmapLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + HeatmapLayer::HeatmapLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } HeatmapLayer::~HeatmapLayer() = default; @@ -118,18 +122,14 @@ namespace android { } } // namespace - jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new HeatmapLayer(toHeatmapLayer(layer))); } - jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> HeatmapJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new HeatmapLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new HeatmapLayer(std::unique_ptr(static_cast(layer.release())))); } void HeatmapJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp index 1f5fe1912..3c72b503b 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp @@ -26,13 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - HillshadeLayer::HillshadeLayer(mbgl::style::HillshadeLayer& coreLayer) : Layer(coreLayer) {} + HillshadeLayer::HillshadeLayer(mbgl::style::HillshadeLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ HillshadeLayer::HillshadeLayer(std::unique_ptr coreLayer) - : Layer(std::move(coreLayer)) {} + : Layer(std::move(coreLayer)) { + } HillshadeLayer::~HillshadeLayer() = default; @@ -133,18 +136,14 @@ namespace android { } } // namespace - jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new HillshadeLayer(toHillshadeLayer(layer))); } - jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> HillshadeJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new HillshadeLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new HillshadeLayer(std::unique_ptr(static_cast(layer.release())))); } void HillshadeJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp index bc87a9d9b..47984e140 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp @@ -5,16 +5,6 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include // Java -> C++ conversion diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs index 5d241e9a3..79df91791 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs @@ -20,7 +20,7 @@ namespace android { return static_castLayer&>(layer); } -<% if (type === 'background') { -%> +<% if (type === 'background' || type === 'location-indicator') { -%> /** * Creates an owning peer object (for layers not attached to the map) from the JVM side */ @@ -121,7 +121,7 @@ namespace android { env, javaClass, "nativePtr", -<% if (type === 'background') { -%> +<% if (type === 'background' || type === 'location-indicator') { -%> jni::MakePeer<<%- camelize(type) %>Layer, jni::String&>, <% } else { -%> jni::MakePeer<<%- camelize(type) %>Layer, jni::String&, jni::String&>, diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs index eb8db0620..05fe925c8 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs @@ -20,7 +20,7 @@ public: using SuperTag = Layer; static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; }; -<% if (type === 'background') { -%> +<% if (type === 'background' || type === 'location-indicator') { -%> <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&); <% } else { -%> <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&, jni::String&); diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp index 2d4172a23..1e72b1516 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer_manager.cpp @@ -17,6 +17,7 @@ #include "raster_layer.hpp" #include "symbol_layer.hpp" #include "fill_extrusion_layer.hpp" +#include "location_indicator_layer.hpp" namespace mbgl { @@ -73,6 +74,9 @@ LayerManagerAndroid::LayerManagerAndroid() { #elif !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) addLayerType(std::make_unique()); #endif +#if !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) + addLayerType(std::make_unique()); +#endif } LayerManagerAndroid::~LayerManagerAndroid() = default; diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp index 89c6cb532..bf3a403b6 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - LineLayer::LineLayer(mbgl::style::LineLayer& coreLayer) : Layer(coreLayer) {} + LineLayer::LineLayer(mbgl::style::LineLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - LineLayer::LineLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + LineLayer::LineLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } LineLayer::~LineLayer() = default; @@ -247,18 +251,14 @@ namespace android { } } // namespace - jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new LineLayer(toLineLayer(layer))); } - jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> LineJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new LineLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new LineLayer(std::unique_ptr(static_cast(layer.release())))); } void LineJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp new file mode 100644 index 000000000..7b2f36b4f --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp @@ -0,0 +1,267 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "location_indicator_layer.hpp" + +#include + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +#include + +namespace mbgl { +namespace android { + + inline mbgl::style::LocationIndicatorLayer& toLocationIndicatorLayer(mbgl::style::Layer& layer) { + return static_cast(layer); + } + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + LocationIndicatorLayer::LocationIndicatorLayer(jni::JNIEnv& env, jni::String& layerId) + : Layer(std::make_unique(jni::Make(env, layerId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + LocationIndicatorLayer::LocationIndicatorLayer(mbgl::style::LocationIndicatorLayer& coreLayer) + : Layer(coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + LocationIndicatorLayer::LocationIndicatorLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } + + LocationIndicatorLayer::~LocationIndicatorLayer() = default; + + // Property getters + + jni::Local> LocationIndicatorLayer::getTopImage(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getTopImage())); + } + + jni::Local> LocationIndicatorLayer::getBearingImage(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getBearingImage())); + } + + jni::Local> LocationIndicatorLayer::getShadowImage(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getShadowImage())); + } + + jni::Local> LocationIndicatorLayer::getPerspectiveCompensation(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getPerspectiveCompensation())); + } + + jni::Local> LocationIndicatorLayer::getImageTiltDisplacement(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getImageTiltDisplacement())); + } + + jni::Local> LocationIndicatorLayer::getBearing(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getBearing())); + } + + jni::Local> LocationIndicatorLayer::getLocation(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getLocation())); + } + + jni::Local> LocationIndicatorLayer::getLocationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getLocationTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setLocationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setLocationTransition(options); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getAccuracyRadius())); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getAccuracyRadiusTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setAccuracyRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setAccuracyRadiusTransition(options); + } + + jni::Local> LocationIndicatorLayer::getTopImageSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getTopImageSize())); + } + + jni::Local> LocationIndicatorLayer::getTopImageSizeTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getTopImageSizeTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setTopImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setTopImageSizeTransition(options); + } + + jni::Local> LocationIndicatorLayer::getBearingImageSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getBearingImageSize())); + } + + jni::Local> LocationIndicatorLayer::getBearingImageSizeTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getBearingImageSizeTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setBearingImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setBearingImageSizeTransition(options); + } + + jni::Local> LocationIndicatorLayer::getShadowImageSize(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getShadowImageSize())); + } + + jni::Local> LocationIndicatorLayer::getShadowImageSizeTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getShadowImageSizeTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setShadowImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setShadowImageSizeTransition(options); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadiusColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getAccuracyRadiusColor())); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadiusColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getAccuracyRadiusColorTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setAccuracyRadiusColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setAccuracyRadiusColorTransition(options); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadiusBorderColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert>>(env, toLocationIndicatorLayer(layer).getAccuracyRadiusBorderColor())); + } + + jni::Local> LocationIndicatorLayer::getAccuracyRadiusBorderColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = toLocationIndicatorLayer(layer).getAccuracyRadiusBorderColorTransition(); + return std::move(*convert>>(env, options)); + } + + void LocationIndicatorLayer::setAccuracyRadiusBorderColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + toLocationIndicatorLayer(layer).setAccuracyRadiusBorderColorTransition(options); + } + + + // LocationIndicatorJavaLayerPeerFactory + + LocationIndicatorJavaLayerPeerFactory::~LocationIndicatorJavaLayerPeerFactory() = default; + + namespace { + jni::Local> createJavaPeer(jni::JNIEnv& env, Layer* layer) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, reinterpret_cast(layer)); + } + } // namespace + + jni::Local> LocationIndicatorJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { + assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new LocationIndicatorLayer(toLocationIndicatorLayer(layer))); + } + + jni::Local> LocationIndicatorJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { + assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); + return createJavaPeer(env, new LocationIndicatorLayer(std::unique_ptr(static_cast(layer.release())))); + } + + void LocationIndicatorJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { + // Lookup the class + static auto& javaClass = jni::Class::Singleton(env); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&LocationIndicatorLayer::getTopImage, "nativeGetTopImage"), + METHOD(&LocationIndicatorLayer::getBearingImage, "nativeGetBearingImage"), + METHOD(&LocationIndicatorLayer::getShadowImage, "nativeGetShadowImage"), + METHOD(&LocationIndicatorLayer::getPerspectiveCompensation, "nativeGetPerspectiveCompensation"), + METHOD(&LocationIndicatorLayer::getImageTiltDisplacement, "nativeGetImageTiltDisplacement"), + METHOD(&LocationIndicatorLayer::getBearing, "nativeGetBearing"), + METHOD(&LocationIndicatorLayer::getLocationTransition, "nativeGetLocationTransition"), + METHOD(&LocationIndicatorLayer::setLocationTransition, "nativeSetLocationTransition"), + METHOD(&LocationIndicatorLayer::getLocation, "nativeGetLocation"), + METHOD(&LocationIndicatorLayer::getAccuracyRadiusTransition, "nativeGetAccuracyRadiusTransition"), + METHOD(&LocationIndicatorLayer::setAccuracyRadiusTransition, "nativeSetAccuracyRadiusTransition"), + METHOD(&LocationIndicatorLayer::getAccuracyRadius, "nativeGetAccuracyRadius"), + METHOD(&LocationIndicatorLayer::getTopImageSizeTransition, "nativeGetTopImageSizeTransition"), + METHOD(&LocationIndicatorLayer::setTopImageSizeTransition, "nativeSetTopImageSizeTransition"), + METHOD(&LocationIndicatorLayer::getTopImageSize, "nativeGetTopImageSize"), + METHOD(&LocationIndicatorLayer::getBearingImageSizeTransition, "nativeGetBearingImageSizeTransition"), + METHOD(&LocationIndicatorLayer::setBearingImageSizeTransition, "nativeSetBearingImageSizeTransition"), + METHOD(&LocationIndicatorLayer::getBearingImageSize, "nativeGetBearingImageSize"), + METHOD(&LocationIndicatorLayer::getShadowImageSizeTransition, "nativeGetShadowImageSizeTransition"), + METHOD(&LocationIndicatorLayer::setShadowImageSizeTransition, "nativeSetShadowImageSizeTransition"), + METHOD(&LocationIndicatorLayer::getShadowImageSize, "nativeGetShadowImageSize"), + METHOD(&LocationIndicatorLayer::getAccuracyRadiusColorTransition, "nativeGetAccuracyRadiusColorTransition"), + METHOD(&LocationIndicatorLayer::setAccuracyRadiusColorTransition, "nativeSetAccuracyRadiusColorTransition"), + METHOD(&LocationIndicatorLayer::getAccuracyRadiusColor, "nativeGetAccuracyRadiusColor"), + METHOD(&LocationIndicatorLayer::getAccuracyRadiusBorderColorTransition, "nativeGetAccuracyRadiusBorderColorTransition"), + METHOD(&LocationIndicatorLayer::setAccuracyRadiusBorderColorTransition, "nativeSetAccuracyRadiusBorderColorTransition"), + METHOD(&LocationIndicatorLayer::getAccuracyRadiusBorderColor, "nativeGetAccuracyRadiusBorderColor")); + } + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp new file mode 100644 index 000000000..6b7621efd --- /dev/null +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp @@ -0,0 +1,86 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include +#include +#include + +namespace mbgl { +namespace android { + +class LocationIndicatorLayer : public Layer { +public: + using SuperTag = Layer; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer"; }; + + LocationIndicatorLayer(jni::JNIEnv&, jni::String&); + + LocationIndicatorLayer(mbgl::style::LocationIndicatorLayer&); + + LocationIndicatorLayer(std::unique_ptr); + + ~LocationIndicatorLayer(); + + // Properties + + jni::Local> getTopImage(jni::JNIEnv&); + + jni::Local> getBearingImage(jni::JNIEnv&); + + jni::Local> getShadowImage(jni::JNIEnv&); + + jni::Local> getPerspectiveCompensation(jni::JNIEnv&); + + jni::Local> getImageTiltDisplacement(jni::JNIEnv&); + + jni::Local> getBearing(jni::JNIEnv&); + + jni::Local> getLocation(jni::JNIEnv&); + void setLocationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getLocationTransition(jni::JNIEnv&); + + jni::Local> getAccuracyRadius(jni::JNIEnv&); + void setAccuracyRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getAccuracyRadiusTransition(jni::JNIEnv&); + + jni::Local> getTopImageSize(jni::JNIEnv&); + void setTopImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getTopImageSizeTransition(jni::JNIEnv&); + + jni::Local> getBearingImageSize(jni::JNIEnv&); + void setBearingImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getBearingImageSizeTransition(jni::JNIEnv&); + + jni::Local> getShadowImageSize(jni::JNIEnv&); + void setShadowImageSizeTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getShadowImageSizeTransition(jni::JNIEnv&); + + jni::Local> getAccuracyRadiusColor(jni::JNIEnv&); + void setAccuracyRadiusColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getAccuracyRadiusColorTransition(jni::JNIEnv&); + + jni::Local> getAccuracyRadiusBorderColor(jni::JNIEnv&); + void setAccuracyRadiusBorderColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Local> getAccuracyRadiusBorderColorTransition(jni::JNIEnv&); + +}; // class LocationIndicatorLayer + +class LocationIndicatorJavaLayerPeerFactory final : public JavaLayerPeerFactory, public mbgl::LocationIndicatorLayerFactory { +public: + ~LocationIndicatorJavaLayerPeerFactory() override; + + // JavaLayerPeerFactory overrides. + jni::Local> createJavaLayerPeer(jni::JNIEnv&, mbgl::style::Layer&) final; + jni::Local> createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr) final; + + void registerNative(jni::JNIEnv&) final; + + LayerFactory* getLayerFactory() final { return this; } + +}; // class LocationIndicatorJavaLayerPeerFactory + +} // namespace android +} // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp index d9cce949c..53442c0a9 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - RasterLayer::RasterLayer(mbgl::style::RasterLayer& coreLayer) : Layer(coreLayer) {} + RasterLayer::RasterLayer(mbgl::style::RasterLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - RasterLayer::RasterLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + RasterLayer::RasterLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } RasterLayer::~RasterLayer() = default; @@ -168,18 +172,14 @@ namespace android { } } // namespace - jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new RasterLayer(toRasterLayer(layer))); } - jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> RasterJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new RasterLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new RasterLayer(std::unique_ptr(static_cast(layer.release())))); } void RasterJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp index f24fb3542..198dbe635 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp @@ -26,12 +26,16 @@ namespace android { /** * Creates a non-owning peer object (for layers currently attached to the map) */ - SymbolLayer::SymbolLayer(mbgl::style::SymbolLayer& coreLayer) : Layer(coreLayer) {} + SymbolLayer::SymbolLayer(mbgl::style::SymbolLayer& coreLayer) + : Layer(coreLayer) { + } /** * Creates an owning peer object (for layers not attached to the map) */ - SymbolLayer::SymbolLayer(std::unique_ptr coreLayer) : Layer(std::move(coreLayer)) {} + SymbolLayer::SymbolLayer(std::unique_ptr coreLayer) + : Layer(std::move(coreLayer)) { + } SymbolLayer::~SymbolLayer() = default; @@ -481,18 +485,14 @@ namespace android { } } // namespace - jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, - mbgl::style::Layer& layer) { + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, mbgl::style::Layer& layer) { assert(layer.baseImpl->getTypeInfo() == getTypeInfo()); return createJavaPeer(env, new SymbolLayer(toSymbolLayer(layer))); } - jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer( - jni::JNIEnv& env, std::unique_ptr layer) { + jni::Local> SymbolJavaLayerPeerFactory::createJavaLayerPeer(jni::JNIEnv& env, std::unique_ptr layer) { assert(layer->baseImpl->getTypeInfo() == getTypeInfo()); - return createJavaPeer(env, - new SymbolLayer(std::unique_ptr( - static_cast(layer.release())))); + return createJavaPeer(env, new SymbolLayer(std::unique_ptr(static_cast(layer.release())))); } void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java new file mode 100644 index 000000000..6f4f0080d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java @@ -0,0 +1,211 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; + +import androidx.annotation.Nullable; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; +import com.mapbox.mapboxsdk.style.layers.PropertyFactory; +import com.mapbox.mapboxsdk.utils.BitmapUtils; +import com.mapbox.mapboxsdk.utils.ColorUtils; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; +import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba; +import static com.mapbox.mapboxsdk.style.layers.Property.NONE; +import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; + +class IndicatorLocationLayerRenderer implements LocationLayerRenderer { + + private Style style; + private final LayerSourceProvider layerSourceProvider; + private LocationIndicatorLayer layer; + + @Nullable + private LatLng latLng; + + IndicatorLocationLayerRenderer(Style style, + LayerSourceProvider layerSourceProvider) { + this.style = style; + this.layerSourceProvider = layerSourceProvider; + } + + @Override + public void initializeComponents(Style style) { + this.style = style; + } + + @Override + public void addLayers(LocationComponentPositionManager positionManager) { + layer = layerSourceProvider.generateLocationComponentLayer(); + setLayerLocation(latLng); + positionManager.addLayerToMap(layer); + } + + @Override + public void removeLayers() { + style.removeLayer(layer); + } + + @Override + public void hide() { + setLayerVisibility(false); + } + + @Override + public void cameraTiltUpdated(double tilt) { + // ignored + } + + @Override + public void cameraBearingUpdated(double bearing) { + // ignored + } + + @Override + public void show(@RenderMode.Mode int renderMode, boolean isStale) { + setImages(renderMode, isStale); + setLayerVisibility(true); + } + + @Override + public void styleAccuracy(float accuracyAlpha, int accuracyColor) { + float[] colorArray = ColorUtils.colorToRgbaArray(accuracyColor); + colorArray[3] = accuracyAlpha; + Expression rgbaExpression = rgba(colorArray[0], colorArray[1], colorArray[2], colorArray[3]); + layer.setProperties( + PropertyFactory.accuracyRadiusColor(rgbaExpression), + PropertyFactory.accuracyRadiusBorderColor(rgbaExpression) + ); + } + + @Override + public void setLatLng(LatLng latLng) { + setLayerLocation(latLng); + } + + @Override + public void setGpsBearing(Float gpsBearing) { + setLayerBearing(gpsBearing); + } + + @Override + public void setCompassBearing(Float compassBearing) { + setLayerBearing(compassBearing); + } + + @Override + public void setAccuracyRadius(Float accuracy) { + layer.setProperties( + PropertyFactory.accuracyRadius(accuracy) + ); + } + + @Override + public void styleScaling(Expression scaleExpression) { + layer.setProperties( + PropertyFactory.shadowImageSize(scaleExpression), + PropertyFactory.bearingImageSize(scaleExpression), + PropertyFactory.topImageSize(scaleExpression) + ); + } + + @Override + public void setLocationStale(boolean isStale, int renderMode) { + setImages(renderMode, isStale); + } + + @Override + public void updateIconIds(String foregroundIconString, String foregroundStaleIconString, String backgroundIconString, + String backgroundStaleIconString, String bearingIconString) { + // not supported + } + + @Override + public void addBitmaps(@RenderMode.Mode int renderMode, @Nullable Bitmap shadowBitmap, Bitmap backgroundBitmap, + Bitmap backgroundStaleBitmap, Bitmap bearingBitmap, + Bitmap foregroundBitmap, Bitmap foregroundStaleBitmap) { + if (shadowBitmap != null) { + style.addImage(SHADOW_ICON, shadowBitmap); + } else { + style.removeImage(SHADOW_ICON); + } + style.addImage(FOREGROUND_ICON, foregroundBitmap); + style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap); + + if (renderMode == RenderMode.COMPASS) { + float leftOffset = (bearingBitmap.getWidth() - backgroundBitmap.getWidth()) / 2f; + float topOffset = (bearingBitmap.getHeight() - backgroundBitmap.getHeight()) / 2f; + style.addImage(BEARING_ICON, BitmapUtils.mergeBitmap(bearingBitmap, backgroundBitmap, leftOffset, topOffset)); + + float staleLeftOffset = (bearingBitmap.getWidth() - backgroundStaleBitmap.getWidth()) / 2f; + float staleTopOffset = (bearingBitmap.getHeight() - backgroundStaleBitmap.getHeight()) / 2f; + style.addImage(BEARING_STALE_ICON, + BitmapUtils.mergeBitmap(bearingBitmap, backgroundStaleBitmap, staleLeftOffset, staleTopOffset)); + } else { + style.addImage(BACKGROUND_ICON, backgroundBitmap); + style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap); + style.addImage(BEARING_ICON, bearingBitmap); + } + } + + private void setLayerVisibility(boolean visible) { + layer.setProperties(visibility(visible ? VISIBLE : NONE)); + } + + private void setLayerLocation(@Nullable LatLng latLng) { + this.latLng = latLng; + if (latLng != null) { + Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; + layer.setProperties( + PropertyFactory.location(values) + ); + } + } + + private void setLayerBearing(double bearing) { + layer.setProperties( + PropertyFactory.bearing(bearing) + ); + } + + private void setImages(@RenderMode.Mode int renderMode, boolean isStale) { + String topImage = ""; + String bearingImage = ""; + String shadowImage = ""; + + switch (renderMode) { + case RenderMode.COMPASS: + topImage = isStale ? FOREGROUND_STALE_ICON : FOREGROUND_ICON; + bearingImage = isStale ? BEARING_STALE_ICON : BEARING_ICON; + shadowImage = SHADOW_ICON; + break; + case RenderMode.GPS: + topImage = ""; + bearingImage = isStale ? FOREGROUND_STALE_ICON : FOREGROUND_ICON; + shadowImage = ""; + setAccuracyRadius(0f); + break; + case RenderMode.NORMAL: + topImage = isStale ? FOREGROUND_STALE_ICON : FOREGROUND_ICON; + bearingImage = isStale ? BACKGROUND_STALE_ICON : BACKGROUND_ICON; + shadowImage = SHADOW_ICON; + break; + } + layer.setProperties( + PropertyFactory.topImage(topImage), + PropertyFactory.bearingImage(bearingImage), + PropertyFactory.shadowImage(shadowImage) + ); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java index 69e08caed..1ad948908 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerFeatureProvider.java @@ -13,14 +13,14 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ class LayerFeatureProvider { @NonNull - Feature generateLocationFeature(@Nullable Feature locationFeature, @NonNull LocationComponentOptions options) { + Feature generateLocationFeature(@Nullable Feature locationFeature, boolean isStale) { if (locationFeature != null) { return locationFeature; } locationFeature = Feature.fromGeometry(Point.fromLngLat(0.0, 0.0)); locationFeature.addNumberProperty(PROPERTY_GPS_BEARING, 0f); locationFeature.addNumberProperty(PROPERTY_COMPASS_BEARING, 0f); - locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, options.enableStaleState()); + locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, isStale); return locationFeature; } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index e3c6ebd91..2d3e969ec 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -1,14 +1,20 @@ package com.mapbox.mapboxsdk.location; import androidx.annotation.NonNull; + import com.mapbox.geojson.Feature; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; import com.mapbox.mapboxsdk.style.layers.Property; +import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; +import java.util.HashSet; +import java.util.Set; + import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER; @@ -108,4 +114,17 @@ class LayerSourceProvider { circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) ); } + + Set getEmptyLayerSet() { + return new HashSet<>(); + } + + LocationIndicatorLayer generateLocationComponentLayer() { + LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); + layer.setProperties( + PropertyFactory.perspectiveCompensation(0.9f), + PropertyFactory.imageTiltDisplacement(4f) + ); + return layer; + } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 0f7dfded0..733dbb259 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -140,6 +140,12 @@ public final class LocationComponent { */ private boolean isComponentInitialized; + /** + * Indicates whether we're using the {@link com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer} + * or the stack of {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer}s. + */ + private boolean useSpecializedLocationLayer; + /** * Indicates that the component is enabled and should be displaying location if Mapbox components are available and * the lifecycle is in a started state. @@ -341,7 +347,7 @@ public final class LocationComponent { @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @NonNull LocationComponentOptions options) { - initialize(context, style, options); + initialize(context, style, false, options); initializeLocationEngine(context); applyStyle(options); } @@ -425,7 +431,7 @@ public final class LocationComponent { public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @NonNull LocationComponentOptions options) { - initialize(context, style, options); + initialize(context, style, false, options); setLocationEngine(locationEngine); applyStyle(options); } @@ -446,7 +452,7 @@ public final class LocationComponent { @Nullable LocationEngine locationEngine, @NonNull LocationEngineRequest locationEngineRequest, @NonNull LocationComponentOptions options) { - initialize(context, style, options); + initialize(context, style, false, options); setLocationEngineRequest(locationEngineRequest); setLocationEngine(locationEngine); applyStyle(options); @@ -470,7 +476,8 @@ public final class LocationComponent { // Initialize the LocationComponent with Context, the map's `Style`, and either custom LocationComponentOptions // or backup options created from default/custom attributes - initialize(activationOptions.context(), activationOptions.style(), options); + initialize(activationOptions.context(), activationOptions.style(), + activationOptions.useSpecializedLocationLayer(), options); // Apply the LocationComponent styling // TODO avoid doubling style initialization @@ -1255,7 +1262,7 @@ public final class LocationComponent { mapboxMap.removeOnCameraIdleListener(onCameraIdleListener); } - private void initialize(@NonNull final Context context, @NonNull Style style, + private void initialize(@NonNull final Context context, @NonNull Style style, boolean useSpecializedLocationLayer, @NonNull final LocationComponentOptions options) { if (isComponentInitialized) { return; @@ -1268,6 +1275,7 @@ public final class LocationComponent { this.style = style; this.options = options; + this.useSpecializedLocationLayer = useSpecializedLocationLayer; mapboxMap.addOnMapClickListener(onMapClickListener); mapboxMap.addOnMapLongClickListener(onMapLongClickListener); @@ -1276,7 +1284,7 @@ public final class LocationComponent { LayerFeatureProvider featureProvider = new LayerFeatureProvider(); LayerBitmapProvider bitmapProvider = new LayerBitmapProvider(context); locationLayerController = new LocationLayerController(mapboxMap, style, sourceProvider, featureProvider, - bitmapProvider, options, renderModeChangedListener); + bitmapProvider, options, renderModeChangedListener, useSpecializedLocationLayer); locationCameraController = new LocationCameraController( context, mapboxMap, transform, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener); @@ -1446,20 +1454,24 @@ public final class LocationComponent { @SuppressLint("MissingPermission") private void updateLayerOffsets(boolean forceUpdate) { + if (useSpecializedLocationLayer) { + return; + } + CameraPosition position = mapboxMap.getCameraPosition(); if (lastCameraPosition == null || forceUpdate) { lastCameraPosition = position; - locationLayerController.updateForegroundBearing((float) position.bearing); - locationLayerController.updateForegroundOffset(position.tilt); + locationLayerController.cameraBearingUpdated(position.bearing); + locationLayerController.cameraTiltUpdated(position.tilt); updateAccuracyRadius(getLastKnownLocation(), true); return; } if (position.bearing != lastCameraPosition.bearing) { - locationLayerController.updateForegroundBearing((float) position.bearing); + locationLayerController.cameraBearingUpdated(position.bearing); } if (position.tilt != lastCameraPosition.tilt) { - locationLayerController.updateForegroundOffset(position.tilt); + locationLayerController.cameraTiltUpdated(position.tilt); } if (position.zoom != lastCameraPosition.zoom) { updateAccuracyRadius(getLastKnownLocation(), true); @@ -1468,7 +1480,15 @@ public final class LocationComponent { } private void updateAccuracyRadius(Location location, boolean noAnimation) { - locationAnimatorCoordinator.feedNewAccuracyRadius(Utils.calculateZoomLevelRadius(mapboxMap, location), noAnimation); + float radius; + if (location == null) { + radius = 0; + } else if (useSpecializedLocationLayer) { + radius = location.getAccuracy(); + } else { + radius = Utils.calculateZoomLevelRadius(mapboxMap, location); + } + locationAnimatorCoordinator.feedNewAccuracyRadius(radius, noAnimation); } private void updateAnimatorListenerHolders() { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java index 7a7b24149..91f6141dd 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.content.Context; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -21,13 +22,15 @@ public class LocationComponentActivationOptions { private final LocationComponentOptions locationComponentOptions; private final int styleRes; private final boolean useDefaultLocationEngine; + private final boolean useSpecializedLocationLayer; private LocationComponentActivationOptions(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @Nullable LocationEngineRequest locationEngineRequest, @Nullable LocationComponentOptions locationComponentOptions, int styleRes, - boolean useDefaultLocationEngine) { + boolean useDefaultLocationEngine, + boolean useSpecializedLocationLayer) { this.context = context; this.style = style; this.locationEngine = locationEngine; @@ -35,6 +38,7 @@ public class LocationComponentActivationOptions { this.locationComponentOptions = locationComponentOptions; this.styleRes = styleRes; this.useDefaultLocationEngine = useDefaultLocationEngine; + this.useSpecializedLocationLayer = useSpecializedLocationLayer; } /** @@ -116,6 +120,25 @@ public class LocationComponentActivationOptions { return useDefaultLocationEngine; } + /** + * True if you want to initialize and use the specialized location layer to render the location puck. + *

    + * The specialized layer comes with significant performance improvements, + * but since it's not based on the runtime styling, + * it's not fully compatible with the traditional implementation. The incompatibilities are: + *

      + *
    • Constants like {@link LocationComponentConstants#FOREGROUND_LAYER} + * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. + *
    • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. + * Use {@link LocationComponentOptions#foregroundDrawable()} instead. + *
    + * + * @return whether the default specialized location layer is used + */ + public boolean useSpecializedLocationLayer() { + return useSpecializedLocationLayer; + } + /** * Builder class for constructing a new instance of {@link LocationComponentActivationOptions}. */ @@ -136,6 +159,8 @@ public class LocationComponentActivationOptions { */ private boolean useDefaultLocationEngine = true; + private boolean useSpecializedLocationLayer = false; + /** * Constructor for the {@link LocationComponentActivationOptions} builder class. * While other activation options are optional, the activation process always requires @@ -208,6 +233,28 @@ public class LocationComponentActivationOptions { return this; } + /** + * True if you want to initialize and use the specialized location layer to render the location puck. + *

    + * The specialized layer comes with significant performance improvements, + * but since it's not based on the runtime styling, + * it's not fully compatible with the traditional implementation. The incompatibilities are: + *

      + *
    • Constants like {@link LocationComponentConstants#FOREGROUND_LAYER} + * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. + *
    • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. + * Use {@link LocationComponentOptions#foregroundDrawable()} instead. + *
    + * + * @param useSpecializedLocationLayer true if you want to initialize and use the + * specialized location layer. Defaults to false. + * @return the {@link Builder} object being constructed + */ + public Builder useSpecializedLocationLayer(boolean useSpecializedLocationLayer) { + this.useSpecializedLocationLayer = useSpecializedLocationLayer; + return this; + } + /** * Method which actually builds the {@link LocationComponentActivationOptions} object while * taking the various options into account. @@ -217,28 +264,29 @@ public class LocationComponentActivationOptions { public LocationComponentActivationOptions build() { if (styleRes != 0 && locationComponentOptions != null) { throw new IllegalArgumentException( - "You've provided both a style resource and a LocationComponentOptions object to the " - + "LocationComponentActivationOptions builder. You can't use both and " - + "you must choose one of the two to style the LocationComponent."); + "You've provided both a style resource and a LocationComponentOptions object to the " + + "LocationComponentActivationOptions builder. You can't use both and " + + "you must choose one of the two to style the LocationComponent."); } if (context == null) { throw new NullPointerException( - "Context in LocationComponentActivationOptions is null."); + "Context in LocationComponentActivationOptions is null."); } if (style == null) { throw new NullPointerException( - "Style in LocationComponentActivationOptions is null. Make sure the " - + "Style object isn't null. Wait for the map to fully load before passing " - + "the Style object to LocationComponentActivationOptions."); + "Style in LocationComponentActivationOptions is null. Make sure the " + + "Style object isn't null. Wait for the map to fully load before passing " + + "the Style object to LocationComponentActivationOptions."); } if (!style.isFullyLoaded()) { throw new IllegalArgumentException( - "Style in LocationComponentActivationOptions isn't fully loaded. Wait for the " - + "map to fully load before passing the Style object to " - + "LocationComponentActivationOptions."); + "Style in LocationComponentActivationOptions isn't fully loaded. Wait for the " + + "map to fully load before passing the Style object to " + + "LocationComponentActivationOptions."); } return new LocationComponentActivationOptions(context, style, locationEngine, - locationEngineRequest, locationComponentOptions, styleRes, useDefaultLocationEngine); + locationEngineRequest, locationComponentOptions, styleRes, useDefaultLocationEngine, + useSpecializedLocationLayer); } } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index f2158584c..a3b4804b7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -87,6 +87,7 @@ public final class LocationComponentConstants { static final String BACKGROUND_STALE_ICON = "mapbox-location-background-stale-icon"; static final String SHADOW_ICON = "mapbox-location-shadow-icon"; static final String BEARING_ICON = "mapbox-location-bearing-icon"; + static final String BEARING_STALE_ICON = "mapbox-location-bearing-stale-icon"; private LocationComponentConstants() { // Class should not be initialized diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index aeb011e81..556254297 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -2,28 +2,22 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; import android.graphics.PointF; -import androidx.annotation.ColorInt; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import com.mapbox.geojson.Feature; -import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.layers.SymbolLayer; -import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; +import com.mapbox.mapboxsdk.style.expressions.Expression; import java.util.HashSet; import java.util.List; import java.util.Set; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; @@ -32,71 +26,58 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_L import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_ALPHA; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_COLOR; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_STALE_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BEARING_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; -import static com.mapbox.mapboxsdk.style.layers.Property.NONE; -import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; -import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; final class LocationLayerController { + private static final String TAG = "Mbgl-LocationLayerController"; + @RenderMode.Mode private int renderMode; private final MapboxMap mapboxMap; private Style style; - private final LayerSourceProvider layerSourceProvider; private final LayerBitmapProvider bitmapProvider; private LocationComponentOptions options; private final OnRenderModeChangedListener internalRenderModeChangedListener; - - @VisibleForTesting - final Set layerSet = new HashSet<>(); - private Feature locationFeature; - private GeoJsonSource locationSource; + private final boolean useSpecializedLocationLayer; private boolean isHidden = true; + private boolean isStale; private LocationComponentPositionManager positionManager; - LocationLayerController(MapboxMap mapboxMap, Style style, LayerSourceProvider layerSourceProvider, - LayerFeatureProvider featureProvider, LayerBitmapProvider bitmapProvider, + private LocationLayerRenderer locationLayerRenderer; + + LocationLayerController(MapboxMap mapboxMap, Style style, + LayerSourceProvider layerSourceProvider, + LayerFeatureProvider featureProvider, + LayerBitmapProvider bitmapProvider, @NonNull LocationComponentOptions options, - @NonNull OnRenderModeChangedListener internalRenderModeChangedListener) { + @NonNull OnRenderModeChangedListener internalRenderModeChangedListener, + boolean useSpecializedLocationLayer) { this.mapboxMap = mapboxMap; this.style = style; - this.layerSourceProvider = layerSourceProvider; this.bitmapProvider = bitmapProvider; - this.locationFeature = featureProvider.generateLocationFeature(locationFeature, options); this.internalRenderModeChangedListener = internalRenderModeChangedListener; + this.useSpecializedLocationLayer = useSpecializedLocationLayer; + this.isStale = options.enableStaleState(); + if (useSpecializedLocationLayer) { + locationLayerRenderer = new IndicatorLocationLayerRenderer(style, layerSourceProvider); + } else { + locationLayerRenderer = new SymbolLocationLayerRenderer(style, layerSourceProvider, featureProvider, isStale); + } initializeComponents(style, options); } void initializeComponents(Style style, LocationComponentOptions options) { this.style = style; this.positionManager = new LocationComponentPositionManager(style, options.layerAbove(), options.layerBelow()); - addLocationSource(); - addLayers(); + locationLayerRenderer.initializeComponents(style); + locationLayerRenderer.addLayers(positionManager); applyStyle(options); if (isHidden) { @@ -108,24 +89,16 @@ final class LocationLayerController { void applyStyle(@NonNull LocationComponentOptions options) { if (positionManager.update(options.layerAbove(), options.layerBelow())) { - removeLayers(); - addLayers(); + locationLayerRenderer.removeLayers(); + locationLayerRenderer.addLayers(positionManager); if (isHidden) { hide(); } } this.options = options; - - float elevation = options.elevation(); - // Only add icon elevation if the values greater than 0. - if (elevation > 0) { - styleShadow(options); - } - styleForeground(options); - styleBackground(options); - styleBearing(options); - styleAccuracy(options.accuracyAlpha(), options.accuracyColor()); + styleBitmaps(options); + locationLayerRenderer.styleAccuracy(options.accuracyAlpha(), options.accuracyColor()); styleScaling(options); determineIconsSource(options); @@ -140,7 +113,7 @@ final class LocationLayerController { } this.renderMode = renderMode; - styleForeground(options); + styleBitmaps(options); determineIconsSource(options); if (!isHidden) { show(); @@ -158,59 +131,12 @@ final class LocationLayerController { void show() { isHidden = false; - boolean isStale = locationFeature.getBooleanProperty(PROPERTY_LOCATION_STALE); - switch (renderMode) { - case RenderMode.NORMAL: - setLayerVisibility(SHADOW_LAYER, true); - setLayerVisibility(FOREGROUND_LAYER, true); - setLayerVisibility(BACKGROUND_LAYER, true); - setLayerVisibility(ACCURACY_LAYER, !isStale); - setLayerVisibility(BEARING_LAYER, false); - break; - case RenderMode.COMPASS: - setLayerVisibility(SHADOW_LAYER, true); - setLayerVisibility(FOREGROUND_LAYER, true); - setLayerVisibility(BACKGROUND_LAYER, true); - setLayerVisibility(ACCURACY_LAYER, !isStale); - setLayerVisibility(BEARING_LAYER, true); - break; - case RenderMode.GPS: - setLayerVisibility(SHADOW_LAYER, false); - setLayerVisibility(FOREGROUND_LAYER, true); - setLayerVisibility(BACKGROUND_LAYER, true); - setLayerVisibility(ACCURACY_LAYER, false); - setLayerVisibility(BEARING_LAYER, false); - break; - default: - break; - } + locationLayerRenderer.show(renderMode, isStale); } void hide() { isHidden = true; - for (String layerId : layerSet) { - setLayerVisibility(layerId, false); - } - } - - void updateForegroundOffset(double tilt) { - JsonArray foregroundJsonArray = new JsonArray(); - foregroundJsonArray.add(0f); - foregroundJsonArray.add((float) (-0.05 * tilt)); - locationFeature.addProperty(PROPERTY_FOREGROUND_ICON_OFFSET, foregroundJsonArray); - - JsonArray backgroundJsonArray = new JsonArray(); - backgroundJsonArray.add(0f); - backgroundJsonArray.add((float) (0.05 * tilt)); - locationFeature.addProperty(PROPERTY_SHADOW_ICON_OFFSET, backgroundJsonArray); - - refreshSource(); - } - - void updateForegroundBearing(float bearing) { - if (renderMode != RenderMode.GPS) { - setBearingProperty(PROPERTY_GPS_BEARING, bearing); - } + locationLayerRenderer.hide(); } boolean isHidden() { @@ -221,148 +147,63 @@ final class LocationLayerController { return renderMode == RenderMode.COMPASS; } - private void setLayerVisibility(@NonNull String layerId, boolean visible) { - Layer layer = style.getLayer(layerId); - if (layer != null) { - String targetVisibility = visible ? VISIBLE : NONE; - if (!layer.getVisibility().value.equals(targetVisibility)) { - layer.setProperties(visibility(visible ? VISIBLE : NONE)); - } - } - } - - private void addLayers() { - // positions the top-most reference layer - Layer layer = layerSourceProvider.generateLayer(BEARING_LAYER); - positionManager.addLayerToMap(layer); - layerSet.add(layer.getId()); - - // adds remaining layers while keeping the order - addSymbolLayer(FOREGROUND_LAYER, BEARING_LAYER); - addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); - addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); - addAccuracyLayer(); - } - - private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) { - Layer layer = layerSourceProvider.generateLayer(layerId); - addLayerToMap(layer, beforeLayerId); - } - - private void addAccuracyLayer() { - Layer accuracyLayer = layerSourceProvider.generateAccuracyLayer(); - addLayerToMap(accuracyLayer, BACKGROUND_LAYER); - } - - private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { - style.addLayerBelow(layer, idBelowLayer); - layerSet.add(layer.getId()); - } - - private void removeLayers() { - for (String layerId : layerSet) { - style.removeLayer(layerId); - } - layerSet.clear(); - } - - private void setBearingProperty(@NonNull String propertyId, float bearing) { - locationFeature.addNumberProperty(propertyId, bearing); - refreshSource(); - } - - private void updateAccuracyRadius(float accuracy) { - locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracy); - refreshSource(); - } - - // - // Source actions - // - - private void addLocationSource() { - locationSource = layerSourceProvider.generateSource(locationFeature); - style.addSource(locationSource); - } - - private void refreshSource() { - GeoJsonSource source = style.getSourceAs(LOCATION_SOURCE); - if (source != null) { - locationSource.setGeoJson(locationFeature); - } - } - - private void setLocationPoint(Point locationPoint) { - JsonObject properties = locationFeature.properties(); - if (properties != null) { - locationFeature = Feature.fromGeometry(locationPoint, properties); - refreshSource(); - } - } - // // Styling // - private void styleBackground(LocationComponentOptions options) { + private void styleBitmaps(LocationComponentOptions options) { + // shadow + Bitmap shadowBitmap = null; + if (options.elevation() > 0) { + // Only add icon elevation if the values greater than 0. + shadowBitmap = bitmapProvider.generateShadowBitmap(options); + } + + // background Bitmap backgroundBitmap = bitmapProvider.generateBitmap( options.backgroundDrawable(), options.backgroundTintColor() ); Bitmap backgroundStaleBitmap = bitmapProvider.generateBitmap( options.backgroundDrawableStale(), options.backgroundStaleTintColor() ); - style.addImage(BACKGROUND_ICON, backgroundBitmap); - style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap); - } - private void styleShadow(@NonNull LocationComponentOptions options) { - style.addImage(SHADOW_ICON, bitmapProvider.generateShadowBitmap(options)); - } - - private void styleBearing(LocationComponentOptions options) { + // compass bearing Bitmap bearingBitmap = bitmapProvider.generateBitmap(options.bearingDrawable(), options.bearingTintColor()); - style.addImage(BEARING_ICON, bearingBitmap); - } - private void styleAccuracy(float accuracyAlpha, @ColorInt int accuracyColor) { - locationFeature.addNumberProperty(PROPERTY_ACCURACY_ALPHA, accuracyAlpha); - locationFeature.addStringProperty(PROPERTY_ACCURACY_COLOR, colorToRgbaString(accuracyColor)); - refreshSource(); - } - - private void styleForeground(LocationComponentOptions options) { + // foreground Bitmap foregroundBitmap = bitmapProvider.generateBitmap( options.foregroundDrawable(), options.foregroundTintColor() ); - Bitmap foregroundBitmapStale = bitmapProvider.generateBitmap( + Bitmap foregroundStaleBitmap = bitmapProvider.generateBitmap( options.foregroundDrawableStale(), options.foregroundStaleTintColor() ); if (renderMode == RenderMode.GPS) { foregroundBitmap = bitmapProvider.generateBitmap( options.gpsDrawable(), options.foregroundTintColor() ); - foregroundBitmapStale = bitmapProvider.generateBitmap( + foregroundStaleBitmap = bitmapProvider.generateBitmap( options.gpsDrawable(), options.foregroundStaleTintColor() ); } - style.addImage(FOREGROUND_ICON, foregroundBitmap); - style.addImage(FOREGROUND_STALE_ICON, foregroundBitmapStale); + + locationLayerRenderer.addBitmaps( + renderMode, + shadowBitmap, + backgroundBitmap, + backgroundStaleBitmap, + bearingBitmap, + foregroundBitmap, + foregroundStaleBitmap + ); } private void styleScaling(@NonNull LocationComponentOptions options) { - for (String layerId : layerSet) { - Layer layer = style.getLayer(layerId); - if (layer instanceof SymbolLayer) { - layer.setProperties( - iconSize( - interpolate(linear(), zoom(), - stop(mapboxMap.getMinZoomLevel(), options.minZoomIconScale()), - stop(mapboxMap.getMaxZoomLevel(), options.maxZoomIconScale()) - ) - ) - ); - } - } + Expression scaleExpression = interpolate(linear(), zoom(), + stop(mapboxMap.getMinZoomLevel(), options.minZoomIconScale()), + stop(mapboxMap.getMaxZoomLevel(), options.maxZoomIconScale()) + ); + + locationLayerRenderer.styleScaling(scaleExpression); } private void determineIconsSource(LocationComponentOptions options) { @@ -373,28 +214,30 @@ final class LocationLayerController { String backgroundStaleIconString = buildIconString(options.backgroundStaleName(), BACKGROUND_STALE_ICON); String bearingIconString = buildIconString(options.bearingName(), BEARING_ICON); - locationFeature.addStringProperty(PROPERTY_FOREGROUND_ICON, foregroundIconString); - locationFeature.addStringProperty(PROPERTY_BACKGROUND_ICON, backgroundIconString); - locationFeature.addStringProperty(PROPERTY_FOREGROUND_STALE_ICON, foregroundStaleIconString); - locationFeature.addStringProperty(PROPERTY_BACKGROUND_STALE_ICON, backgroundStaleIconString); - locationFeature.addStringProperty(PROPERTY_BEARING_ICON, bearingIconString); - refreshSource(); + locationLayerRenderer.updateIconIds( + foregroundIconString, + foregroundStaleIconString, + backgroundIconString, + backgroundStaleIconString, + bearingIconString + ); } @NonNull private String buildIconString(@Nullable String bitmapName, @NonNull String drawableName) { if (bitmapName != null) { + if (useSpecializedLocationLayer) { + Logger.e(TAG, bitmapName + " replacement ID provided for an unsupported specialized location layer"); + return drawableName; + } return bitmapName; } return drawableName; } void setLocationsStale(boolean isStale) { - locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, isStale); - refreshSource(); - if (renderMode != RenderMode.GPS) { - setLayerVisibility(ACCURACY_LAYER, !isStale); - } + this.isStale = isStale; + locationLayerRenderer.setLocationStale(isStale, renderMode); } // @@ -415,8 +258,7 @@ final class LocationLayerController { new MapboxAnimator.AnimationsValueChangeListener() { @Override public void onNewAnimationValue(LatLng value) { - Point point = Point.fromLngLat(value.getLongitude(), value.getLatitude()); - setLocationPoint(point); + locationLayerRenderer.setLatLng(value); } }; @@ -424,7 +266,7 @@ final class LocationLayerController { new MapboxAnimator.AnimationsValueChangeListener() { @Override public void onNewAnimationValue(Float value) { - setBearingProperty(PROPERTY_GPS_BEARING, value); + locationLayerRenderer.setGpsBearing(value); } }; @@ -432,7 +274,7 @@ final class LocationLayerController { new MapboxAnimator.AnimationsValueChangeListener() { @Override public void onNewAnimationValue(Float value) { - setBearingProperty(PROPERTY_COMPASS_BEARING, value); + locationLayerRenderer.setCompassBearing(value); } }; @@ -440,7 +282,7 @@ final class LocationLayerController { new MapboxAnimator.AnimationsValueChangeListener() { @Override public void onNewAnimationValue(Float value) { - updateAccuracyRadius(value); + locationLayerRenderer.setAccuracyRadius(value); } }; @@ -461,4 +303,14 @@ final class LocationLayerController { return holders; } + + void cameraBearingUpdated(double bearing) { + if (renderMode != RenderMode.GPS) { + locationLayerRenderer.cameraBearingUpdated(bearing); + } + } + + void cameraTiltUpdated(double tilt) { + locationLayerRenderer.cameraTiltUpdated(tilt); + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java new file mode 100644 index 000000000..01d4d1272 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java @@ -0,0 +1,47 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; + +import androidx.annotation.Nullable; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.expressions.Expression; + +interface LocationLayerRenderer { + void initializeComponents(Style style); + + void addLayers(LocationComponentPositionManager positionManager); + + void removeLayers(); + + void hide(); + + void cameraTiltUpdated(double tilt); + + void cameraBearingUpdated(double bearing); + + void show(@RenderMode.Mode int renderMode, boolean isStale); + + void styleAccuracy(float accuracyAlpha, int accuracyColor); + + void setLatLng(LatLng latLng); + + void setGpsBearing(Float gpsBearing); + + void setCompassBearing(Float compassBearing); + + void setAccuracyRadius(Float accuracy); + + void styleScaling(Expression scaleExpression); + + void setLocationStale(boolean isStale, int renderMode); + + void updateIconIds(String foregroundIconString, String foregroundStaleIconString, String backgroundIconString, + String backgroundStaleIconString, String bearingIconString); + + void addBitmaps(@RenderMode.Mode int renderMode, @Nullable Bitmap shadowBitmap, Bitmap backgroundBitmap, + Bitmap backgroundStaleBitmap, Bitmap bearingBitmap, + Bitmap foregroundBitmap, Bitmap foregroundStaleBitmap); +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java new file mode 100644 index 000000000..7ad336313 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java @@ -0,0 +1,293 @@ +package com.mapbox.mapboxsdk.location; + +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; + +import java.util.Set; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.LOCATION_SOURCE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_ALPHA; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_COLOR; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ACCURACY_RADIUS; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BACKGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_BEARING_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_COMPASS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.style.layers.Property.NONE; +import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; +import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; + +final class SymbolLocationLayerRenderer implements LocationLayerRenderer { + private Style style; + private final LayerSourceProvider layerSourceProvider; + + private final Set layerSet; + private Feature locationFeature; + private GeoJsonSource locationSource; + + SymbolLocationLayerRenderer(Style style, + LayerSourceProvider layerSourceProvider, + LayerFeatureProvider featureProvider, + boolean isStale) { + this.style = style; + this.layerSourceProvider = layerSourceProvider; + this.layerSet = layerSourceProvider.getEmptyLayerSet(); + this.locationFeature = featureProvider.generateLocationFeature(locationFeature, isStale); + } + + @Override + public void initializeComponents(Style style) { + this.style = style; + addLocationSource(); + } + + @Override + public void addLayers(LocationComponentPositionManager positionManager) { + // positions the top-most reference layer + Layer layer = layerSourceProvider.generateLayer(BEARING_LAYER); + positionManager.addLayerToMap(layer); + layerSet.add(layer.getId()); + + // adds remaining layers while keeping the order + addSymbolLayer(FOREGROUND_LAYER, BEARING_LAYER); + addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); + addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); + addAccuracyLayer(); + } + + @Override + public void removeLayers() { + for (String layerId : layerSet) { + style.removeLayer(layerId); + } + layerSet.clear(); + } + + @Override + public void hide() { + for (String layerId : layerSet) { + setLayerVisibility(layerId, false); + } + } + + @Override + public void cameraTiltUpdated(double tilt) { + updateForegroundOffset(tilt); + } + + @Override + public void cameraBearingUpdated(double bearing) { + updateForegroundBearing((float) bearing); + } + + @Override + public void show(@RenderMode.Mode int renderMode, boolean isStale) { + switch (renderMode) { + case RenderMode.NORMAL: + setLayerVisibility(SHADOW_LAYER, true); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, !isStale); + setLayerVisibility(BEARING_LAYER, false); + break; + case RenderMode.COMPASS: + setLayerVisibility(SHADOW_LAYER, true); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, !isStale); + setLayerVisibility(BEARING_LAYER, true); + break; + case RenderMode.GPS: + setLayerVisibility(SHADOW_LAYER, false); + setLayerVisibility(FOREGROUND_LAYER, true); + setLayerVisibility(BACKGROUND_LAYER, true); + setLayerVisibility(ACCURACY_LAYER, false); + setLayerVisibility(BEARING_LAYER, false); + break; + default: + break; + } + } + + @Override + public void styleAccuracy(float accuracyAlpha, int accuracyColor) { + locationFeature.addNumberProperty(PROPERTY_ACCURACY_ALPHA, accuracyAlpha); + locationFeature.addStringProperty(PROPERTY_ACCURACY_COLOR, colorToRgbaString(accuracyColor)); + refreshSource(); + } + + @Override + public void setLatLng(LatLng latLng) { + Point point = Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()); + setLocationPoint(point); + } + + @Override + public void setGpsBearing(Float gpsBearing) { + setBearingProperty(PROPERTY_GPS_BEARING, gpsBearing); + } + + @Override + public void setCompassBearing(Float compassBearing) { + setBearingProperty(PROPERTY_COMPASS_BEARING, compassBearing); + } + + @Override + public void setAccuracyRadius(Float accuracy) { + updateAccuracyRadius(accuracy); + } + + @Override + public void styleScaling(Expression scaleExpression) { + for (String layerId : layerSet) { + Layer layer = style.getLayer(layerId); + if (layer instanceof SymbolLayer) { + layer.setProperties( + iconSize(scaleExpression) + ); + } + } + } + + @Override + public void setLocationStale(boolean isStale, int renderMode) { + locationFeature.addBooleanProperty(PROPERTY_LOCATION_STALE, isStale); + refreshSource(); + if (renderMode != RenderMode.GPS) { + setLayerVisibility(ACCURACY_LAYER, !isStale); + } + } + + @Override + public void updateIconIds(String foregroundIconString, String foregroundStaleIconString, String backgroundIconString, + String backgroundStaleIconString, String bearingIconString) { + locationFeature.addStringProperty(PROPERTY_FOREGROUND_ICON, foregroundIconString); + locationFeature.addStringProperty(PROPERTY_BACKGROUND_ICON, backgroundIconString); + locationFeature.addStringProperty(PROPERTY_FOREGROUND_STALE_ICON, foregroundStaleIconString); + locationFeature.addStringProperty(PROPERTY_BACKGROUND_STALE_ICON, backgroundStaleIconString); + locationFeature.addStringProperty(PROPERTY_BEARING_ICON, bearingIconString); + refreshSource(); + } + + @Override + public void addBitmaps(@RenderMode.Mode int renderMode, @Nullable Bitmap shadowBitmap, Bitmap backgroundBitmap, + Bitmap backgroundStaleBitmap, Bitmap bearingBitmap, + Bitmap foregroundBitmap, Bitmap foregroundBitmapStale) { + if (shadowBitmap != null) { + style.addImage(SHADOW_ICON, shadowBitmap); + } else { + style.removeImage(SHADOW_ICON); + } + style.addImage(BACKGROUND_ICON, backgroundBitmap); + style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap); + style.addImage(BEARING_ICON, bearingBitmap); + style.addImage(FOREGROUND_ICON, foregroundBitmap); + style.addImage(FOREGROUND_STALE_ICON, foregroundBitmapStale); + } + + private void updateForegroundOffset(double tilt) { + JsonArray foregroundJsonArray = new JsonArray(); + foregroundJsonArray.add(0f); + foregroundJsonArray.add((float) (-0.05 * tilt)); + locationFeature.addProperty(PROPERTY_FOREGROUND_ICON_OFFSET, foregroundJsonArray); + + JsonArray backgroundJsonArray = new JsonArray(); + backgroundJsonArray.add(0f); + backgroundJsonArray.add((float) (0.05 * tilt)); + locationFeature.addProperty(PROPERTY_SHADOW_ICON_OFFSET, backgroundJsonArray); + + refreshSource(); + } + + private void updateForegroundBearing(float bearing) { + setBearingProperty(PROPERTY_GPS_BEARING, bearing); + } + + private void setLayerVisibility(@NonNull String layerId, boolean visible) { + Layer layer = style.getLayer(layerId); + if (layer != null) { + String targetVisibility = visible ? VISIBLE : NONE; + if (!layer.getVisibility().value.equals(targetVisibility)) { + layer.setProperties(visibility(visible ? VISIBLE : NONE)); + } + } + } + + private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) { + Layer layer = layerSourceProvider.generateLayer(layerId); + addLayerToMap(layer, beforeLayerId); + } + + private void addAccuracyLayer() { + Layer accuracyLayer = layerSourceProvider.generateAccuracyLayer(); + addLayerToMap(accuracyLayer, BACKGROUND_LAYER); + } + + private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { + style.addLayerBelow(layer, idBelowLayer); + layerSet.add(layer.getId()); + } + + private void addLocationSource() { + locationSource = layerSourceProvider.generateSource(locationFeature); + style.addSource(locationSource); + } + + private void refreshSource() { + GeoJsonSource source = style.getSourceAs(LOCATION_SOURCE); + if (source != null) { + locationSource.setGeoJson(locationFeature); + } + } + + private void setLocationPoint(Point locationPoint) { + JsonObject properties = locationFeature.properties(); + if (properties != null) { + locationFeature = Feature.fromGeometry(locationPoint, properties); + refreshSource(); + } + } + + private void setBearingProperty(@NonNull String propertyId, float bearing) { + locationFeature.addNumberProperty(propertyId, bearing); + refreshSource(); + } + + private void updateAccuracyRadius(float accuracy) { + locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracy); + refreshSource(); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java new file mode 100644 index 000000000..eefd65924 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java @@ -0,0 +1,565 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +package com.mapbox.mapboxsdk.style.layers; + +import androidx.annotation.ColorInt; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; + +import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; + +/** + * + * + * @see The online documentation + */ +@UiThread +public class LocationIndicatorLayer extends Layer { + + /** + * Creates a LocationIndicatorLayer. + * + * @param nativePtr pointer used by core + */ + @Keep + LocationIndicatorLayer(long nativePtr) { + super(nativePtr); + } + + /** + * Creates a LocationIndicatorLayer. + * + * @param layerId the id of the layer + */ + public LocationIndicatorLayer(String layerId) { + super(); + initialize(layerId); + } + + @Keep + protected native void initialize(String layerId); + + /** + * Get the source id. + * + * @return id of the source + */ + @NonNull + public String getSourceId() { + checkThread(); + return nativeGetSourceId(); + } + + /** + * Get the source layer. + * + * @return sourceLayer the source layer to get + */ + @NonNull + public String getSourceLayer() { + checkThread(); + return nativeGetSourceLayer(); + } + + /** + * Set a single expression filter. + * + * @param filter the expression filter to set + */ + public void setFilter(@NonNull Expression filter) { + checkThread(); + nativeSetFilter(filter.toArray()); + } + + /** + * Set a single expression filter. + * + * @param filter the expression filter to set + * @return This + */ + @NonNull + public LocationIndicatorLayer withFilter(@NonNull Expression filter) { + setFilter(filter); + return this; + } + + /** + * Get a single expression filter. + * + * @return the expression filter to get + */ + @Nullable + public Expression getFilter() { + checkThread(); + JsonElement jsonElement = nativeGetFilter(); + if (jsonElement != null) { + return Expression.Converter.convert(jsonElement); + } else { + return null; + } + } + + /** + * Set a property or properties. + * + * @param properties the var-args properties + * @return This + */ + @NonNull + public LocationIndicatorLayer withProperties(@NonNull PropertyValue... properties) { + setProperties(properties); + return this; + } + + // Property getters + + /** + * Get the TopImage property + * + * @return property wrapper value around String + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getTopImage() { + checkThread(); + return (PropertyValue) new PropertyValue("top-image", nativeGetTopImage()); + } + + /** + * Get the BearingImage property + * + * @return property wrapper value around String + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getBearingImage() { + checkThread(); + return (PropertyValue) new PropertyValue("bearing-image", nativeGetBearingImage()); + } + + /** + * Get the ShadowImage property + * + * @return property wrapper value around String + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getShadowImage() { + checkThread(); + return (PropertyValue) new PropertyValue("shadow-image", nativeGetShadowImage()); + } + + /** + * Get the PerspectiveCompensation property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getPerspectiveCompensation() { + checkThread(); + return (PropertyValue) new PropertyValue("perspective-compensation", nativeGetPerspectiveCompensation()); + } + + /** + * Get the ImageTiltDisplacement property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getImageTiltDisplacement() { + checkThread(); + return (PropertyValue) new PropertyValue("image-tilt-displacement", nativeGetImageTiltDisplacement()); + } + + /** + * Get the Bearing property + * + * @return property wrapper value around Double + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getBearing() { + checkThread(); + return (PropertyValue) new PropertyValue("bearing", nativeGetBearing()); + } + + /** + * Get the Location property + * + * @return property wrapper value around Double[] + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getLocation() { + checkThread(); + return (PropertyValue) new PropertyValue("location", nativeGetLocation()); + } + + /** + * Get the Location property transition options + * + * @return transition options for Double[] + */ + @NonNull + public TransitionOptions getLocationTransition() { + checkThread(); + return nativeGetLocationTransition(); + } + + /** + * Set the Location property transition options + * + * @param options transition options for Double[] + */ + public void setLocationTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetLocationTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the AccuracyRadius property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getAccuracyRadius() { + checkThread(); + return (PropertyValue) new PropertyValue("accuracy-radius", nativeGetAccuracyRadius()); + } + + /** + * Get the AccuracyRadius property transition options + * + * @return transition options for Float + */ + @NonNull + public TransitionOptions getAccuracyRadiusTransition() { + checkThread(); + return nativeGetAccuracyRadiusTransition(); + } + + /** + * Set the AccuracyRadius property transition options + * + * @param options transition options for Float + */ + public void setAccuracyRadiusTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetAccuracyRadiusTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the TopImageSize property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getTopImageSize() { + checkThread(); + return (PropertyValue) new PropertyValue("top-image-size", nativeGetTopImageSize()); + } + + /** + * Get the TopImageSize property transition options + * + * @return transition options for Float + */ + @NonNull + public TransitionOptions getTopImageSizeTransition() { + checkThread(); + return nativeGetTopImageSizeTransition(); + } + + /** + * Set the TopImageSize property transition options + * + * @param options transition options for Float + */ + public void setTopImageSizeTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetTopImageSizeTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the BearingImageSize property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getBearingImageSize() { + checkThread(); + return (PropertyValue) new PropertyValue("bearing-image-size", nativeGetBearingImageSize()); + } + + /** + * Get the BearingImageSize property transition options + * + * @return transition options for Float + */ + @NonNull + public TransitionOptions getBearingImageSizeTransition() { + checkThread(); + return nativeGetBearingImageSizeTransition(); + } + + /** + * Set the BearingImageSize property transition options + * + * @param options transition options for Float + */ + public void setBearingImageSizeTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetBearingImageSizeTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the ShadowImageSize property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getShadowImageSize() { + checkThread(); + return (PropertyValue) new PropertyValue("shadow-image-size", nativeGetShadowImageSize()); + } + + /** + * Get the ShadowImageSize property transition options + * + * @return transition options for Float + */ + @NonNull + public TransitionOptions getShadowImageSizeTransition() { + checkThread(); + return nativeGetShadowImageSizeTransition(); + } + + /** + * Set the ShadowImageSize property transition options + * + * @param options transition options for Float + */ + public void setShadowImageSizeTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetShadowImageSizeTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the AccuracyRadiusColor property + * + * @return property wrapper value around String + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getAccuracyRadiusColor() { + checkThread(); + return (PropertyValue) new PropertyValue("accuracy-radius-color", nativeGetAccuracyRadiusColor()); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @return int representation of a rgba string color + * @throws RuntimeException thrown if property isn't a value + */ + @ColorInt + public int getAccuracyRadiusColorAsInt() { + checkThread(); + PropertyValue value = getAccuracyRadiusColor(); + if (value.isValue()) { + return rgbaToColor(value.getValue()); + } else { + throw new RuntimeException("accuracy-radius-color was set as a Function"); + } + } + + /** + * Get the AccuracyRadiusColor property transition options + * + * @return transition options for String + */ + @NonNull + public TransitionOptions getAccuracyRadiusColorTransition() { + checkThread(); + return nativeGetAccuracyRadiusColorTransition(); + } + + /** + * Set the AccuracyRadiusColor property transition options + * + * @param options transition options for String + */ + public void setAccuracyRadiusColorTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetAccuracyRadiusColorTransition(options.getDuration(), options.getDelay()); + } + + /** + * Get the AccuracyRadiusBorderColor property + * + * @return property wrapper value around String + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue getAccuracyRadiusBorderColor() { + checkThread(); + return (PropertyValue) new PropertyValue("accuracy-radius-border-color", nativeGetAccuracyRadiusBorderColor()); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @return int representation of a rgba string color + * @throws RuntimeException thrown if property isn't a value + */ + @ColorInt + public int getAccuracyRadiusBorderColorAsInt() { + checkThread(); + PropertyValue value = getAccuracyRadiusBorderColor(); + if (value.isValue()) { + return rgbaToColor(value.getValue()); + } else { + throw new RuntimeException("accuracy-radius-border-color was set as a Function"); + } + } + + /** + * Get the AccuracyRadiusBorderColor property transition options + * + * @return transition options for String + */ + @NonNull + public TransitionOptions getAccuracyRadiusBorderColorTransition() { + checkThread(); + return nativeGetAccuracyRadiusBorderColorTransition(); + } + + /** + * Set the AccuracyRadiusBorderColor property transition options + * + * @param options transition options for String + */ + public void setAccuracyRadiusBorderColorTransition(@NonNull TransitionOptions options) { + checkThread(); + nativeSetAccuracyRadiusBorderColorTransition(options.getDuration(), options.getDelay()); + } + + @NonNull + @Keep + private native Object nativeGetTopImage(); + + @NonNull + @Keep + private native Object nativeGetBearingImage(); + + @NonNull + @Keep + private native Object nativeGetShadowImage(); + + @NonNull + @Keep + private native Object nativeGetPerspectiveCompensation(); + + @NonNull + @Keep + private native Object nativeGetImageTiltDisplacement(); + + @NonNull + @Keep + private native Object nativeGetBearing(); + + @NonNull + @Keep + private native Object nativeGetLocation(); + + @NonNull + @Keep + private native TransitionOptions nativeGetLocationTransition(); + + @Keep + private native void nativeSetLocationTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetAccuracyRadius(); + + @NonNull + @Keep + private native TransitionOptions nativeGetAccuracyRadiusTransition(); + + @Keep + private native void nativeSetAccuracyRadiusTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetTopImageSize(); + + @NonNull + @Keep + private native TransitionOptions nativeGetTopImageSizeTransition(); + + @Keep + private native void nativeSetTopImageSizeTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetBearingImageSize(); + + @NonNull + @Keep + private native TransitionOptions nativeGetBearingImageSizeTransition(); + + @Keep + private native void nativeSetBearingImageSizeTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetShadowImageSize(); + + @NonNull + @Keep + private native TransitionOptions nativeGetShadowImageSizeTransition(); + + @Keep + private native void nativeSetShadowImageSizeTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetAccuracyRadiusColor(); + + @NonNull + @Keep + private native TransitionOptions nativeGetAccuracyRadiusColorTransition(); + + @Keep + private native void nativeSetAccuracyRadiusColorTransition(long duration, long delay); + + @NonNull + @Keep + private native Object nativeGetAccuracyRadiusBorderColor(); + + @NonNull + @Keep + private native TransitionOptions nativeGetAccuracyRadiusBorderColorTransition(); + + @Keep + private native void nativeSetAccuracyRadiusBorderColorTransition(long duration, long delay); + + @Override + @Keep + protected native void finalize() throws Throwable; + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index b3ae7a325..907867707 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -1645,6 +1645,226 @@ public class PropertyFactory { return new PaintPropertyValue<>("background-opacity", expression); } + /** + * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue perspectiveCompensation(Float value) { + return new PaintPropertyValue<>("perspective-compensation", value); + } + + /** + * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue perspectiveCompensation(Expression expression) { + return new PaintPropertyValue<>("perspective-compensation", expression); + } + + /** + * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue imageTiltDisplacement(Float value) { + return new PaintPropertyValue<>("image-tilt-displacement", value); + } + + /** + * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue imageTiltDisplacement(Expression expression) { + return new PaintPropertyValue<>("image-tilt-displacement", expression); + } + + /** + * The bearing of the location indicator. + * + * @param value a Double value + * @return property wrapper around Double + */ + public static PropertyValue bearing(Double value) { + return new PaintPropertyValue<>("bearing", value); + } + + /** + * The bearing of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue bearing(Expression expression) { + return new PaintPropertyValue<>("bearing", expression); + } + + /** + * An array of [latitude, longitude, altitude] position of the location indicator. + * + * @param value a Double[] value + * @return property wrapper around Double[] + */ + public static PropertyValue location(Double[] value) { + return new PaintPropertyValue<>("location", value); + } + + /** + * An array of [latitude, longitude, altitude] position of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue location(Expression expression) { + return new PaintPropertyValue<>("location", expression); + } + + /** + * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue accuracyRadius(Float value) { + return new PaintPropertyValue<>("accuracy-radius", value); + } + + /** + * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadius(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius", expression); + } + + /** + * The size of the top image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue topImageSize(Float value) { + return new PaintPropertyValue<>("top-image-size", value); + } + + /** + * The size of the top image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue topImageSize(Expression expression) { + return new PaintPropertyValue<>("top-image-size", expression); + } + + /** + * The size of the bearing image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue bearingImageSize(Float value) { + return new PaintPropertyValue<>("bearing-image-size", value); + } + + /** + * The size of the bearing image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue bearingImageSize(Expression expression) { + return new PaintPropertyValue<>("bearing-image-size", expression); + } + + /** + * The size of the shadow image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue shadowImageSize(Float value) { + return new PaintPropertyValue<>("shadow-image-size", value); + } + + /** + * The size of the shadow image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue shadowImageSize(Expression expression) { + return new PaintPropertyValue<>("shadow-image-size", expression); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a int color value + * @return property wrapper around String color + */ + public static PropertyValue accuracyRadiusColor(@ColorInt int value) { + return new PaintPropertyValue<>("accuracy-radius-color", colorToRgbaString(value)); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue accuracyRadiusColor(String value) { + return new PaintPropertyValue<>("accuracy-radius-color", value); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadiusColor(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius-color", expression); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a int color value + * @return property wrapper around String color + */ + public static PropertyValue accuracyRadiusBorderColor(@ColorInt int value) { + return new PaintPropertyValue<>("accuracy-radius-border-color", colorToRgbaString(value)); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue accuracyRadiusBorderColor(String value) { + return new PaintPropertyValue<>("accuracy-radius-border-color", value); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadiusBorderColor(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius-border-color", expression); + } + /** * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. * @@ -2615,4 +2835,64 @@ public class PropertyFactory { return new LayoutPropertyValue<>("circle-sort-key", value); } + /** + * Name of image in sprite to use as the top of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue topImage(String value) { + return new LayoutPropertyValue<>("top-image", value); + } + + /** + * Name of image in sprite to use as the top of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue topImage(Expression value) { + return new LayoutPropertyValue<>("top-image", value); + } + + /** + * Name of image in sprite to use as the middle of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue bearingImage(String value) { + return new LayoutPropertyValue<>("bearing-image", value); + } + + /** + * Name of image in sprite to use as the middle of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue bearingImage(Expression value) { + return new LayoutPropertyValue<>("bearing-image", value); + } + + /** + * Name of image in sprite to use as the background of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue shadowImage(String value) { + return new LayoutPropertyValue<>("shadow-image", value); + } + + /** + * Name of image in sprite to use as the background of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue shadowImage(Expression value) { + return new LayoutPropertyValue<>("shadow-image", value); + } + } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs index 3d2ccffba..db1510aab 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs @@ -42,7 +42,7 @@ public class <%- camelize(type) %>Layer extends Layer { super(nativePtr); } -<% if (type === 'background') { -%> +<% if (type === 'background' || type === 'location-indicator') { -%> /** * Creates a <%- camelize(type) %>Layer. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java index aa0b370e4..195f8ad89 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java @@ -53,10 +53,23 @@ public class BitmapUtils { * @return the merged bitmap */ public static Bitmap mergeBitmap(@NonNull Bitmap background, @NonNull Bitmap foreground) { + return mergeBitmap(background, foreground, 10f, 10f); + } + + /** + * 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 + * @param left position of the left side of the foreground bitmap + * @param top position of the top side of the foreground bitmap + * @return the merged bitmap + */ + public static Bitmap mergeBitmap(@NonNull Bitmap background, @NonNull Bitmap foreground, float left, float top) { Bitmap result = Bitmap.createBitmap(background.getWidth(), background.getHeight(), background.getConfig()); Canvas canvas = new Canvas(result); canvas.drawBitmap(background, 0f, 0f, null); - canvas.drawBitmap(foreground, 10, 10, null); + canvas.drawBitmap(foreground, left, top, null); return result; } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index 5ff7c2bb3..c41732bc9 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -16,6 +16,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import java.util.HashSet; import java.util.Set; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_LAYER; @@ -68,7 +69,7 @@ public class LocationLayerControllerTest { LocationComponentOptions options = mock(LocationComponentOptions.class); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addSource(locationSource); } @@ -85,7 +86,7 @@ public class LocationLayerControllerTest { LocationComponentOptions options = mock(LocationComponentOptions.class); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addLayerBelow(shadowLayer, BACKGROUND_LAYER); } @@ -102,7 +103,7 @@ public class LocationLayerControllerTest { LocationComponentOptions options = mock(LocationComponentOptions.class); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addLayerBelow(backgroundLayer, FOREGROUND_LAYER); } @@ -119,7 +120,7 @@ public class LocationLayerControllerTest { LocationComponentOptions options = mock(LocationComponentOptions.class); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addLayerBelow(foregroundLayer, BEARING_LAYER); } @@ -138,7 +139,7 @@ public class LocationLayerControllerTest { when(options.layerBelow()).thenReturn(layerBelow); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addLayerBelow(bearingLayer, layerBelow); } @@ -155,7 +156,7 @@ public class LocationLayerControllerTest { LocationComponentOptions options = mock(LocationComponentOptions.class); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addLayerBelow(accuracyLayer, BACKGROUND_LAYER); } @@ -166,16 +167,18 @@ public class LocationLayerControllerTest { LayerSourceProvider sourceProvider = buildLayerProvider(); GeoJsonSource locationSource = mock(GeoJsonSource.class); when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + Set layerSet = new HashSet<>(); + when(sourceProvider.getEmptyLayerSet()).thenReturn(layerSet); LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); LocationComponentOptions options = mock(LocationComponentOptions.class); LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.initializeComponents(mapboxMap.getStyle(), options); - assertEquals(5, controller.layerSet.size()); + assertEquals(5, layerSet.size()); } @Test @@ -191,7 +194,7 @@ public class LocationLayerControllerTest { // Style is applied on initialization new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(SHADOW_ICON, bitmap); } @@ -208,7 +211,7 @@ public class LocationLayerControllerTest { when(options.elevation()).thenReturn(0f); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style, times(0)).addImage(SHADOW_ICON, bitmap); } @@ -228,7 +231,7 @@ public class LocationLayerControllerTest { when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(FOREGROUND_ICON, bitmap); } @@ -248,7 +251,7 @@ public class LocationLayerControllerTest { when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(FOREGROUND_STALE_ICON, bitmap); } @@ -268,7 +271,7 @@ public class LocationLayerControllerTest { when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(BACKGROUND_ICON, bitmap); } @@ -288,7 +291,7 @@ public class LocationLayerControllerTest { when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(BACKGROUND_STALE_ICON, bitmap); } @@ -308,7 +311,7 @@ public class LocationLayerControllerTest { when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap); new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(BEARING_ICON, bitmap); } @@ -326,7 +329,7 @@ public class LocationLayerControllerTest { LocationLayerController layerController = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); Layer bearingLayer2 = mock(Layer.class); when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer2); @@ -371,7 +374,7 @@ public class LocationLayerControllerTest { LocationLayerController layerController = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); options = mock(LocationComponentOptions.class); layerBelow = "layer-below"; @@ -394,7 +397,7 @@ public class LocationLayerControllerTest { LocationLayerController layerController = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); options = mock(LocationComponentOptions.class); layerController.applyStyle(options); @@ -415,10 +418,9 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); - layer.updateForegroundOffset(2d); + layer.cameraTiltUpdated(2d); verify(locationFeature).addProperty(eq(PROPERTY_FOREGROUND_ICON_OFFSET), any(JsonElement.class)); } @@ -434,9 +436,8 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); - layer.updateForegroundOffset(2d); + bitmapProvider, options, internalRenderModeChangedListener, false); + layer.cameraTiltUpdated(2d); verify(locationFeature).addProperty(eq(PROPERTY_SHADOW_ICON_OFFSET), any(JsonElement.class)); } @@ -453,8 +454,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); getAnimationListener(ANIMATOR_LAYER_LATLNG, layer.getAnimationListeners()).onNewAnimationValue(new LatLng()); @@ -474,8 +474,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.GPS); float gpsBearing = 2f; @@ -496,8 +495,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.COMPASS); float gpsBearing = 2f; @@ -517,8 +515,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.COMPASS); float compassBearing = 2f; @@ -540,8 +537,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.GPS); float compassBearing = 2f; @@ -561,8 +557,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.NORMAL); float accuracyRadiusValue = 2f; @@ -584,8 +579,7 @@ public class LocationLayerControllerTest { Feature locationFeature = mock(Feature.class); LocationLayerController layer = new LocationLayerController( mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(locationFeature, options), - bitmapProvider, options, internalRenderModeChangedListener - ); + bitmapProvider, options, internalRenderModeChangedListener, false); layer.setRenderMode(RenderMode.GPS); float accuracyRadiusValue = 2f; @@ -605,7 +599,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.NORMAL); controller.setRenderMode(RenderMode.NORMAL); @@ -624,7 +618,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.GPS); controller.setRenderMode(RenderMode.GPS); @@ -648,7 +642,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(FOREGROUND_ICON, bitmap); @@ -669,13 +663,13 @@ public class LocationLayerControllerTest { private LayerFeatureProvider buildFeatureProvider(@NonNull LocationComponentOptions options) { LayerFeatureProvider provider = mock(LayerFeatureProvider.class); - when(provider.generateLocationFeature(null, options)).thenReturn(mock(Feature.class)); + when(provider.generateLocationFeature(null, options.enableStaleState())).thenReturn(mock(Feature.class)); return provider; } private LayerFeatureProvider buildFeatureProvider(Feature feature, @NonNull LocationComponentOptions options) { LayerFeatureProvider provider = mock(LayerFeatureProvider.class); - when(provider.generateLocationFeature(null, options)).thenReturn(feature); + when(provider.generateLocationFeature(null, options.enableStaleState())).thenReturn(feature); return provider; } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java new file mode 100644 index 000000000..1a14d242f --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java @@ -0,0 +1,330 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +package com.mapbox.mapboxsdk.testapp.style; + +import android.graphics.Color; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.mapbox.mapboxsdk.maps.BaseLayerTest; +import org.junit.Before; +import timber.log.Timber; + +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.mapbox.mapboxsdk.style.expressions.Expression.*; +import static org.junit.Assert.*; +import static com.mapbox.mapboxsdk.style.layers.Property.*; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; + +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; + +/** + * Basic smoke tests for LocationIndicatorLayer + */ +@RunWith(AndroidJUnit4.class) +public class LocationIndicatorLayerTest extends BaseLayerTest { + + private LocationIndicatorLayer layer; + + @Before + @UiThreadTest + public void beforeTest(){ + super.before(); + layer = new LocationIndicatorLayer("my-layer"); + setupLayer(layer); + } + + @Test + @UiThreadTest + public void testSetVisibility() { + Timber.i("Visibility"); + assertNotNull(layer); + + // Get initial + assertEquals(layer.getVisibility().getValue(), VISIBLE); + + // Set + layer.setProperties(visibility(NONE)); + assertEquals(layer.getVisibility().getValue(), NONE); + } + + @Test + @UiThreadTest + public void testTopImageAsConstant() { + Timber.i("top-image"); + assertNotNull(layer); + assertNull(layer.getTopImage().getValue()); + + // Set and Get + String propertyValue = "undefined"; + layer.setProperties(topImage(propertyValue)); + assertEquals(layer.getTopImage().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testBearingImageAsConstant() { + Timber.i("bearing-image"); + assertNotNull(layer); + assertNull(layer.getBearingImage().getValue()); + + // Set and Get + String propertyValue = "undefined"; + layer.setProperties(bearingImage(propertyValue)); + assertEquals(layer.getBearingImage().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testShadowImageAsConstant() { + Timber.i("shadow-image"); + assertNotNull(layer); + assertNull(layer.getShadowImage().getValue()); + + // Set and Get + String propertyValue = "undefined"; + layer.setProperties(shadowImage(propertyValue)); + assertEquals(layer.getShadowImage().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testPerspectiveCompensationAsConstant() { + Timber.i("perspective-compensation"); + assertNotNull(layer); + assertNull(layer.getPerspectiveCompensation().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(perspectiveCompensation(propertyValue)); + assertEquals(layer.getPerspectiveCompensation().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testImageTiltDisplacementAsConstant() { + Timber.i("image-tilt-displacement"); + assertNotNull(layer); + assertNull(layer.getImageTiltDisplacement().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(imageTiltDisplacement(propertyValue)); + assertEquals(layer.getImageTiltDisplacement().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testBearingAsConstant() { + Timber.i("bearing"); + assertNotNull(layer); + assertNull(layer.getBearing().getValue()); + + // Set and Get + Double propertyValue = 0.3; + layer.setProperties(bearing(propertyValue)); + assertEquals(layer.getBearing().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testLocationTransition() { + Timber.i("locationTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setLocationTransition(options); + assertEquals(layer.getLocationTransition(), options); + } + + @Test + @UiThreadTest + public void testLocationAsConstant() { + Timber.i("location"); + assertNotNull(layer); + assertNull(layer.getLocation().getValue()); + + // Set and Get + Double[] propertyValue = new Double[] {0.0, 0.0, 0.0}; + layer.setProperties(location(propertyValue)); + assertEquals(layer.getLocation().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusTransition() { + Timber.i("accuracy-radiusTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setAccuracyRadiusTransition(options); + assertEquals(layer.getAccuracyRadiusTransition(), options); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusAsConstant() { + Timber.i("accuracy-radius"); + assertNotNull(layer); + assertNull(layer.getAccuracyRadius().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(accuracyRadius(propertyValue)); + assertEquals(layer.getAccuracyRadius().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testTopImageSizeTransition() { + Timber.i("top-image-sizeTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setTopImageSizeTransition(options); + assertEquals(layer.getTopImageSizeTransition(), options); + } + + @Test + @UiThreadTest + public void testTopImageSizeAsConstant() { + Timber.i("top-image-size"); + assertNotNull(layer); + assertNull(layer.getTopImageSize().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(topImageSize(propertyValue)); + assertEquals(layer.getTopImageSize().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testBearingImageSizeTransition() { + Timber.i("bearing-image-sizeTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setBearingImageSizeTransition(options); + assertEquals(layer.getBearingImageSizeTransition(), options); + } + + @Test + @UiThreadTest + public void testBearingImageSizeAsConstant() { + Timber.i("bearing-image-size"); + assertNotNull(layer); + assertNull(layer.getBearingImageSize().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(bearingImageSize(propertyValue)); + assertEquals(layer.getBearingImageSize().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testShadowImageSizeTransition() { + Timber.i("shadow-image-sizeTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setShadowImageSizeTransition(options); + assertEquals(layer.getShadowImageSizeTransition(), options); + } + + @Test + @UiThreadTest + public void testShadowImageSizeAsConstant() { + Timber.i("shadow-image-size"); + assertNotNull(layer); + assertNull(layer.getShadowImageSize().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(shadowImageSize(propertyValue)); + assertEquals(layer.getShadowImageSize().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusColorTransition() { + Timber.i("accuracy-radius-colorTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setAccuracyRadiusColorTransition(options); + assertEquals(layer.getAccuracyRadiusColorTransition(), options); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusColorAsConstant() { + Timber.i("accuracy-radius-color"); + assertNotNull(layer); + assertNull(layer.getAccuracyRadiusColor().getValue()); + + // Set and Get + String propertyValue = "rgba(255,128,0,0.7)"; + layer.setProperties(accuracyRadiusColor(propertyValue)); + assertEquals(layer.getAccuracyRadiusColor().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusColorAsIntConstant() { + Timber.i("accuracy-radius-color"); + assertNotNull(layer); + + // Set and Get + layer.setProperties(accuracyRadiusColor(Color.argb(127, 255, 127, 0))); + assertEquals(layer.getAccuracyRadiusColorAsInt(), Color.argb(127, 255, 127, 0)); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusBorderColorTransition() { + Timber.i("accuracy-radius-border-colorTransitionOptions"); + assertNotNull(layer); + + // Set and Get + TransitionOptions options = new TransitionOptions(300, 100); + layer.setAccuracyRadiusBorderColorTransition(options); + assertEquals(layer.getAccuracyRadiusBorderColorTransition(), options); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusBorderColorAsConstant() { + Timber.i("accuracy-radius-border-color"); + assertNotNull(layer); + assertNull(layer.getAccuracyRadiusBorderColor().getValue()); + + // Set and Get + String propertyValue = "rgba(255,128,0,0.7)"; + layer.setProperties(accuracyRadiusBorderColor(propertyValue)); + assertEquals(layer.getAccuracyRadiusBorderColor().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testAccuracyRadiusBorderColorAsIntConstant() { + Timber.i("accuracy-radius-border-color"); + assertNotNull(layer); + + // Set and Get + layer.setProperties(accuracyRadiusBorderColor(Color.argb(127, 255, 127, 0))); + assertEquals(layer.getAccuracyRadiusBorderColorAsInt(), Color.argb(127, 255, 127, 0)); + } +} diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index dd18ad581..c5515a396 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -43,7 +43,7 @@ public class <%- camelize(type) %>LayerTest extends BaseLayerTest { @UiThreadTest public void beforeTest(){ super.before(); -<% if (type === 'background') { -%> +<% if (type === 'background' || type === 'location-indicator') { -%> layer = new <%- camelize(type) %>Layer("my-layer"); <% } else { -%> layer = new <%- camelize(type) %>Layer("my-layer", "composite"); @@ -51,7 +51,7 @@ public class <%- camelize(type) %>LayerTest extends BaseLayerTest { <% } -%> setupLayer(layer); } -<% if (type !== 'background') { -%> +<% if (type !== 'background' && type !== 'location-indicator') { -%> @Test @UiThreadTest @@ -75,7 +75,7 @@ public class <%- camelize(type) %>LayerTest extends BaseLayerTest { layer.setProperties(visibility(NONE)); assertEquals(layer.getVisibility().getValue(), NONE); } -<% if (!(type === 'background' || type === 'raster' || type === 'hillshade')) { -%> +<% if (!(type === 'background' || type === 'location-indicator' || type === 'raster' || type === 'hillshade')) { -%> @Test @UiThreadTest diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java index e76fb59e5..f805918cc 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java @@ -129,6 +129,7 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea locationComponent.activateLocationComponent( LocationComponentActivationOptions .builder(this, style) + .useSpecializedLocationLayer(true) .useDefaultLocationEngine(true) .locationEngineRequest(new LocationEngineRequest.Builder(750) .setFastestInterval(750) diff --git a/core-files.json b/core-files.json deleted file mode 100644 index 70b748234..000000000 --- a/core-files.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "//": "This file can be edited manually and is the canonical source.", - "sources": [ - "vendor-android/mapbox-gl-native/platform/android/src/main.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_backend.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_frontend.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/annotation/marker.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/annotation/polygon.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/annotation/polyline.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/async_task.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/attach_env.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/bitmap.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/bitmap_factory.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/conversion/collection.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/conversion/color.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/conversion/constant.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature_collection.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry_collection.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/line_string.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_line_string.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_point.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_polygon.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/point.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geojson/polygon.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_bounds.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_quad.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/geometry/projected_meters.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/graphics/pointf.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/graphics/rectf.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/gson/json_array.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/gson/json_element.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/gson/json_object.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/gson/json_primitive.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/i18n/collator.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/i18n/number_format.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/image.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/java/util.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/java_types.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/jni.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/jni_native.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/logger.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/logging_android.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/mapbox.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/map/camera_position.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/map/image.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/map_renderer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/map_renderer_runnable.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/native_map_view.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/run_loop.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshot.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshotter.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/string_util.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/filter.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/position.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/transition_options.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/url_or_tileset.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/formatted.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/formatted_section.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/background_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/circle_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/custom_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_extrusion_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/heatmap_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/hillshade_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer_manager.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/line_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/raster_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/layers/symbol_layer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/light.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/position.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/custom_geometry_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/geojson_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/image_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_dem_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/unknown_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/sources/vector_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/transition_options.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/style/value.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/text/local_glyph_rasterizer.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/gl_functions.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/thread.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/timer.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gfx/headless_backend.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gfx/headless_frontend.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/gl/headless_backend.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/map/map_snapshotter.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/text/bidi.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/compression.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/monotonic_timer.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/png_writer.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/thread_local.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/util/utf.cpp", - "vendor-android/mapbox-gl-native/platform/linux/src/headless_backend_egl.cpp" - ], - "public_headers": { - "jni/string_conversion.hpp": "vendor-android/mapbox-gl-native/platform/default/include/jni/string_conversion.hpp", - "mbgl/gfx/headless_backend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gfx/headless_backend.hpp", - "mbgl/gfx/headless_frontend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gfx/headless_frontend.hpp", - "mbgl/gl/headless_backend.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/gl/headless_backend.hpp", - "mbgl/map/map_snapshotter.hpp": "vendor-android/mapbox-gl-native/platform/default/include/mbgl/map/map_snapshotter.hpp" - }, - "private_headers": { - "android_renderer_backend.hpp": "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_backend.hpp", - "android_renderer_frontend.hpp": "vendor-android/mapbox-gl-native/platform/android/src/android_renderer_frontend.hpp", - "annotation/marker.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/marker.hpp", - "annotation/multi_point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/multi_point.hpp", - "annotation/polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/polygon.hpp", - "annotation/polyline.hpp": "vendor-android/mapbox-gl-native/platform/android/src/annotation/polyline.hpp", - "attach_env.hpp": "vendor-android/mapbox-gl-native/platform/android/src/attach_env.hpp", - "bitmap.hpp": "vendor-android/mapbox-gl-native/platform/android/src/bitmap.hpp", - "bitmap_factory.hpp": "vendor-android/mapbox-gl-native/platform/android/src/bitmap_factory.hpp", - "conversion/collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/collection.hpp", - "conversion/color.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/color.hpp", - "conversion/constant.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/constant.hpp", - "conversion/conversion.hpp": "vendor-android/mapbox-gl-native/platform/android/src/conversion/conversion.hpp", - "geojson/feature.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature.hpp", - "geojson/feature_collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/feature_collection.hpp", - "geojson/geometry.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry.hpp", - "geojson/geometry_collection.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/geometry_collection.hpp", - "geojson/line_string.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/line_string.hpp", - "geojson/multi_line_string.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_line_string.hpp", - "geojson/multi_point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_point.hpp", - "geojson/multi_polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/multi_polygon.hpp", - "geojson/point.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/point.hpp", - "geojson/polygon.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/polygon.hpp", - "geojson/util.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geojson/util.hpp", - "geometry/lat_lng.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng.hpp", - "geometry/lat_lng_bounds.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_bounds.hpp", - "geometry/lat_lng_quad.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/lat_lng_quad.hpp", - "geometry/projected_meters.hpp": "vendor-android/mapbox-gl-native/platform/android/src/geometry/projected_meters.hpp", - "graphics/pointf.hpp": "vendor-android/mapbox-gl-native/platform/android/src/graphics/pointf.hpp", - "graphics/rectf.hpp": "vendor-android/mapbox-gl-native/platform/android/src/graphics/rectf.hpp", - "gson/json_array.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_array.hpp", - "gson/json_element.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_element.hpp", - "gson/json_object.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_object.hpp", - "gson/json_primitive.hpp": "vendor-android/mapbox-gl-native/platform/android/src/gson/json_primitive.hpp", - "java/util.hpp": "vendor-android/mapbox-gl-native/platform/android/src/java/util.hpp", - "java_types.hpp": "vendor-android/mapbox-gl-native/platform/android/src/java_types.hpp", - "jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/jni.hpp", - "jni_native.hpp": "vendor-android/mapbox-gl-native/platform/android/src/jni_native.hpp", - "i18n/collator_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/i18n/collator_jni.hpp", - "i18n/number_format_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/i18n/number_format_jni.hpp", - "logger.hpp": "vendor-android/mapbox-gl-native/platform/android/src/logger.hpp", - "mapbox.hpp": "vendor-android/mapbox-gl-native/platform/android/src/mapbox.hpp", - "map/camera_position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map/camera_position.hpp", - "map/image.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map/image.hpp", - "map_renderer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map_renderer.hpp", - "map_renderer_runnable.hpp": "vendor-android/mapbox-gl-native/platform/android/src/map_renderer_runnable.hpp", - "native_map_view.hpp": "vendor-android/mapbox-gl-native/platform/android/src/native_map_view.hpp", - "run_loop_impl.hpp": "vendor-android/mapbox-gl-native/platform/android/src/run_loop_impl.hpp", - "snapshotter/map_snapshot.hpp": "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshot.hpp", - "snapshotter/map_snapshotter.hpp": "vendor-android/mapbox-gl-native/platform/android/src/snapshotter/map_snapshotter.hpp", - "style/android_conversion.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/android_conversion.hpp", - "style/conversion/filter.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/filter.hpp", - "style/conversion/position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/position.hpp", - "style/conversion/property_expression.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/property_expression.hpp", - "style/conversion/property_value.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/property_value.hpp", - "style/conversion/transition_options.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/transition_options.hpp", - "style/conversion/url_or_tileset.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/conversion/url_or_tileset.hpp", - "style/formatted.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/formatted.hpp", - "style/formatted_section.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/formatted_section.hpp", - "style/layers/background_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/background_layer.hpp", - "style/layers/circle_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/circle_layer.hpp", - "style/layers/custom_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/custom_layer.hpp", - "style/layers/fill_extrusion_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_extrusion_layer.hpp", - "style/layers/fill_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/fill_layer.hpp", - "style/layers/heatmap_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/heatmap_layer.hpp", - "style/layers/hillshade_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/hillshade_layer.hpp", - "style/layers/layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer.hpp", - "style/layers/layer_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/layer_manager.hpp", - "style/layers/line_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/line_layer.hpp", - "style/layers/raster_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/raster_layer.hpp", - "style/layers/symbol_layer.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/layers/symbol_layer.hpp", - "style/light.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/light.hpp", - "style/position.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/position.hpp", - "style/sources/custom_geometry_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/custom_geometry_source.hpp", - "style/sources/geojson_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/geojson_source.hpp", - "style/sources/image_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/image_source.hpp", - "style/sources/raster_dem_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_dem_source.hpp", - "style/sources/raster_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/raster_source.hpp", - "style/sources/source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/source.hpp", - "style/sources/unknown_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/unknown_source.hpp", - "style/sources/vector_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/sources/vector_source.hpp", - "style/transition_options.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/transition_options.hpp", - "style/value.hpp": "vendor-android/mapbox-gl-native/platform/android/src/style/value.hpp", - "text/local_glyph_rasterizer_jni.hpp": "vendor-android/mapbox-gl-native/platform/android/src/text/local_glyph_rasterizer_jni.hpp" - } -} \ No newline at end of file diff --git a/filesource-files.json b/filesource-files.json deleted file mode 100644 index 7be8bc8a0..000000000 --- a/filesource-files.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "//": "This file can be edited manually and is the canonical source.", - "sources": [ - "vendor-android/mapbox-gl-native/platform/android/src/asset_manager_file_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/connectivity_listener.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/file_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/http_file_source.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_manager.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_definition.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_error.cpp", - "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_status.cpp", - "vendor-android/mapbox-gl-native/platform/default/src/mbgl/storage/sqlite3.cpp" - ], - "public_headers": {}, - "private_headers": { - "asset_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/asset_manager.hpp", - "asset_manager_file_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/asset_manager_file_source.hpp", - "connectivity_listener.hpp": "vendor-android/mapbox-gl-native/platform/android/src/connectivity_listener.hpp", - "file_source.hpp": "vendor-android/mapbox-gl-native/platform/android/src/file_source.hpp", - "offline/offline_manager.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_manager.hpp", - "offline/offline_region.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region.hpp", - "offline/offline_region_definition.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_definition.hpp", - "offline/offline_region_error.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_error.hpp", - "offline/offline_region_status.hpp": "vendor-android/mapbox-gl-native/platform/android/src/offline/offline_region_status.hpp" - } -} \ No newline at end of file diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 3ed77405a..821f03666 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -68,7 +68,12 @@ global.propertyType = function propertyType(property) { case 'boolean': return 'Boolean'; case 'number': - return 'Float'; + if (/bearing$/.test(property.name) && + property.period == 360 && + property.units =='degrees') { + return 'Double'; + } + return /location$/.test(property.name) ? 'Double' : 'Float'; case 'formatted': return 'Formatted'; case 'string': @@ -79,7 +84,7 @@ global.propertyType = function propertyType(property) { case 'color': return 'String'; case 'array': - return `${propertyType({type:property.value})}[]`; + return `${propertyType({type:property.value, name: property.name})}[]`; default: throw new Error(`unknown type for ${property.name}`); } @@ -205,6 +210,11 @@ global.defaultValueJava = function(property) { case 'boolean': return 'true'; case 'number': + if (/bearing$/.test(property.name) && + property.period == 360 && + property.units =='degrees') { + return '0.3'; + } return '0.3f'; case 'formatted': return 'new Formatted(new FormattedSection("default"))' @@ -225,14 +235,16 @@ global.defaultValueJava = function(property) { return 'new String[0]'; } case 'number': - var result ='new Float[] {'; + var isDouble = /location$/.test(property.name) + console.log(isDouble) + var result = 'new ' + (isDouble ? 'Double' : 'Float') + '[] {'; for (var i = 0; i < property.length; i++) { - result += "0f"; + result += isDouble ? '0.0' : '0f'; if (i +1 != property.length) { - result += ", "; + result += ', '; } } - return result + "}"; + return result + '}'; } default: throw new Error(`unknown type for ${property.name}`) } diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index c4b061bd9..3d2e20810 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit c4b061bd959a0efa5d0202d16d39e92e4f416abb +Subproject commit 3d2e20810cb9a4e2f351774889fd04b87814694c From dbaad6312bb2ec178a14a4acf919b52baf74d603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 14 Apr 2020 13:15:24 +0200 Subject: [PATCH 125/185] hide the LocationIndicatorLayer impl --- .../src/cpp/style/layers/background_layer.cpp | 2 +- .../src/cpp/style/layers/background_layer.hpp | 2 +- .../src/cpp/style/layers/circle_layer.cpp | 2 +- .../src/cpp/style/layers/circle_layer.hpp | 2 +- .../cpp/style/layers/fill_extrusion_layer.cpp | 2 +- .../cpp/style/layers/fill_extrusion_layer.hpp | 2 +- .../src/cpp/style/layers/fill_layer.cpp | 2 +- .../src/cpp/style/layers/fill_layer.hpp | 2 +- .../src/cpp/style/layers/heatmap_layer.cpp | 2 +- .../src/cpp/style/layers/heatmap_layer.hpp | 2 +- .../src/cpp/style/layers/hillshade_layer.cpp | 2 +- .../src/cpp/style/layers/hillshade_layer.hpp | 2 +- .../src/cpp/style/layers/layer.cpp.ejs | 2 +- .../src/cpp/style/layers/layer.hpp.ejs | 6 +- .../src/cpp/style/layers/line_layer.cpp | 2 +- .../src/cpp/style/layers/line_layer.hpp | 2 +- .../style/layers/location_indicator_layer.cpp | 2 +- .../style/layers/location_indicator_layer.hpp | 4 +- .../src/cpp/style/layers/raster_layer.cpp | 2 +- .../src/cpp/style/layers/raster_layer.hpp | 2 +- .../src/cpp/style/layers/symbol_layer.cpp | 2 +- .../src/cpp/style/layers/symbol_layer.hpp | 2 +- .../IndicatorLocationLayerRenderer.java | 27 +- .../location/LayerSourceProvider.java | 6 +- .../LocationIndicatorLayer.java | 68 +--- .../location/LocationPropertyFactory.java | 312 ++++++++++++++++++ .../style/layers/BackgroundLayer.java | 2 +- .../mapboxsdk/style/layers/CircleLayer.java | 2 +- .../style/layers/FillExtrusionLayer.java | 2 +- .../mapboxsdk/style/layers/FillLayer.java | 2 +- .../mapboxsdk/style/layers/HeatmapLayer.java | 2 +- .../style/layers/HillshadeLayer.java | 2 +- .../style/layers/LayoutPropertyValue.java | 4 +- .../mapboxsdk/style/layers/LineLayer.java | 2 +- .../style/layers/PaintPropertyValue.java | 4 +- .../mapboxsdk/style/layers/Property.java | 2 +- .../style/layers/PropertyFactory.java | 282 +--------------- .../mapboxsdk/style/layers/RasterLayer.java | 2 +- .../mapboxsdk/style/layers/SymbolLayer.java | 2 +- .../mapboxsdk/style/layers/layer.java.ejs | 18 +- .../mapboxsdk/style/layers/property.java.ejs | 2 +- .../style/layers/property_factory.java.ejs | 17 +- .../mapbox/mapboxsdk/style/light/Light.java | 2 +- .../mapboxsdk/style/light/light.java.ejs | 2 +- .../LocationIndicatorLayerTest.java | 7 +- .../testapp/style/BackgroundLayerTest.java | 2 +- .../testapp/style/CircleLayerTest.java | 2 +- .../testapp/style/FillExtrusionLayerTest.java | 2 +- .../testapp/style/FillLayerTest.java | 2 +- .../testapp/style/HeatmapLayerTest.java | 2 +- .../testapp/style/HillshadeLayerTest.java | 2 +- .../testapp/style/LineLayerTest.java | 2 +- .../testapp/style/RasterLayerTest.java | 2 +- .../testapp/style/SymbolLayerTest.java | 2 +- .../mapboxsdk/testapp/style/layer.junit.ejs | 12 +- scripts/generate-style-code.js | 55 ++- 56 files changed, 476 insertions(+), 430 deletions(-) rename MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/{style/layers => location}/LocationIndicatorLayer.java (90%) create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationPropertyFactory.java rename MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/{testapp/style => location}/LocationIndicatorLayerTest.java (96%) diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp index d0084dc2d..99fb75cc0 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "background_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp index e402dc021..8958c929e 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/background_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp index 705bb9136..f51e2dae9 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "circle_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp index daa28571b..ee95656d6 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/circle_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp index 9b7c66a0a..0d1d107b1 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "fill_extrusion_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp index 6f0a24131..aa478e422 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_extrusion_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp index ba6ed2179..8b33c8077 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "fill_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp index 807b939a7..592d951f2 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/fill_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp index dfb8bbb4b..686e44c3a 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "heatmap_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp index f56e3eb4a..15b24b147 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/heatmap_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp index 3c72b503b..fa094f9ae 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "hillshade_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp index bc210a998..0c5d489ee 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/hillshade_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs index 79df91791..d72fbc2c9 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.cpp.ejs @@ -2,7 +2,7 @@ const type = locals.type; const properties = locals.properties; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "<%- type.replace('-', '_') %>_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs index 05fe925c8..771ffd664 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/layer.hpp.ejs @@ -2,7 +2,7 @@ const type = locals.type; const properties = locals.properties; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once @@ -18,7 +18,11 @@ namespace android { class <%- camelize(type) %>Layer : public Layer { public: using SuperTag = Layer; +<% if (type === 'location-indicator') { -%> + static constexpr auto Name() { return "com/mapbox/mapboxsdk/location/<%- camelize(type) %>Layer"; }; +<% } else { -%> static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; }; +<% } -%> <% if (type === 'background' || type === 'location-indicator') { -%> <%- camelize(type) %>Layer(jni::JNIEnv&, jni::String&); diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp index bf3a403b6..bc05c41a1 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "line_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp index 25b270fbc..1a53b9e32 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/line_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp index 7b2f36b4f..9e6429792 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "location_indicator_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp index 6b7621efd..81a20d793 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/location_indicator_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once @@ -14,7 +14,7 @@ namespace android { class LocationIndicatorLayer : public Layer { public: using SuperTag = Layer; - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer"; }; + static constexpr auto Name() { return "com/mapbox/mapboxsdk/location/LocationIndicatorLayer"; }; LocationIndicatorLayer(jni::JNIEnv&, jni::String&); diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp index 53442c0a9..759161aeb 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "raster_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp index bbda2e0c5..4c3d6b19c 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/raster_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp index 198dbe635..6abf5fd73 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.cpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include "symbol_layer.hpp" diff --git a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp index 4898c830d..f51cdb4e3 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/layers/symbol_layer.hpp @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #pragma once diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java index 6f4f0080d..d9ae215dd 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java @@ -8,8 +8,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; -import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.mapboxsdk.utils.ColorUtils; @@ -23,7 +21,6 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_IC import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba; import static com.mapbox.mapboxsdk.style.layers.Property.NONE; import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; class IndicatorLocationLayerRenderer implements LocationLayerRenderer { @@ -84,8 +81,8 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { colorArray[3] = accuracyAlpha; Expression rgbaExpression = rgba(colorArray[0], colorArray[1], colorArray[2], colorArray[3]); layer.setProperties( - PropertyFactory.accuracyRadiusColor(rgbaExpression), - PropertyFactory.accuracyRadiusBorderColor(rgbaExpression) + LocationPropertyFactory.accuracyRadiusColor(rgbaExpression), + LocationPropertyFactory.accuracyRadiusBorderColor(rgbaExpression) ); } @@ -107,16 +104,16 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { @Override public void setAccuracyRadius(Float accuracy) { layer.setProperties( - PropertyFactory.accuracyRadius(accuracy) + LocationPropertyFactory.accuracyRadius(accuracy) ); } @Override public void styleScaling(Expression scaleExpression) { layer.setProperties( - PropertyFactory.shadowImageSize(scaleExpression), - PropertyFactory.bearingImageSize(scaleExpression), - PropertyFactory.topImageSize(scaleExpression) + LocationPropertyFactory.shadowImageSize(scaleExpression), + LocationPropertyFactory.bearingImageSize(scaleExpression), + LocationPropertyFactory.topImageSize(scaleExpression) ); } @@ -160,7 +157,7 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { } private void setLayerVisibility(boolean visible) { - layer.setProperties(visibility(visible ? VISIBLE : NONE)); + layer.setProperties(LocationPropertyFactory.visibility(visible ? VISIBLE : NONE)); } private void setLayerLocation(@Nullable LatLng latLng) { @@ -168,14 +165,14 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { if (latLng != null) { Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; layer.setProperties( - PropertyFactory.location(values) + LocationPropertyFactory.location(values) ); } } private void setLayerBearing(double bearing) { layer.setProperties( - PropertyFactory.bearing(bearing) + LocationPropertyFactory.bearing(bearing) ); } @@ -203,9 +200,9 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { break; } layer.setProperties( - PropertyFactory.topImage(topImage), - PropertyFactory.bearingImage(bearingImage), - PropertyFactory.shadowImage(shadowImage) + LocationPropertyFactory.topImage(topImage), + LocationPropertyFactory.bearingImage(bearingImage), + LocationPropertyFactory.shadowImage(shadowImage) ); } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index 2d3e969ec..d33206f10 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -5,9 +5,7 @@ import androidx.annotation.NonNull; import com.mapbox.geojson.Feature; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; import com.mapbox.mapboxsdk.style.layers.Property; -import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; @@ -122,8 +120,8 @@ class LayerSourceProvider { LocationIndicatorLayer generateLocationComponentLayer() { LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); layer.setProperties( - PropertyFactory.perspectiveCompensation(0.9f), - PropertyFactory.imageTiltDisplacement(4f) + LocationPropertyFactory.perspectiveCompensation(0.9f), + LocationPropertyFactory.imageTiltDisplacement(4f) ); return layer; } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayer.java similarity index 90% rename from MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java rename to MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayer.java index eefd65924..9399c8fa3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LocationIndicatorLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayer.java @@ -1,6 +1,6 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -package com.mapbox.mapboxsdk.style.layers; +package com.mapbox.mapboxsdk.location; import androidx.annotation.ColorInt; import androidx.annotation.Keep; @@ -14,6 +14,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.PropertyValue; /** * @@ -21,7 +23,7 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions; * @see The online documentation */ @UiThread -public class LocationIndicatorLayer extends Layer { +class LocationIndicatorLayer extends Layer { /** * Creates a LocationIndicatorLayer. @@ -46,66 +48,6 @@ public class LocationIndicatorLayer extends Layer { @Keep protected native void initialize(String layerId); - /** - * Get the source id. - * - * @return id of the source - */ - @NonNull - public String getSourceId() { - checkThread(); - return nativeGetSourceId(); - } - - /** - * Get the source layer. - * - * @return sourceLayer the source layer to get - */ - @NonNull - public String getSourceLayer() { - checkThread(); - return nativeGetSourceLayer(); - } - - /** - * Set a single expression filter. - * - * @param filter the expression filter to set - */ - public void setFilter(@NonNull Expression filter) { - checkThread(); - nativeSetFilter(filter.toArray()); - } - - /** - * Set a single expression filter. - * - * @param filter the expression filter to set - * @return This - */ - @NonNull - public LocationIndicatorLayer withFilter(@NonNull Expression filter) { - setFilter(filter); - return this; - } - - /** - * Get a single expression filter. - * - * @return the expression filter to get - */ - @Nullable - public Expression getFilter() { - checkThread(); - JsonElement jsonElement = nativeGetFilter(); - if (jsonElement != null) { - return Expression.Converter.convert(jsonElement); - } else { - return null; - } - } - /** * Set a property or properties. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationPropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationPropertyFactory.java new file mode 100644 index 000000000..367c47091 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationPropertyFactory.java @@ -0,0 +1,312 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +package com.mapbox.mapboxsdk.location; + +import androidx.annotation.ColorInt; + +import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.types.Formatted; +import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; +import com.mapbox.mapboxsdk.style.layers.LayoutPropertyValue; +import com.mapbox.mapboxsdk.style.layers.PaintPropertyValue; +import com.mapbox.mapboxsdk.style.layers.Property; +import com.mapbox.mapboxsdk.style.layers.PropertyValue; + +/** + * Constructs paint/layout properties for Layers + * + * @see Layer style documentation + */ +class LocationPropertyFactory { + + /** + * Set the property visibility. + * + * @param value the visibility value + * @return property wrapper around visibility + */ + public static PropertyValue visibility(@Property.VISIBILITY String value) { + return new LayoutPropertyValue<>("visibility", value); + } + + /** + * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue perspectiveCompensation(Float value) { + return new PaintPropertyValue<>("perspective-compensation", value); + } + + /** + * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue perspectiveCompensation(Expression expression) { + return new PaintPropertyValue<>("perspective-compensation", expression); + } + + /** + * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue imageTiltDisplacement(Float value) { + return new PaintPropertyValue<>("image-tilt-displacement", value); + } + + /** + * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue imageTiltDisplacement(Expression expression) { + return new PaintPropertyValue<>("image-tilt-displacement", expression); + } + + /** + * The bearing of the location indicator. + * + * @param value a Double value + * @return property wrapper around Double + */ + public static PropertyValue bearing(Double value) { + return new PaintPropertyValue<>("bearing", value); + } + + /** + * The bearing of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue bearing(Expression expression) { + return new PaintPropertyValue<>("bearing", expression); + } + + /** + * An array of [latitude, longitude, altitude] position of the location indicator. + * + * @param value a Double[] value + * @return property wrapper around Double[] + */ + public static PropertyValue location(Double[] value) { + return new PaintPropertyValue<>("location", value); + } + + /** + * An array of [latitude, longitude, altitude] position of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue location(Expression expression) { + return new PaintPropertyValue<>("location", expression); + } + + /** + * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue accuracyRadius(Float value) { + return new PaintPropertyValue<>("accuracy-radius", value); + } + + /** + * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadius(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius", expression); + } + + /** + * The size of the top image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue topImageSize(Float value) { + return new PaintPropertyValue<>("top-image-size", value); + } + + /** + * The size of the top image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue topImageSize(Expression expression) { + return new PaintPropertyValue<>("top-image-size", expression); + } + + /** + * The size of the bearing image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue bearingImageSize(Float value) { + return new PaintPropertyValue<>("bearing-image-size", value); + } + + /** + * The size of the bearing image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue bearingImageSize(Expression expression) { + return new PaintPropertyValue<>("bearing-image-size", expression); + } + + /** + * The size of the shadow image, as a scale factor applied to the size of the specified image. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue shadowImageSize(Float value) { + return new PaintPropertyValue<>("shadow-image-size", value); + } + + /** + * The size of the shadow image, as a scale factor applied to the size of the specified image. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue shadowImageSize(Expression expression) { + return new PaintPropertyValue<>("shadow-image-size", expression); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a int color value + * @return property wrapper around String color + */ + public static PropertyValue accuracyRadiusColor(@ColorInt int value) { + return new PaintPropertyValue<>("accuracy-radius-color", colorToRgbaString(value)); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue accuracyRadiusColor(String value) { + return new PaintPropertyValue<>("accuracy-radius-color", value); + } + + /** + * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadiusColor(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius-color", expression); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a int color value + * @return property wrapper around String color + */ + public static PropertyValue accuracyRadiusBorderColor(@ColorInt int value) { + return new PaintPropertyValue<>("accuracy-radius-border-color", colorToRgbaString(value)); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue accuracyRadiusBorderColor(String value) { + return new PaintPropertyValue<>("accuracy-radius-border-color", value); + } + + /** + * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue accuracyRadiusBorderColor(Expression expression) { + return new PaintPropertyValue<>("accuracy-radius-border-color", expression); + } + + /** + * Name of image in sprite to use as the top of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue topImage(String value) { + return new LayoutPropertyValue<>("top-image", value); + } + + /** + * Name of image in sprite to use as the top of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue topImage(Expression value) { + return new LayoutPropertyValue<>("top-image", value); + } + + /** + * Name of image in sprite to use as the middle of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue bearingImage(String value) { + return new LayoutPropertyValue<>("bearing-image", value); + } + + /** + * Name of image in sprite to use as the middle of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue bearingImage(Expression value) { + return new LayoutPropertyValue<>("bearing-image", value); + } + + /** + * Name of image in sprite to use as the background of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue shadowImage(String value) { + return new LayoutPropertyValue<>("shadow-image", value); + } + + /** + * Name of image in sprite to use as the background of the location indicator. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue shadowImage(Expression value) { + return new LayoutPropertyValue<>("shadow-image", value); + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java index 3197b1a5b..6870e6537 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index d9845634c..2f2d8325f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java index 28d125565..841a4b35d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java index 98b5f8feb..38de5d56a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java index 5e5faed33..fce946ffe 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java index dae70ae36..0342a35cf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java index 5417e814e..630a4239a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.style.layers; import androidx.annotation.NonNull; -class LayoutPropertyValue extends PropertyValue { +public class LayoutPropertyValue extends PropertyValue { - LayoutPropertyValue(@NonNull String name, T value) { + public LayoutPropertyValue(@NonNull String name, T value) { super(name, value); } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java index cf1335269..00b07f792 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java index 394258834..bd5eaa81a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.style.layers; import androidx.annotation.NonNull; -class PaintPropertyValue extends PropertyValue { +public class PaintPropertyValue extends PropertyValue { - PaintPropertyValue(@NonNull String name, T value) { + public PaintPropertyValue(@NonNull String name, T value) { super(name, value); } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java index f2c0c7898..d5f1daa82 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 907867707..cb9aa5805 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; @@ -1645,226 +1645,6 @@ public class PropertyFactory { return new PaintPropertyValue<>("background-opacity", expression); } - /** - * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue perspectiveCompensation(Float value) { - return new PaintPropertyValue<>("perspective-compensation", value); - } - - /** - * The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location indicator of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue perspectiveCompensation(Expression expression) { - return new PaintPropertyValue<>("perspective-compensation", expression); - } - - /** - * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue imageTiltDisplacement(Float value) { - return new PaintPropertyValue<>("image-tilt-displacement", value); - } - - /** - * The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue imageTiltDisplacement(Expression expression) { - return new PaintPropertyValue<>("image-tilt-displacement", expression); - } - - /** - * The bearing of the location indicator. - * - * @param value a Double value - * @return property wrapper around Double - */ - public static PropertyValue bearing(Double value) { - return new PaintPropertyValue<>("bearing", value); - } - - /** - * The bearing of the location indicator. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue bearing(Expression expression) { - return new PaintPropertyValue<>("bearing", expression); - } - - /** - * An array of [latitude, longitude, altitude] position of the location indicator. - * - * @param value a Double[] value - * @return property wrapper around Double[] - */ - public static PropertyValue location(Double[] value) { - return new PaintPropertyValue<>("location", value); - } - - /** - * An array of [latitude, longitude, altitude] position of the location indicator. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue location(Expression expression) { - return new PaintPropertyValue<>("location", expression); - } - - /** - * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue accuracyRadius(Float value) { - return new PaintPropertyValue<>("accuracy-radius", value); - } - - /** - * The accuracy, in meters, of the position source used to retrieve the position of the location indicator. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue accuracyRadius(Expression expression) { - return new PaintPropertyValue<>("accuracy-radius", expression); - } - - /** - * The size of the top image, as a scale factor applied to the size of the specified image. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue topImageSize(Float value) { - return new PaintPropertyValue<>("top-image-size", value); - } - - /** - * The size of the top image, as a scale factor applied to the size of the specified image. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue topImageSize(Expression expression) { - return new PaintPropertyValue<>("top-image-size", expression); - } - - /** - * The size of the bearing image, as a scale factor applied to the size of the specified image. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue bearingImageSize(Float value) { - return new PaintPropertyValue<>("bearing-image-size", value); - } - - /** - * The size of the bearing image, as a scale factor applied to the size of the specified image. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue bearingImageSize(Expression expression) { - return new PaintPropertyValue<>("bearing-image-size", expression); - } - - /** - * The size of the shadow image, as a scale factor applied to the size of the specified image. - * - * @param value a Float value - * @return property wrapper around Float - */ - public static PropertyValue shadowImageSize(Float value) { - return new PaintPropertyValue<>("shadow-image-size", value); - } - - /** - * The size of the shadow image, as a scale factor applied to the size of the specified image. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue shadowImageSize(Expression expression) { - return new PaintPropertyValue<>("shadow-image-size", expression); - } - - /** - * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. - * - * @param value a int color value - * @return property wrapper around String color - */ - public static PropertyValue accuracyRadiusColor(@ColorInt int value) { - return new PaintPropertyValue<>("accuracy-radius-color", colorToRgbaString(value)); - } - - /** - * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue accuracyRadiusColor(String value) { - return new PaintPropertyValue<>("accuracy-radius-color", value); - } - - /** - * The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue accuracyRadiusColor(Expression expression) { - return new PaintPropertyValue<>("accuracy-radius-color", expression); - } - - /** - * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. - * - * @param value a int color value - * @return property wrapper around String color - */ - public static PropertyValue accuracyRadiusBorderColor(@ColorInt int value) { - return new PaintPropertyValue<>("accuracy-radius-border-color", colorToRgbaString(value)); - } - - /** - * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue accuracyRadiusBorderColor(String value) { - return new PaintPropertyValue<>("accuracy-radius-border-color", value); - } - - /** - * The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly. - * - * @param expression an expression statement - * @return property wrapper around an expression statement - */ - public static PropertyValue accuracyRadiusBorderColor(Expression expression) { - return new PaintPropertyValue<>("accuracy-radius-border-color", expression); - } - /** * Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key. * @@ -2835,64 +2615,4 @@ public class PropertyFactory { return new LayoutPropertyValue<>("circle-sort-key", value); } - /** - * Name of image in sprite to use as the top of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue topImage(String value) { - return new LayoutPropertyValue<>("top-image", value); - } - - /** - * Name of image in sprite to use as the top of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue topImage(Expression value) { - return new LayoutPropertyValue<>("top-image", value); - } - - /** - * Name of image in sprite to use as the middle of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue bearingImage(String value) { - return new LayoutPropertyValue<>("bearing-image", value); - } - - /** - * Name of image in sprite to use as the middle of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue bearingImage(Expression value) { - return new LayoutPropertyValue<>("bearing-image", value); - } - - /** - * Name of image in sprite to use as the background of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue shadowImage(String value) { - return new LayoutPropertyValue<>("shadow-image", value); - } - - /** - * Name of image in sprite to use as the background of the location indicator. - * - * @param value a String value - * @return property wrapper around String - */ - public static PropertyValue shadowImage(Expression value) { - return new LayoutPropertyValue<>("shadow-image", value); - } - } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java index 9c0c73327..82f1a0771 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java index 06d488d6e..1355458b7 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs index db1510aab..987316768 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs @@ -3,9 +3,13 @@ const properties = locals.properties; const doc = locals.doc; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. +<% if (type === 'location-indicator') { -%> +package com.mapbox.mapboxsdk.location; +<% } else { -%> package com.mapbox.mapboxsdk.style.layers; +<% } -%> import androidx.annotation.ColorInt; import androidx.annotation.Keep; @@ -23,6 +27,10 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions; import com.mapbox.mapboxsdk.style.types.Formatted; import com.mapbox.mapboxsdk.style.types.FormattedSection; <% } -%> +<% if (type === 'location-indicator') { -%> +import com.mapbox.mapboxsdk.style.layers.Layer; +import com.mapbox.mapboxsdk.style.layers.PropertyValue; +<% } -%> /** * <%- doc %> @@ -30,7 +38,11 @@ import com.mapbox.mapboxsdk.style.types.FormattedSection; * @see The online documentation */ @UiThread +<% if (type === 'location-indicator') { -%> +class <%- camelize(type) %>Layer extends Layer { +<% } else { -%> public class <%- camelize(type) %>Layer extends Layer { +<% } -%> /** * Creates a <%- camelize(type) %>Layer. @@ -94,7 +106,7 @@ public class <%- camelize(type) %>Layer extends Layer { } <% } -%> -<% if (type !== 'background' && type !== 'custom') { -%> +<% if (type !== 'background' && type !== 'location-indicator' && type !== 'custom') { -%> /** * Get the source id. * @@ -107,7 +119,7 @@ public class <%- camelize(type) %>Layer extends Layer { } <% } -%> -<% if (type !== 'background' && type !== 'raster' && type !== 'hillshade') { -%> +<% if (type !== 'background' && type !== 'location-indicator' && type !== 'raster' && type !== 'hillshade') { -%> /** * Get the source layer. * diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs index 7d859893b..06481fa4d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs @@ -1,7 +1,7 @@ <% const properties = locals.properties; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.layers; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs index 0a8d5c3b2..18bf39bcd 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs @@ -1,23 +1,38 @@ <% const paintProperties = locals.paintProperties; const layoutProperties = locals.layoutProperties; + const locationIndicator = locals.locationIndicator; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. +<% if (locationIndicator) { -%> +package com.mapbox.mapboxsdk.location; +<% } else { -%> package com.mapbox.mapboxsdk.style.layers; +<% } -%> import androidx.annotation.ColorInt; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.types.Formatted; import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; +<% if (locationIndicator) { -%> +import com.mapbox.mapboxsdk.style.layers.LayoutPropertyValue; +import com.mapbox.mapboxsdk.style.layers.PaintPropertyValue; +import com.mapbox.mapboxsdk.style.layers.Property; +import com.mapbox.mapboxsdk.style.layers.PropertyValue; +<% } -%> /** * Constructs paint/layout properties for Layers * * @see Layer style documentation */ +<% if (locationIndicator) { -%> +class LocationPropertyFactory { +<% } else { -%> public class PropertyFactory { +<% } -%> /** * Set the property visibility. diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java index 24105bb0c..75cd89128 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.light; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs index 30a021195..8074fa0df 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs @@ -2,7 +2,7 @@ const properties = locals.properties; const doc = locals.doc; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.style.light; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayerTest.java similarity index 96% rename from MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java rename to MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayerTest.java index 1a14d242f..1ecc78d5a 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LocationIndicatorLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationIndicatorLayerTest.java @@ -1,6 +1,6 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -package com.mapbox.mapboxsdk.testapp.style; +package com.mapbox.mapboxsdk.location; import android.graphics.Color; import androidx.test.annotation.UiThreadTest; @@ -11,7 +11,6 @@ import org.junit.Before; import timber.log.Timber; import com.mapbox.mapboxsdk.style.expressions.Expression; -import com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,7 +18,7 @@ import org.junit.runner.RunWith; import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; +import static com.mapbox.mapboxsdk.location.LocationPropertyFactory.*; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java index c6fe2d62d..e7226327c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java index 1430f304c..cba1bad81 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java index ecbae353c..4d57b38fa 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java index ef75a5e64..2e01ec4f2 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java index 79c244c45..0c8f7d25d 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java index 68943d19a..6e74654e9 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java index daeb41c1c..0a95b83f2 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java index 56cf1e845..cf16175ec 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java index 207d346f4..504bd39e5 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java @@ -1,4 +1,4 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. package com.mapbox.mapboxsdk.testapp.style; diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index c5515a396..46a46063c 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -2,9 +2,13 @@ const type = locals.type; const properties = locals.properties; -%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. +<% if (type === 'location-indicator') { -%> +package com.mapbox.mapboxsdk.location; +<% } else { -%> package com.mapbox.mapboxsdk.testapp.style; +<% } -%> import android.graphics.Color; import androidx.test.annotation.UiThreadTest; @@ -15,7 +19,9 @@ import org.junit.Before; import timber.log.Timber; import com.mapbox.mapboxsdk.style.expressions.Expression; +<% if (type !== 'location-indicator') { -%> import com.mapbox.mapboxsdk.style.layers.<%- camelize(type) %>Layer; +<% } -%> <% if (type === 'symbol') { -%> import com.mapbox.mapboxsdk.style.types.Formatted; import com.mapbox.mapboxsdk.style.types.FormattedSection; @@ -27,7 +33,11 @@ import org.junit.runner.RunWith; import static com.mapbox.mapboxsdk.style.expressions.Expression.*; import static org.junit.Assert.*; import static com.mapbox.mapboxsdk.style.layers.Property.*; +<% if (type === 'location-indicator') { -%> +import static com.mapbox.mapboxsdk.location.LocationPropertyFactory.*; +<% } else { -%> import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*; +<% } -%> import com.mapbox.mapboxsdk.style.layers.TransitionOptions; diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 821f03666..cab7bca0d 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -26,7 +26,7 @@ const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => { // Collect layer types from spec var layers = Object.keys(spec.layer.type.values).map((type) => { const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => { - if (name !== 'visibility') { + if (name !== 'visibility' && type !== 'location-indicator') { spec[`layout_${type}`][name].name = name; memo.push(spec[`layout_${type}`][name]); } @@ -34,8 +34,26 @@ var layers = Object.keys(spec.layer.type.values).map((type) => { }, []); const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => { - spec[`paint_${type}`][name].name = name; - memo.push(spec[`paint_${type}`][name]); + if (type !== 'location-indicator') { + spec[`paint_${type}`][name].name = name; + memo.push(spec[`paint_${type}`][name]); + } + return memo; + }, []); + + const locationLayoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => { + if (name !== 'visibility' && type === 'location-indicator') { + spec[`layout_${type}`][name].name = name; + memo.push(spec[`layout_${type}`][name]); + } + return memo; + }, []); + + const locationPaintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => { + if (type === 'location-indicator') { + spec[`paint_${type}`][name].name = name; + memo.push(spec[`paint_${type}`][name]); + } return memo; }, []); @@ -44,7 +62,9 @@ var layers = Object.keys(spec.layer.type.values).map((type) => { doc: spec.layer.type.values[type].doc, layoutProperties: layoutProperties, paintProperties: paintProperties, - properties: layoutProperties.concat(paintProperties) + locationLayoutProperties: locationLayoutProperties, + locationPaintProperties: locationPaintProperties, + properties: layoutProperties.concat(paintProperties).concat(locationLayoutProperties).concat(locationPaintProperties) }; }); @@ -57,6 +77,8 @@ const uniqueArrayEnum = (prop, enums) => { const layoutProperties = _(layers).map('layoutProperties').flatten().value(); const paintProperties = _(layers).map('paintProperties').flatten().value(); +const locationLayoutProperties = _(layers).map('locationLayoutProperties').flatten().value(); +const locationPaintProperties = _(layers).map('locationPaintProperties').flatten().value(); const allProperties = _(layoutProperties).union(paintProperties).union(lightProperties).value(); let allEnumProperties = _(allProperties).filter({'type': 'enum'}).value(); const uniqueArrayEnumProperties = _(allProperties).filter({'type': 'array'}).filter(prop => uniqueArrayEnum(prop, allEnumProperties)).value(); @@ -391,8 +413,15 @@ const layerJava = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/ const layerJavaUnitTests = ejs.compile(fs.readFileSync('MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs', 'utf8'), {strict: true}); for (const layer of layers) { - writeIfModified(`MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer)); - writeIfModified(`MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); + var srcDir = 'MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/' + var testDir = 'MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/' + if (layer.type === 'location-indicator') { + srcDir = 'MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/' + testDir = 'MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/' + } + + writeIfModified(srcDir + `${camelize(layer.type)}Layer.java`, layerJava(layer)); + writeIfModified(testDir + `${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer)); } // Jni @@ -407,10 +436,18 @@ for (const layer of layers) { } // Java PropertyFactory -const propertiesTemplate = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); +const propertyFactoryTemplate = ejs.compile(fs.readFileSync('MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true}); + +var propertyFactorySrcDir = 'MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java' writeIfModified( - `MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java`, - propertiesTemplate({layoutProperties: layoutProperties, paintProperties: paintProperties}) + propertyFactorySrcDir, + propertyFactoryTemplate({layoutProperties: layoutProperties, paintProperties: paintProperties, locationIndicator: false}) +); + +var locationPropertyFactorySrcDir = 'MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationPropertyFactory.java' +writeIfModified( + locationPropertyFactorySrcDir, + propertyFactoryTemplate({layoutProperties: locationLayoutProperties, paintProperties: locationPaintProperties, locationIndicator: true}) ); // Java Property From 7364dd028204dab28f768575b3267344878eb147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 14 Apr 2020 16:32:53 +0200 Subject: [PATCH 126/185] LocationIndicatorLayer tests --- .../IndicatorLocationLayerRenderer.java | 35 +- .../location/LayerSourceProvider.java | 11 +- .../mapboxsdk/location/LocationComponent.java | 6 +- .../LocationComponentActivationOptions.java | 8 +- .../location/LocationLayerController.java | 8 +- .../location/SymbolLocationLayerRenderer.java | 4 +- .../mapboxsdk/style/layers/PropertyValue.java | 33 ++ .../IndicatorLocationLayerRendererTest.kt | 327 ++++++++++++++++++ .../location/LocationComponentTest.kt | 45 ++- .../location/LocationLayerControllerTest.java | 39 ++- gradle/gradle-checkstyle.gradle | 3 + 11 files changed, 484 insertions(+), 35 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java index d9ae215dd..5cb1f37df 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java @@ -8,6 +8,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.mapboxsdk.utils.ColorUtils; @@ -26,26 +27,30 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { private Style style; private final LayerSourceProvider layerSourceProvider; - private LocationIndicatorLayer layer; + private Layer layer; @Nullable - private LatLng latLng; + private LatLng lastLatLng; + private double lastBearing = 0; + private float lastAccuracy = 0; - IndicatorLocationLayerRenderer(Style style, - LayerSourceProvider layerSourceProvider) { - this.style = style; + IndicatorLocationLayerRenderer(LayerSourceProvider layerSourceProvider) { this.layerSourceProvider = layerSourceProvider; } @Override public void initializeComponents(Style style) { this.style = style; + layer = layerSourceProvider.generateLocationComponentLayer(); + if (lastLatLng != null) { + setLatLng(lastLatLng); + } + setLayerBearing(lastBearing); + setAccuracyRadius(lastAccuracy); } @Override public void addLayers(LocationComponentPositionManager positionManager) { - layer = layerSourceProvider.generateLocationComponentLayer(); - setLayerLocation(latLng); positionManager.addLayerToMap(layer); } @@ -106,6 +111,7 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { layer.setProperties( LocationPropertyFactory.accuracyRadius(accuracy) ); + lastAccuracy = accuracy; } @Override @@ -160,20 +166,19 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { layer.setProperties(LocationPropertyFactory.visibility(visible ? VISIBLE : NONE)); } - private void setLayerLocation(@Nullable LatLng latLng) { - this.latLng = latLng; - if (latLng != null) { - Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; - layer.setProperties( - LocationPropertyFactory.location(values) - ); - } + private void setLayerLocation(LatLng latLng) { + Double[] values = new Double[] {latLng.getLatitude(), latLng.getLongitude(), 0d}; + layer.setProperties( + LocationPropertyFactory.location(values) + ); + lastLatLng = latLng; } private void setLayerBearing(double bearing) { layer.setProperties( LocationPropertyFactory.bearing(bearing) ); + lastBearing = bearing; } private void setImages(@RenderMode.Mode int renderMode, boolean isStale) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index d33206f10..3626f42db 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -117,7 +117,16 @@ class LayerSourceProvider { return new HashSet<>(); } - LocationIndicatorLayer generateLocationComponentLayer() { + LocationLayerRenderer getSymbolLocationLayerRenderer(LayerFeatureProvider featureProvider, + boolean isStale) { + return new SymbolLocationLayerRenderer(this, featureProvider, isStale); + } + + LocationLayerRenderer getIndicatorLocationLayerRenderer() { + return new IndicatorLocationLayerRenderer(this); + } + + Layer generateLocationComponentLayer() { LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); layer.setProperties( LocationPropertyFactory.perspectiveCompensation(0.9f), diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 733dbb259..bbb60289d 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -141,7 +141,7 @@ public final class LocationComponent { private boolean isComponentInitialized; /** - * Indicates whether we're using the {@link com.mapbox.mapboxsdk.style.layers.LocationIndicatorLayer} + * Indicates whether we're using the {@link com.mapbox.mapboxsdk.location.LocationIndicatorLayer} * or the stack of {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer}s. */ private boolean useSpecializedLocationLayer; @@ -217,7 +217,8 @@ public final class LocationComponent { @NonNull LocationAnimatorCoordinator locationAnimatorCoordinator, @NonNull StaleStateManager staleStateManager, @NonNull CompassEngine compassEngine, - @NonNull InternalLocationEngineProvider internalLocationEngineProvider) { + @NonNull InternalLocationEngineProvider internalLocationEngineProvider, + boolean useSpecializedLocationLayer) { this.mapboxMap = mapboxMap; this.transform = transform; developerAnimationListeners.add(developerAnimationListener); @@ -229,6 +230,7 @@ public final class LocationComponent { this.staleStateManager = staleStateManager; this.compassEngine = compassEngine; this.internalLocationEngineProvider = internalLocationEngineProvider; + this.useSpecializedLocationLayer = useSpecializedLocationLayer; isComponentInitialized = true; } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java index 91f6141dd..bc295e920 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -123,14 +123,14 @@ public class LocationComponentActivationOptions { /** * True if you want to initialize and use the specialized location layer to render the location puck. *

    - * The specialized layer comes with significant performance improvements, + * The specialized layer is not based on runtime styling. This brings significant performance improvements, * but since it's not based on the runtime styling, * it's not fully compatible with the traditional implementation. The incompatibilities are: *

      *
    • Constants like {@link LocationComponentConstants#FOREGROUND_LAYER} * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. *
    • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. - * Use {@link LocationComponentOptions#foregroundDrawable()} instead. + * Use {@link LocationComponentOptions#foregroundDrawable()} to alter the image rendered as the puck. *
    * * @return whether the default specialized location layer is used @@ -236,14 +236,14 @@ public class LocationComponentActivationOptions { /** * True if you want to initialize and use the specialized location layer to render the location puck. *

    - * The specialized layer comes with significant performance improvements, + * The specialized layer is not based on runtime styling. This brings significant performance improvements, * but since it's not based on the runtime styling, * it's not fully compatible with the traditional implementation. The incompatibilities are: *

      *
    • Constants like {@link LocationComponentConstants#FOREGROUND_LAYER} * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. *
    • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. - * Use {@link LocationComponentOptions#foregroundDrawable()} instead. + * Use {@link LocationComponentOptions#foregroundDrawable()} to alter the image rendered as the puck. *
    * * @param useSpecializedLocationLayer true if you want to initialize and use the diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index 556254297..656191ddb 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -39,7 +39,6 @@ final class LocationLayerController { private int renderMode; private final MapboxMap mapboxMap; - private Style style; private final LayerBitmapProvider bitmapProvider; private LocationComponentOptions options; private final OnRenderModeChangedListener internalRenderModeChangedListener; @@ -60,21 +59,20 @@ final class LocationLayerController { @NonNull OnRenderModeChangedListener internalRenderModeChangedListener, boolean useSpecializedLocationLayer) { this.mapboxMap = mapboxMap; - this.style = style; this.bitmapProvider = bitmapProvider; this.internalRenderModeChangedListener = internalRenderModeChangedListener; this.useSpecializedLocationLayer = useSpecializedLocationLayer; this.isStale = options.enableStaleState(); if (useSpecializedLocationLayer) { - locationLayerRenderer = new IndicatorLocationLayerRenderer(style, layerSourceProvider); + locationLayerRenderer = layerSourceProvider.getIndicatorLocationLayerRenderer(); } else { - locationLayerRenderer = new SymbolLocationLayerRenderer(style, layerSourceProvider, featureProvider, isStale); + locationLayerRenderer = + layerSourceProvider.getSymbolLocationLayerRenderer(featureProvider, isStale); } initializeComponents(style, options); } void initializeComponents(Style style, LocationComponentOptions options) { - this.style = style; this.positionManager = new LocationComponentPositionManager(style, options.layerAbove(), options.layerBelow()); locationLayerRenderer.initializeComponents(style); locationLayerRenderer.addLayers(positionManager); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java index 7ad336313..ae722b3d2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java @@ -58,11 +58,9 @@ final class SymbolLocationLayerRenderer implements LocationLayerRenderer { private Feature locationFeature; private GeoJsonSource locationSource; - SymbolLocationLayerRenderer(Style style, - LayerSourceProvider layerSourceProvider, + SymbolLocationLayerRenderer(LayerSourceProvider layerSourceProvider, LayerFeatureProvider featureProvider, boolean isStale) { - this.style = style; this.layerSourceProvider = layerSourceProvider; this.layerSet = layerSourceProvider.getEmptyLayerSet(); this.locationFeature = featureProvider.generateLocationFeature(locationFeature, isStale); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java index 735ba3d70..871ac36f9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java @@ -10,6 +10,8 @@ import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.utils.ColorUtils; +import java.util.Arrays; + /** * Properties for Layer */ @@ -124,4 +126,35 @@ public class PropertyValue { public String toString() { return String.format("%s: %s", name, value); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PropertyValue that = (PropertyValue) o; + + if (!name.equals(that.name)) { + return false; + } + if (value != null) { + if (value instanceof Object[]) { + return Arrays.deepEquals((Object[]) value, (Object[]) that.value); + } + return value.equals(that.value); + } else { + return that.value == null; + } + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt new file mode 100644 index 000000000..0d485952b --- /dev/null +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRendererTest.kt @@ -0,0 +1,327 @@ +package com.mapbox.mapboxsdk.location + +import android.graphics.Bitmap +import android.graphics.Color +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.location.LocationComponentConstants.* +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.style.expressions.Expression +import com.mapbox.mapboxsdk.style.layers.Layer +import com.mapbox.mapboxsdk.style.layers.Property +import com.mapbox.mapboxsdk.utils.BitmapUtils +import com.mapbox.mapboxsdk.utils.ColorUtils +import io.mockk.* +import org.junit.Assert +import org.junit.Before +import org.junit.Test + +class IndicatorLocationLayerRendererTest { + + private val style: Style = mockk(relaxUnitFun = true) + private val layerSourceProvider: LayerSourceProvider = mockk(relaxUnitFun = true) + private val layer: Layer = mockk(relaxUnitFun = true) + + private lateinit var locationLayerRenderer: IndicatorLocationLayerRenderer + + @Before + fun setup() { + every { style.removeLayer(any()) } returns true + locationLayerRenderer = IndicatorLocationLayerRenderer(layerSourceProvider) + every { layerSourceProvider.generateLocationComponentLayer() } returns layer + locationLayerRenderer.initializeComponents(style) + } + + @Test + fun sanity() { + Assert.assertNotNull(locationLayerRenderer) + } + + @Test + fun initializeComponents_withLocation() { + val newLayer: Layer = mockk(relaxUnitFun = true) + every { layerSourceProvider.generateLocationComponentLayer() } returns newLayer + val latLng = LatLng(10.0, 20.0) + val bearing = 11f + val accuracy = 65f + locationLayerRenderer.setLatLng(latLng) + locationLayerRenderer.setGpsBearing(bearing) + locationLayerRenderer.setAccuracyRadius(accuracy) + + locationLayerRenderer.initializeComponents(mockk()) + + verify { newLayer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) } + verify { newLayer.setProperties(LocationPropertyFactory.bearing(bearing.toDouble())) } + verify { newLayer.setProperties(LocationPropertyFactory.accuracyRadius(accuracy)) } + } + + @Test + fun addLayers() { + val positionManager: LocationComponentPositionManager = mockk(relaxUnitFun = true) + + locationLayerRenderer.addLayers(positionManager) + + verify { positionManager.addLayerToMap(layer) } + } + + @Test + fun removeLayers() { + locationLayerRenderer.removeLayers() + + verify { style.removeLayer(layer) } + } + + @Test + fun hide() { + locationLayerRenderer.hide() + + verify { layer.setProperties(LocationPropertyFactory.visibility(Property.NONE)) } + } + + @Test + fun show() { + locationLayerRenderer.show(RenderMode.NORMAL, false) + + verify { layer.setProperties(LocationPropertyFactory.visibility(Property.VISIBLE)) } + } + + @Test + fun show_normal_notStale() { + locationLayerRenderer.show(RenderMode.NORMAL, false) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_ICON), + LocationPropertyFactory.bearingImage(BACKGROUND_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_compass_notStale() { + locationLayerRenderer.show(RenderMode.COMPASS, false) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_ICON), + LocationPropertyFactory.bearingImage(BEARING_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_gps_notStale() { + locationLayerRenderer.show(RenderMode.GPS, false) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(""), + LocationPropertyFactory.bearingImage(FOREGROUND_ICON), + LocationPropertyFactory.shadowImage("") + ) + } + verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) } + } + + @Test + fun show_normal_stale() { + locationLayerRenderer.show(RenderMode.NORMAL, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_compass_stale() { + locationLayerRenderer.show(RenderMode.COMPASS, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.bearingImage(BEARING_STALE_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun show_gps_stale() { + locationLayerRenderer.show(RenderMode.GPS, true) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(""), + LocationPropertyFactory.bearingImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.shadowImage("") + ) + } + verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(0f)) } + } + + @Test + fun styleAccuracy() { + val colorArray = ColorUtils.colorToRgbaArray(Color.RED) + val exp = Expression.rgba(colorArray[0], colorArray[1], colorArray[2], 0.7f) + + locationLayerRenderer.styleAccuracy(0.7f, Color.RED) + + verify { + layer.setProperties( + LocationPropertyFactory.accuracyRadiusColor(exp), + LocationPropertyFactory.accuracyRadiusBorderColor(exp) + ) + } + } + + @Test + fun setLatLng() { + val latLng = LatLng(10.0, 20.0) + locationLayerRenderer.setLatLng(latLng) + + verify { layer.setProperties(LocationPropertyFactory.location(latLng.toLocationArray())) } + } + + @Test + fun setGpsBearing() { + val bearing = 30.0 + locationLayerRenderer.setGpsBearing(bearing.toFloat()) + + verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) } + } + + @Test + fun setCompassBearing() { + val bearing = 30.0 + locationLayerRenderer.setCompassBearing(bearing.toFloat()) + + verify { layer.setProperties(LocationPropertyFactory.bearing(bearing)) } + } + + @Test + fun setAccuracyRadius() { + val radius = 40f + locationLayerRenderer.setAccuracyRadius(radius) + + verify { layer.setProperties(LocationPropertyFactory.accuracyRadius(radius)) } + } + + @Test + fun styleScaling() { + val exp = Expression.literal("") + locationLayerRenderer.styleScaling(exp) + + verify { + layer.setProperties( + LocationPropertyFactory.shadowImageSize(exp), + LocationPropertyFactory.bearingImageSize(exp), + LocationPropertyFactory.topImageSize(exp) + ) + } + } + + @Test + fun setLocationStale() { + locationLayerRenderer.setLocationStale(true, RenderMode.NORMAL) + + verify { + layer.setProperties( + LocationPropertyFactory.topImage(FOREGROUND_STALE_ICON), + LocationPropertyFactory.bearingImage(BACKGROUND_STALE_ICON), + LocationPropertyFactory.shadowImage(SHADOW_ICON) + ) + } + } + + @Test + fun addBitmaps_shadow() { + addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL) + + verify { style.addImage(SHADOW_ICON, shadowBitmap) } + } + + @Test + fun addBitmaps_noShadow() { + addBitmaps(withShadow = false, renderMode = RenderMode.NORMAL) + + verify { style.removeImage(SHADOW_ICON) } + } + + @Test + fun addBitmaps_normal() { + addBitmaps(withShadow = true, renderMode = RenderMode.NORMAL) + + verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) } + verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) } + verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) } + verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) } + verify { style.addImage(BEARING_ICON, bearingBitmap) } + } + + @Test + fun addBitmaps_compass() { + every { bearingBitmap.width } returns 40 + every { bearingBitmap.height } returns 40 + every { bearingBitmap.config } returns mockk() + every { backgroundBitmap.width } returns 20 + every { backgroundBitmap.height } returns 10 + + val mergedBitmap = mockk() + mockkStatic(BitmapUtils::class) + every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundBitmap, 10f, 15f) } returns mergedBitmap + + every { bearingBitmap.width } returns 40 + every { bearingBitmap.height } returns 40 + every { bearingBitmap.config } returns mockk() + every { backgroundStaleBitmap.width } returns 30 + every { backgroundStaleBitmap.height } returns 10 + + val mergedStaleBitmap = mockk() + every { BitmapUtils.mergeBitmap(bearingBitmap, backgroundStaleBitmap, 5f, 15f) } returns mergedStaleBitmap + + addBitmaps(withShadow = true, renderMode = RenderMode.COMPASS) + + verify { style.addImage(BEARING_ICON, mergedBitmap) } + verify { style.addImage(BEARING_STALE_ICON, mergedStaleBitmap) } + + unmockkStatic(BitmapUtils::class) + } + + @Test + fun addBitmaps_gps() { + addBitmaps(withShadow = true, renderMode = RenderMode.GPS) + + verify { style.addImage(FOREGROUND_ICON, foregroundBitmap) } + verify { style.addImage(FOREGROUND_STALE_ICON, foregroundStaleBitmap) } + verify { style.addImage(BACKGROUND_ICON, backgroundBitmap) } + verify { style.addImage(BACKGROUND_STALE_ICON, backgroundStaleBitmap) } + verify { style.addImage(BEARING_ICON, bearingBitmap) } + } + + private val shadowBitmap = mockk() + private val backgroundBitmap = mockk() + private val backgroundStaleBitmap = mockk() + private val bearingBitmap = mockk() + private val foregroundBitmap = mockk() + private val foregroundStaleBitmap = mockk() + + private fun addBitmaps(withShadow: Boolean, @RenderMode.Mode renderMode: Int) { + locationLayerRenderer.addBitmaps( + renderMode, + if (withShadow) shadowBitmap else null, + backgroundBitmap, + backgroundStaleBitmap, + bearingBitmap, + foregroundBitmap, + foregroundStaleBitmap + ) + } + + private fun LatLng.toLocationArray() = arrayOf(latitude, longitude, 0.0) +} \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index 4a2839361..33a067f59 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -13,6 +13,7 @@ import com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMA import com.mapbox.mapboxsdk.location.modes.CameraMode import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Projection import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.maps.Transform import org.junit.Assert @@ -80,7 +81,7 @@ class LocationComponentTest { fun before() { MockitoAnnotations.initMocks(this) developerAnimationListeners = mutableListOf() - locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider) + locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, false) doReturn(locationEngine).`when`(locationEngineProvider).getBestLocationEngine(context, false) doReturn(style).`when`(mapboxMap).style } @@ -587,4 +588,46 @@ class LocationComponentTest { verify(callback, times(0)).onCancel() verify(locationAnimatorCoordinator).feedNewZoomLevel(14.0, CameraPosition.DEFAULT, 500L, callback) } + + @Test + fun newLocation_accuracy_symbolLayerRadiusValue() { + val location = Location("test") + location.accuracy = 50f + val projection: Projection = mock(Projection::class.java) + `when`(projection.getMetersPerPixelAtLatitude(location.latitude)).thenReturn(10.0) + `when`(mapboxMap.projection).thenReturn(projection) + `when`(style.isFullyLoaded).thenReturn(true) + locationComponent.activateLocationComponent( + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(false) + .build() + ) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + locationComponent.forceLocationUpdate(location) + + val radius = (location.accuracy * (1 / 10.0)).toFloat() + verify(locationAnimatorCoordinator).feedNewAccuracyRadius(radius, false) + } + + @Test + fun newLocation_accuracy_indicatorLayerRadiusValue() { + val location = Location("test") + location.accuracy = 50f + `when`(style.isFullyLoaded).thenReturn(true) + locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, true) + locationComponent.activateLocationComponent( + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useSpecializedLocationLayer(true) + .useDefaultLocationEngine(false) + .build() + ) + locationComponent.isLocationComponentEnabled = true + locationComponent.onStart() + locationComponent.forceLocationUpdate(location) + + verify(locationAnimatorCoordinator).feedNewAccuracyRadius(location.accuracy, false) + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index c41732bc9..40726acbe 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; + import androidx.annotation.NonNull; import com.google.gson.JsonElement; @@ -15,6 +16,8 @@ import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.util.HashSet; import java.util.Set; @@ -43,6 +46,8 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -53,6 +58,7 @@ public class LocationLayerControllerTest { private MapboxMap mapboxMap = mock(MapboxMap.class); private Style style = mock(Style.class); + private LocationLayerRenderer indicatorRenderer = mock(LocationLayerRenderer.class); @Before public void before() { @@ -316,6 +322,20 @@ public class LocationLayerControllerTest { verify(style).addImage(BEARING_ICON, bitmap); } + @Test + public void applyStyle_specializedLayer_ignoreBitmapNames() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.foregroundName()).thenReturn("new_name"); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener, true); + + verify(indicatorRenderer).updateIconIds(eq(FOREGROUND_ICON), anyString(), anyString(), anyString(), anyString()); + } + @Test public void applyStyle_layerBelowChanged() { OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); @@ -599,7 +619,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.NORMAL); controller.setRenderMode(RenderMode.NORMAL); @@ -618,7 +638,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); controller.setRenderMode(RenderMode.GPS); controller.setRenderMode(RenderMode.GPS); @@ -642,7 +662,7 @@ public class LocationLayerControllerTest { LocationLayerController controller = new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), - bitmapProvider, options, internalRenderModeChangedListener, false); + bitmapProvider, options, internalRenderModeChangedListener, false); verify(style).addImage(FOREGROUND_ICON, bitmap); @@ -674,7 +694,18 @@ public class LocationLayerControllerTest { } private LayerSourceProvider buildLayerProvider() { - LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); + final LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); + when(layerSourceProvider.getIndicatorLocationLayerRenderer()).thenReturn(indicatorRenderer); + when(layerSourceProvider.getSymbolLocationLayerRenderer(any(LayerFeatureProvider.class), anyBoolean())).thenAnswer( + new Answer() { + @Override + public LocationLayerRenderer answer(InvocationOnMock invocation) { + LayerFeatureProvider featureProvider = invocation.getArgument(0); + boolean isStale = invocation.getArgument(1); + return new SymbolLocationLayerRenderer(layerSourceProvider, featureProvider, isStale); + } + } + ); Layer shadowLayer = mock(Layer.class); when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); diff --git a/gradle/gradle-checkstyle.gradle b/gradle/gradle-checkstyle.gradle index 8eb4baa85..3e36e7746 100644 --- a/gradle/gradle-checkstyle.gradle +++ b/gradle/gradle-checkstyle.gradle @@ -21,6 +21,9 @@ task checkstyle(type: Checkstyle) { exclude '**/log/LoggerDefinition.java' exclude '**/log/Logger.java' exclude '**/Expression.java' + exclude '**/location/LocationPropertyFactory.java' + exclude '**/location/LocationIndicatorLayer.java' + exclude '**/location/LocationIndicatorLayerTest.java' classpath = files() ignoreFailures = false } From 1c88a2261fadfeb7da845c38f5bb6fa8072f0a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 20 Apr 2020 18:15:46 +0200 Subject: [PATCH 127/185] bump gl-native to 1.6.0-rc.1 --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 3d2e20810..71ce52d35 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 3d2e20810cb9a4e2f351774889fd04b87814694c +Subproject commit 71ce52d35f8421c89f6112b83061613937b2836c From e491d3c9ec27e8eb34ba7595456d1e2a02fa0b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 20 Apr 2020 18:16:59 +0200 Subject: [PATCH 128/185] update license file --- LICENSE.md | 56 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 8423a34a6..dab65c9b0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -44,115 +44,115 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens Mapbox GL uses portions of the Android Support Library Annotations. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Async Layout Inflater. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library collections. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library compat. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Coordinator Layout. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library core UI. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library core utils. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Cursor Adapter. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Custom View. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Custom View. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Document File. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Drawer Layout. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library fragment. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Interpolators. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library loader. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Local Broadcast Manager. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Print. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library Sliding Pane Layout. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== Mapbox GL uses portions of the Android Support Library View Pager. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== @@ -169,7 +169,7 @@ License: [Mapbox Terms of Service](https://www.mapbox.com/tos/) Mapbox GL uses portions of the Mapbox Android Core Library. URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The MIT License](https://opensource.org/licenses/MIT) =========================================================================== @@ -181,7 +181,7 @@ License: [BSD](https://opensource.org/licenses/BSD-2-Clause) Mapbox GL uses portions of the Mapbox Android Telemetry Library. URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The MIT License](https://opensource.org/licenses/MIT) =========================================================================== @@ -213,9 +213,21 @@ License: [Apache-2](https://github.com/facebook/soloader/blob/master/LICENSE) =========================================================================== +Mapbox GL uses portions of the SoLoader. +URL: [https://github.com/facebook/soloader](https://github.com/facebook/soloader) +License: [Apache-2](https://github.com/facebook/soloader/blob/master/LICENSE) + +=========================================================================== + +Mapbox GL uses portions of the SoLoader. +URL: [https://github.com/facebook/soloader](https://github.com/facebook/soloader) +License: [Apache-2](https://github.com/facebook/soloader/blob/master/LICENSE) + +=========================================================================== + Mapbox GL uses portions of the VersionedParcelable and friends. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== From 6f73982d95f272e4023dc84ca4182dc6ee3648e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 21 Apr 2020 11:46:18 +0200 Subject: [PATCH 129/185] disable LocationIndicatorLayer's location transitions --- .../java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index 3626f42db..053fdb24f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -7,6 +7,7 @@ import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.layers.TransitionOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; @@ -128,6 +129,7 @@ class LayerSourceProvider { Layer generateLocationComponentLayer() { LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); + layer.setLocationTransition(new TransitionOptions(0, 0)); layer.setProperties( LocationPropertyFactory.perspectiveCompensation(0.9f), LocationPropertyFactory.imageTiltDisplacement(4f) From bb1132a4d38023ab7fd640924464b5e90b4bcc20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 21 Apr 2020 14:07:57 +0200 Subject: [PATCH 130/185] make sure to hard-cancel all ignored location animators --- .../location/LocationAnimatorCoordinator.java | 16 ++++++++ .../mapboxsdk/location/MapboxAnimator.java | 15 ++++++- .../LocationAnimatorCoordinatorTest.kt | 39 +++++++++++++++++-- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 474e524d1..50b2d6384 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -74,6 +74,16 @@ final class LocationAnimatorCoordinator { for (AnimatorListenerHolder holder : listenerHolders) { listeners.append(holder.getAnimatorType(), holder.getListener()); } + + for (int i = 0; i < animatorArray.size(); i++) { + @MapboxAnimator.Type int animatorType = animatorArray.keyAt(i); + if (listeners.get(animatorType) == null) { + MapboxAnimator animator = animatorArray.get(animatorType); + if (animator != null) { + animator.makeInvalid(); + } + } + } } void feedNewLocation(@NonNull Location newLocation, @NonNull CameraPosition currentCameraPosition, @@ -397,6 +407,8 @@ final class LocationAnimatorCoordinator { MapboxFloatAnimator gpsBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_GPS_BEARING); MapboxFloatAnimator compassBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING); + MapboxFloatAnimator accuracyAnimator = + (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_ACCURACY); if (latLngAnimator != null && gpsBearingAnimator != null) { LatLng currentLatLng = (LatLng) latLngAnimator.getAnimatedValue(); @@ -420,6 +432,10 @@ final class LocationAnimatorCoordinator { compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0, ANIMATOR_LAYER_COMPASS_BEARING); } + + if (accuracyAnimator != null) { + feedNewAccuracyRadius(previousAccuracyRadius, false); + } } void cancelZoomAnimation() { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index f9a213241..694594fa6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -50,6 +50,13 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. private final double minUpdateInterval; private long timeElapsed; + /** + * Makes this animator invalid and prevents it from pushing any more updates to the listener. + * + * This can be used to prevent propagating final updates when the animator should be immediately canceled. + */ + private boolean invalid; + MapboxAnimator(@NonNull @Size(min = 2) K[] values, @NonNull AnimationsValueChangeListener updateListener, int maxAnimationFps) { minUpdateInterval = 1E9 / maxAnimationFps; @@ -82,7 +89,9 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. } private void postUpdates() { - updateListener.onNewAnimationValue(animatedValue); + if (!invalid) { + updateListener.onNewAnimationValue(animatedValue); + } } K getTarget() { @@ -94,4 +103,8 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. interface AnimationsValueChangeListener { void onNewAnimationValue(K value); } + + public void makeInvalid() { + invalid = true; + } } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt index bd741e5b9..7c4feb83b 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location import android.animation.Animator +import android.animation.ValueAnimator import android.location.Location import android.util.SparseArray import android.view.animation.LinearInterpolator @@ -9,7 +10,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION import com.mapbox.mapboxsdk.location.MapboxAnimator.* -import com.mapbox.mapboxsdk.location.modes.CameraMode import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Projection @@ -517,16 +517,16 @@ class LocationAnimatorCoordinatorTest { @Test fun updateListeners() { val listener = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder = AnimatorListenerHolder(RenderMode.NORMAL, listener) + val holder = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener) val set = HashSet().also { it.add(holder) } locationAnimatorCoordinator.updateAnimatorListenerHolders(set) val listener2 = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder2 = AnimatorListenerHolder(RenderMode.NORMAL, listener2) + val holder2 = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener2) val listener3 = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder3 = AnimatorListenerHolder(CameraMode.TRACKING_GPS, listener3) + val holder3 = AnimatorListenerHolder(ANIMATOR_LAYER_ACCURACY, listener3) val set2 = HashSet().also { it.add(holder2) it.add(holder3) @@ -538,6 +538,37 @@ class LocationAnimatorCoordinatorTest { assertTrue(locationAnimatorCoordinator.listeners.contains(listener3)) } + @Test + fun updateListeners_listenerRemoved_animtorInvalid() { + // setup accuracy animator + val listener: AnimationsValueChangeListener = mockk(relaxUnitFun = true) + val holder = AnimatorListenerHolder(ANIMATOR_LAYER_ACCURACY, listener) + val set = HashSet().also { + it.add(holder) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set) + locationAnimatorCoordinator.feedNewAccuracyRadius(500f, true) + + // reset animator listeners which should make the previously created animator invalid + val listener2: AnimationsValueChangeListener<*> = mockk() + val holder2 = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener2) + val listener3: AnimationsValueChangeListener<*> = mockk() + val holder3 = AnimatorListenerHolder(ANIMATOR_CAMERA_GPS_BEARING, listener3) + val set2 = HashSet().also { + it.add(holder2) + it.add(holder3) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set2) + + // try pushing an update to verify it was ignored + val valueAnimator: ValueAnimator = mockk() + every { valueAnimator.animatedValue } returns 10f + val animator = locationAnimatorCoordinator.animatorArray.get(ANIMATOR_LAYER_ACCURACY) + animator.onAnimationUpdate(valueAnimator) + + verify(exactly = 0) { listener.onNewAnimationValue(any()) } + } + @Test fun feedNewCompassBearing_withAnimation() { locationAnimatorCoordinator.setCompassAnimationEnabled(true) From ec15d862dba4967fc821784bb69fc8f8c5a6a35b Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 22 Apr 2020 12:54:09 +0800 Subject: [PATCH 131/185] Update changelog for 9.2.0-alpha.1 (#329) * Incorporate changes since 9.1.0 and changes in GL Native maps-v1.6.0-rc.1 Co-authored-by: Chloe Krawczyk --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 434860bc8..550b173e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ Mapbox welcomes participation and contributions from everyone. Please read [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) to get started. +## 9.2.0-alpha.1 - April 21, 2020 +### Features + - The [`SymbolLayer.iconTextFit`](https://docs.mapbox.com/android/api/map-sdk/9.2.0-alpha.1/com/mapbox/mapboxsdk/style/layers/PropertyFactory.html#iconTextFit-com.mapbox.mapboxsdk.style.expressions.Expression-) property now respects the stretch metadata of any nine-part stretchable image passed into the `style.addImage` method. You can define the stretchable area of an image by configuring the `stretchX`, `stretchY`, `content` options on `Style.addImage` to append the requisite [metadata](https://github.com/mapbox/mapbox-gl-js/issues/8917). ([#314](https://github.com/mapbox/mapbox-gl-native-android/pull/314)) + - Added methods to set and get the sort key of features in a `CircleLayer` at runtime. Features with a higher sort key will appear above features with a lower sort key. ([#322](https://github.com/mapbox/mapbox-gl-native-android/pull/322)) + - Added `Source.maxOverscaleFactor` for defining the maximum factor by which a parent tile can be overscaled during rendering. This setting is only needed if a custom source on your map appears blurry or distorted when viewed at new zoom levels. ([#299](https://github.com/mapbox/mapbox-gl-native-android/pull/299)) + +### Improvements and bug fixes + - Enabled adding style images on-demand on `MapSnapshotter`. ([#317](https://github.com/mapbox/mapbox-gl-native-android/pull/317)) + - Fixed a crash when calling the `Style.removeImage` method with the name of a nonexistent image. ([#16391](https://github.com/mapbox/mapbox-gl-native/pull/16391)) + - Fixed a crash when encountering an invalid polyline. ([#16409](https://github.com/mapbox/mapbox-gl-native/pull/16409)) + - Certain logging statements no longer run on the main thread. ([#16325](https://github.com/mapbox/mapbox-gl-native/pull/16325)) + ## 9.1.0 ### Features From 7367a49de07826da99f4b8806dfca4f79faf6f38 Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Thu, 16 Apr 2020 11:31:25 +0800 Subject: [PATCH 132/185] Remove the use of the deprecated TYPE_ORIENTATION sensor. The compass engine has not adjusted the heading according to the device orientation. This causes wrong heading if the device is not in its normal orientation. --- .../LocationComponentCompassEngine.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 17fc2c063..9f363bf14 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -69,16 +69,10 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen this.sensorManager = sensorManager; compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); if (compassSensor == null) { - if (isGyroscopeAvailable()) { - Logger.d(TAG, "Rotation vector sensor not supported on device, " - + "falling back to orientation."); - compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); - } else { - Logger.d(TAG, "Rotation vector sensor not supported on device, " - + "falling back to accelerometer and magnetic field."); - gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - magneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); - } + Logger.d(TAG, "Rotation vector sensor not supported on device, " + + "falling back to accelerometer and magnetic field."); + gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + magneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); } } @@ -122,8 +116,6 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { rotationVectorValue = getRotationVectorFromSensorEvent(event); updateOrientation(); - } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { - notifyCompassChangeListeners((event.values[0] + 360) % 360); } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { gravityValues = lowPassFilter(getRotationVectorFromSensorEvent(event), gravityValues); updateOrientation(); @@ -146,10 +138,6 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen } } - private boolean isGyroscopeAvailable() { - return sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null; - } - @SuppressWarnings("SuspiciousNameCombination") private void updateOrientation() { if (rotationVectorValue != null) { From 928632ad43232bf2682e80670c15e41c9dd222dc Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Thu, 16 Apr 2020 14:14:33 +0800 Subject: [PATCH 133/185] Prevent dropping the TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD sensor events, otherwise, only one sensor value is updated in each heading update. Especially, there may be more TYPE_ACCELEROMETER events in some devices, such that TYPE_MAGNETIC_FIELD events could be dropped easily. Also, it took longer time to reflect the latest heading if there are few events, due to the lowPassFilter. --- .../LocationComponentCompassEngine.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 9f363bf14..230fc1b39 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -104,11 +104,6 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @Override public void onSensorChanged(@NonNull SensorEvent event) { - // check when the last time the compass was updated, return if too soon. - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime < compassUpdateNextTimestamp) { - return; - } if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); return; @@ -123,9 +118,6 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen magneticValues = lowPassFilter(getRotationVectorFromSensorEvent(event), magneticValues); updateOrientation(); } - - // Update the compassUpdateNextTimestamp - compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } @Override @@ -140,6 +132,12 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @SuppressWarnings("SuspiciousNameCombination") private void updateOrientation() { + // check when the last time the compass was updated, return if too soon. + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime < compassUpdateNextTimestamp) { + return; + } + if (rotationVectorValue != null) { SensorManager.getRotationMatrixFromVector(rotationMatrix, rotationVectorValue); } else { @@ -182,6 +180,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen // The x-axis is all we care about here. notifyCompassChangeListeners((float) Math.toDegrees(orientation[0])); + + // Update the compassUpdateNextTimestamp + compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } private void notifyCompassChangeListeners(float heading) { From 7bcc2d3282d66dba67ca74a70ce6ada6d3f5fff4 Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Thu, 16 Apr 2020 15:35:35 +0800 Subject: [PATCH 134/185] Calculate the heading differently, depending on whether the device is placed horizontally or vertically. The previous logic may return wrong heading when the device is placed horizontally. --- .../LocationComponentCompassEngine.java | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 230fc1b39..4862297f2 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -145,28 +145,28 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen SensorManager.getRotationMatrix(rotationMatrix, null, gravityValues, magneticValues); } - final int worldAxisForDeviceAxisX; - final int worldAxisForDeviceAxisY; + int worldAxisForDeviceAxisX; + int worldAxisForDeviceAxisY; - // Remap the axes as if the device screen was the instrument panel, + // Assume the device screen was parallel to the ground, // and adjust the rotation matrix for the device orientation. switch (windowManager.getDefaultDisplay().getRotation()) { case Surface.ROTATION_90: - worldAxisForDeviceAxisX = SensorManager.AXIS_Z; + worldAxisForDeviceAxisX = SensorManager.AXIS_Y; worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_X; break; case Surface.ROTATION_180: worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_X; - worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Y; break; case Surface.ROTATION_270: - worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Z; + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Y; worldAxisForDeviceAxisY = SensorManager.AXIS_X; break; case Surface.ROTATION_0: default: worldAxisForDeviceAxisX = SensorManager.AXIS_X; - worldAxisForDeviceAxisY = SensorManager.AXIS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_Y; break; } @@ -178,6 +178,37 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen float[] orientation = new float[3]; SensorManager.getOrientation(adjustedRotationMatrix, orientation); + if (orientation[1] < -Math.PI / 4) { + // The pitch is less than 45 degrees. + // Remap the axes as if the device screen was the instrument panel, + // and adjust the rotation matrix for the device orientation. + switch (windowManager.getDefaultDisplay().getRotation()) { + case Surface.ROTATION_90: + worldAxisForDeviceAxisX = SensorManager.AXIS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_X; + break; + case Surface.ROTATION_180: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Z; + break; + case Surface.ROTATION_270: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_X; + break; + case Surface.ROTATION_0: + default: + worldAxisForDeviceAxisX = SensorManager.AXIS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_Z; + break; + } + + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, + worldAxisForDeviceAxisY, adjustedRotationMatrix); + + // Transform rotation matrix into azimuth/pitch/roll + SensorManager.getOrientation(adjustedRotationMatrix, orientation); + } + // The x-axis is all we care about here. notifyCompassChangeListeners((float) Math.toDegrees(orientation[0])); From e3b2452ba2b4ec3dfc83129e7555f70c84ca3373 Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Thu, 16 Apr 2020 16:08:35 +0800 Subject: [PATCH 135/185] Update the heading, even if the sensor is unreliable. This makes it possible to use a different indicator for the unreliable case, instead of just changing the RenderMode to NORMAL. --- .../mapboxsdk/location/LocationComponentCompassEngine.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 4862297f2..39c1a4cd8 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -106,7 +106,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen public void onSensorChanged(@NonNull SensorEvent event) { if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); - return; + // Update the heading, even if the sensor is unreliable. + // This makes it possible to use a different indicator for the unreliable case, instead of just changing the RenderMode to NORMAL. + //return; } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { rotationVectorValue = getRotationVectorFromSensorEvent(event); From d230172b3ca2d997c58090fa7628deea40bc16f3 Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Tue, 21 Apr 2020 13:52:37 +0800 Subject: [PATCH 136/185] Fix code style and unit test issues for the compass fix. --- .../mapboxsdk/location/LocationComponentCompassEngine.java | 3 ++- .../java/com/mapbox/mapboxsdk/location/CompassEngineTest.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 39c1a4cd8..3fdc20a35 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -107,7 +107,8 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); // Update the heading, even if the sensor is unreliable. - // This makes it possible to use a different indicator for the unreliable case, instead of just changing the RenderMode to NORMAL. + // This makes it possible to use a different indicator for the unreliable case, + // instead of just changing the RenderMode to NORMAL. //return; } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java index bebd82811..0ff562a43 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java @@ -58,7 +58,6 @@ public class CompassEngineTest { @Test public void whenGyroscopeIsNull_fallbackToGravity() { SensorManager sensorManager = mock(SensorManager.class); - when(sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)).thenReturn(null); new LocationComponentCompassEngine(windowManager, sensorManager); verify(sensorManager, times(1)).getDefaultSensor(Sensor.TYPE_ACCELEROMETER); @@ -67,7 +66,6 @@ public class CompassEngineTest { @Test public void whenGyroscopeIsNull_fallbackToMagneticField() { SensorManager sensorManager = mock(SensorManager.class); - when(sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)).thenReturn(null); new LocationComponentCompassEngine(windowManager, sensorManager); verify(sensorManager, times(1)).getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); From 6f6f146d698e1cbdab580632cc7b040e597c8e26 Mon Sep 17 00:00:00 2001 From: Tsoi Yat Shing Date: Thu, 23 Apr 2020 11:46:57 +0800 Subject: [PATCH 137/185] Prevent bearing flipping in the cases of upside down and face down. --- .../LocationComponentCompassEngine.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 3fdc20a35..2bcba2950 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -182,7 +182,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen SensorManager.getOrientation(adjustedRotationMatrix, orientation); if (orientation[1] < -Math.PI / 4) { - // The pitch is less than 45 degrees. + // The pitch is less than -45 degrees. // Remap the axes as if the device screen was the instrument panel, // and adjust the rotation matrix for the device orientation. switch (windowManager.getDefaultDisplay().getRotation()) { @@ -205,6 +205,64 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen break; } + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, + worldAxisForDeviceAxisY, adjustedRotationMatrix); + + // Transform rotation matrix into azimuth/pitch/roll + SensorManager.getOrientation(adjustedRotationMatrix, orientation); + } else if (orientation[1] > Math.PI / 4) { + // The pitch is larger than 45 degrees. + // Remap the axes as if the device screen was upside down and facing back, + // and adjust the rotation matrix for the device orientation. + switch (windowManager.getDefaultDisplay().getRotation()) { + case Surface.ROTATION_90: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_X; + break; + case Surface.ROTATION_180: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_Z; + break; + case Surface.ROTATION_270: + worldAxisForDeviceAxisX = SensorManager.AXIS_Z; + worldAxisForDeviceAxisY = SensorManager.AXIS_X; + break; + case Surface.ROTATION_0: + default: + worldAxisForDeviceAxisX = SensorManager.AXIS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Z; + break; + } + + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, + worldAxisForDeviceAxisY, adjustedRotationMatrix); + + // Transform rotation matrix into azimuth/pitch/roll + SensorManager.getOrientation(adjustedRotationMatrix, orientation); + } else if (Math.abs(orientation[2]) > Math.PI / 2) { + // The roll is less than -90 degrees, or is larger than 90 degrees. + // Remap the axes as if the device screen was face down, + // and adjust the rotation matrix for the device orientation. + switch (windowManager.getDefaultDisplay().getRotation()) { + case Surface.ROTATION_90: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Y; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_X; + break; + case Surface.ROTATION_180: + worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_Y; + break; + case Surface.ROTATION_270: + worldAxisForDeviceAxisX = SensorManager.AXIS_Y; + worldAxisForDeviceAxisY = SensorManager.AXIS_X; + break; + case Surface.ROTATION_0: + default: + worldAxisForDeviceAxisX = SensorManager.AXIS_X; + worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Y; + break; + } + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, worldAxisForDeviceAxisY, adjustedRotationMatrix); From 161abf832664f7e9646482859586505e2a7e2450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 23 Apr 2020 12:17:35 +0200 Subject: [PATCH 138/185] clean up compass engine comments and duplication --- .../LocationComponentCompassEngine.java | 34 +++++-------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index 2bcba2950..649ccc267 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -109,7 +109,6 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen // Update the heading, even if the sensor is unreliable. // This makes it possible to use a different indicator for the unreliable case, // instead of just changing the RenderMode to NORMAL. - //return; } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { rotationVectorValue = getRotationVectorFromSensorEvent(event); @@ -183,8 +182,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen if (orientation[1] < -Math.PI / 4) { // The pitch is less than -45 degrees. - // Remap the axes as if the device screen was the instrument panel, - // and adjust the rotation matrix for the device orientation. + // Remap the axes as if the device screen was the instrument panel. switch (windowManager.getDefaultDisplay().getRotation()) { case Surface.ROTATION_90: worldAxisForDeviceAxisX = SensorManager.AXIS_Z; @@ -204,16 +202,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen worldAxisForDeviceAxisY = SensorManager.AXIS_Z; break; } - - SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, - worldAxisForDeviceAxisY, adjustedRotationMatrix); - - // Transform rotation matrix into azimuth/pitch/roll - SensorManager.getOrientation(adjustedRotationMatrix, orientation); } else if (orientation[1] > Math.PI / 4) { // The pitch is larger than 45 degrees. - // Remap the axes as if the device screen was upside down and facing back, - // and adjust the rotation matrix for the device orientation. + // Remap the axes as if the device screen was upside down and facing back. switch (windowManager.getDefaultDisplay().getRotation()) { case Surface.ROTATION_90: worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Z; @@ -233,16 +224,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Z; break; } - - SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, - worldAxisForDeviceAxisY, adjustedRotationMatrix); - - // Transform rotation matrix into azimuth/pitch/roll - SensorManager.getOrientation(adjustedRotationMatrix, orientation); } else if (Math.abs(orientation[2]) > Math.PI / 2) { // The roll is less than -90 degrees, or is larger than 90 degrees. - // Remap the axes as if the device screen was face down, - // and adjust the rotation matrix for the device orientation. + // Remap the axes as if the device screen was face down. switch (windowManager.getDefaultDisplay().getRotation()) { case Surface.ROTATION_90: worldAxisForDeviceAxisX = SensorManager.AXIS_MINUS_Y; @@ -262,14 +246,14 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen worldAxisForDeviceAxisY = SensorManager.AXIS_MINUS_Y; break; } - - SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, - worldAxisForDeviceAxisY, adjustedRotationMatrix); - - // Transform rotation matrix into azimuth/pitch/roll - SensorManager.getOrientation(adjustedRotationMatrix, orientation); } + SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisForDeviceAxisX, + worldAxisForDeviceAxisY, adjustedRotationMatrix); + + // Transform rotation matrix into azimuth/pitch/roll + SensorManager.getOrientation(adjustedRotationMatrix, orientation); + // The x-axis is all we care about here. notifyCompassChangeListeners((float) Math.toDegrees(orientation[0])); From 5cee66a451005fff55b9e9366e092432d0cbd41c Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 24 Apr 2020 16:55:02 +0800 Subject: [PATCH 139/185] Add api and demo for expression distance (#339) * Add api and demo for expression distance * Update test case --- .../style/expressions/Expression.java | 37 +++++ .../style/expressions/ExpressionTest.java | 17 +++ .../src/main/AndroidManifest.xml | 12 ++ .../style/DistanceExpressionActivity.kt | 129 ++++++++++++++++++ .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/titles.xml | 1 + vendor/mapbox-gl-native | 2 +- 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DistanceExpressionActivity.kt diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index f27a4f738..ba1048879 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -8,6 +8,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.mapbox.geojson.GeoJson; import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.style.layers.PropertyValue; @@ -1574,6 +1575,42 @@ public class Expression { return new Expression("in", literal(needle), haystack); } + /** + * Retrieves the shortest distance between two geometries. + * The returned value can be consumed as an input into another expression for changing a paint or layout property + * or filtering features by distance. + * + * @param geoJson the target feature geoJso. + * Currently supports `Point`, `MultiPoint`, `LineString`, `MultiLineString` geometry types + * @param unit the unit for the returned value. + * Currently supports `metres`, `kilometers`, `miles`, `nauticalmiles`, "yards","feet","inches"。 + * @return the distance in the unit that is provided. + * @see Style specification + */ + public static Expression distance(@NonNull GeoJson geoJson, String unit) { + Map map = new HashMap<>(); + map.put("json", literal(geoJson.toJson())); + return new Expression("distance", new ExpressionMap(map), literal(unit)); + } + + /** + * Retrieves the shortest distance between two geometries. + * The returned value can be consumed as an input into another expression for changing a paint or layout property + * or filtering features by distance. + *

    + * Currently supports `Point`, `MultiPoint`, `LineString`, `MultiLineString` geometry types. + * + * @param geoJson the target feature geoJson. + * Currently supports `Point`, `MultiPoint`, `LineString`, `MultiLineString` geometry types + * @return the distance in the unit "meters". + * @see Style specification + */ + public static Expression distance(@NonNull GeoJson geoJson) { + Map map = new HashMap<>(); + map.put("json", literal(geoJson.toJson())); + return new Expression("distance", new ExpressionMap(map)); + } + public static Expression within(@NonNull Polygon polygon) { Map map = new HashMap<>(); diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java index 62f3a71f0..6ca50a510 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java @@ -37,6 +37,7 @@ 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.distance; 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; @@ -487,6 +488,22 @@ public class ExpressionTest { assertTrue("expression should match", Arrays.deepEquals(expected, actual)); } + + @Test + public void testDistance() throws Exception { + Point point = Point.fromLngLat(1, 2); + HashMap map = new HashMap<>(); + map.put("json", point.toJson()); + Object[] expected = new Object[] {"distance", map}; + Object[] actual = distance(point).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + + Object[] expectedWithUnit = new Object[] {"distance", map, "meters"}; + Object[] actualWithUnit = distance(point, "meters").toArray(); + assertTrue("expression should match", Arrays.deepEquals(expectedWithUnit, actualWithUnit)); + } + + @Test public void testInArray() throws Exception { Object[] expected = new Object[] {"in", "one", new Object[] {"literal", new Object[] {"one", "two"}}}; diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index e89902d7e..ba26ee8d6 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -515,6 +515,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + + mapboxMap = map + + // Setup camera position above Georgetown + mapboxMap.cameraPosition = CameraPosition.Builder() + .target(LatLng(lat, lon)) + .zoom(16.0) + .build() + setupStyle() + } + } + + private fun setupStyle() { + val center = Point.fromLngLat(lon, lat) + val circle = TurfTransformation.circle(center, 150.0, TurfConstants.UNIT_METRES) + // Setup style with additional layers, + // using Style.MAPBOX_STREETS as a base style + mapboxMap.setStyle( + Style.Builder() + .fromUri(Style.MAPBOX_STREETS) + .withSources( + GeoJsonSource( + POINT_ID, Point.fromLngLat(lon, lat) + ), + GeoJsonSource(CIRCLE_ID, circle) + ) + .withLayerBelow( + FillLayer(CIRCLE_ID, CIRCLE_ID) + .withProperties( + fillOpacity(0.5f), + fillColor(Color.parseColor("#3bb2d0")) + ), "poi-label" + ) + ) { style -> + // Show only POI labels inside circle radius using distance expression + val symbolLayer = style.getLayer("poi-label") as SymbolLayer + symbolLayer.setFilter(lt( + distance( + Point.fromLngLat(lon, lat), "meters" + ), 150) + ) + + // Hide other types of labels to highlight POI labels + (style.getLayer("road-label") as SymbolLayer).setProperties(visibility(NONE)) + (style.getLayer("transit-label") as SymbolLayer).setProperties(visibility(NONE)) + (style.getLayer("road-number-shield") as SymbolLayer).setProperties(visibility(NONE)) + } + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + override fun onDestroy() { + super.onDestroy() + mapView.onDestroy() + } + + override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) { + super.onSaveInstanceState(outState, outPersistentState) + outState?.let { + mapView.onSaveInstanceState(it) + } + } + + companion object { + const val POINT_ID = "point" + const val CIRCLE_ID = "circle" + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 6f61fb649..63c410cda 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -34,6 +34,7 @@ Learn how to create a dynamic custom InfoWindow Use SupportMapFragments in a ViewPager Adopt the map style on the fly + Show POIs on a map with distance expression filter Show a gradient line layer from a geojson source Use functions to change the map appearance Manipulate symbols at runtime diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 23c227f23..912af9ab9 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -32,6 +32,7 @@ Min/Max Zoom ViewPager Runtime Style + Distance Expression Gradient line layer Data Driven Style Circle layer diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 71ce52d35..9f8c9c61e 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 71ce52d35f8421c89f6112b83061613937b2836c +Subproject commit 9f8c9c61e87868510ee2951c93044c4995478641 From 847774712bf7b57fbf7e40a13ef439ee7453f144 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 28 Apr 2020 08:26:49 +0800 Subject: [PATCH 140/185] Bump gl-native to maps-v1.6.0-rc.2 (#344) --- vendor/mapbox-gl-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-gl-native b/vendor/mapbox-gl-native index 9f8c9c61e..de12a0647 160000 --- a/vendor/mapbox-gl-native +++ b/vendor/mapbox-gl-native @@ -1 +1 @@ -Subproject commit 9f8c9c61e87868510ee2951c93044c4995478641 +Subproject commit de12a0647dd1d0681d051ff7e3797356db149a52 From c77a49c15cfe785a093988fd79a8890f88b182da Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 28 Apr 2020 17:48:26 +0800 Subject: [PATCH 141/185] Make onSnapshotFailed run on main thread. (#347) --- .../mapboxsdk/snapshotter/MapSnapshotter.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index fc9ad758b..40a8532e9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -721,16 +721,20 @@ public class MapSnapshotter { /** * Called by JNI peer when snapshot has failed. - * Always called on the origin (main) thread. * * @param reason the exception string */ @Keep - protected void onSnapshotFailed(String reason) { - if (errorHandler != null) { - errorHandler.onError(reason); - reset(); - } + protected void onSnapshotFailed(final String reason) { + new Handler().post(new Runnable() { + @Override + public void run() { + if (errorHandler != null) { + errorHandler.onError(reason); + reset(); + } + } + }); } /** From 4e878d614d241297fa57063ea2cca75a29d4aede Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 28 Apr 2020 18:32:29 +0800 Subject: [PATCH 142/185] Update gralde configure to only build the target abi. (#341) * Update gralde configure to only build the target abi. * Fix sync project error. --- gradle/native-build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gradle/native-build.gradle b/gradle/native-build.gradle index 8aa760892..807fd12ea 100644 --- a/gradle/native-build.gradle +++ b/gradle/native-build.gradle @@ -58,7 +58,13 @@ ext.nativeBuild = { nativeTargets -> if (abi != 'all') { abiFilters abi.split(' ') } else { - abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" + if (project.hasProperty('android.injected.invoked.from.ide') && project.hasProperty('android.injected.build.abi')) { + //Only build the target abi while running from Android studio + abi = project.getProperty("android.injected.build.abi") + abiFilters abi.split(',').first() + } else { + abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" + } } } } From 859f64f97ee7165bcacce82f31c2da9be1e3a0ba Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 29 Apr 2020 15:57:25 +0800 Subject: [PATCH 143/185] Remove unit param for expression distance. (#352) --- .../style/expressions/Expression.java | 18 ------------------ .../style/expressions/ExpressionTest.java | 4 ---- .../style/DistanceExpressionActivity.kt | 2 +- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index ba1048879..860261b65 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -1575,24 +1575,6 @@ public class Expression { return new Expression("in", literal(needle), haystack); } - /** - * Retrieves the shortest distance between two geometries. - * The returned value can be consumed as an input into another expression for changing a paint or layout property - * or filtering features by distance. - * - * @param geoJson the target feature geoJso. - * Currently supports `Point`, `MultiPoint`, `LineString`, `MultiLineString` geometry types - * @param unit the unit for the returned value. - * Currently supports `metres`, `kilometers`, `miles`, `nauticalmiles`, "yards","feet","inches"。 - * @return the distance in the unit that is provided. - * @see Style specification - */ - public static Expression distance(@NonNull GeoJson geoJson, String unit) { - Map map = new HashMap<>(); - map.put("json", literal(geoJson.toJson())); - return new Expression("distance", new ExpressionMap(map), literal(unit)); - } - /** * Retrieves the shortest distance between two geometries. * The returned value can be consumed as an input into another expression for changing a paint or layout property diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java index 6ca50a510..729b58def 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java @@ -497,10 +497,6 @@ public class ExpressionTest { Object[] expected = new Object[] {"distance", map}; Object[] actual = distance(point).toArray(); assertTrue("expression should match", Arrays.deepEquals(expected, actual)); - - Object[] expectedWithUnit = new Object[] {"distance", map, "meters"}; - Object[] actualWithUnit = distance(point, "meters").toArray(); - assertTrue("expression should match", Arrays.deepEquals(expectedWithUnit, actualWithUnit)); } diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DistanceExpressionActivity.kt b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DistanceExpressionActivity.kt index 6d23b5324..e212f765c 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DistanceExpressionActivity.kt +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DistanceExpressionActivity.kt @@ -74,7 +74,7 @@ class DistanceExpressionActivity : AppCompatActivity() { val symbolLayer = style.getLayer("poi-label") as SymbolLayer symbolLayer.setFilter(lt( distance( - Point.fromLngLat(lon, lat), "meters" + Point.fromLngLat(lon, lat) ), 150) ) From 6fd498ed16dbd063447813622e3e00fa70e7e1bf Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Wed, 29 Apr 2020 20:49:35 +0800 Subject: [PATCH 144/185] Add set and get api for volatile and minimumTileUpdateInterval in Source (#355) * Add set and get api for Volatile and minimumTileUpdateInterval in Source * Format codes. --- .../src/cpp/style/sources/source.cpp | 24 +++++++- .../src/cpp/style/sources/source.hpp | 8 +++ .../mapboxsdk/style/sources/Source.java | 60 ++++++++++++++++++- .../testapp/style/CustomGeometrySourceTest.kt | 24 ++++++++ 4 files changed, 111 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp b/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp index 29e41976c..39f352a84 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/source.cpp @@ -180,6 +180,22 @@ static std::unique_ptr createSourcePeer(jni::JNIEnv& env, return ownedSource != nullptr; } + jni::Local Source::isVolatile(jni::JNIEnv& env) { + return jni::Box(env, jni::jboolean(source.isVolatile())); + } + + void Source::setVolatile(JNIEnv& env, jni::Boolean& value) { + source.setVolatile(jni::Unbox(env, value)); + } + + void Source::setMinimumTileUpdateInterval(JNIEnv& env, jni::Long& interval) { + source.setMinimumTileUpdateInterval(Milliseconds(jni::Unbox(env, interval))); + } + + jni::Local Source::getMinimumTileUpdateInterval(JNIEnv& env) { + return jni::Box(env, jni::jlong(source.getMinimumTileUpdateInterval().count() / 1000000)); + } + void Source::releaseJavaPeer() { // We can't release the peer if the source was not removed from the map if (!ownedSource) { @@ -214,7 +230,12 @@ static std::unique_ptr createSourcePeer(jni::JNIEnv& env, METHOD(&Source::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), METHOD(&Source::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta"), METHOD(&Source::setMaxOverscaleFactorForParentTiles, "nativeSetMaxOverscaleFactorForParentTiles"), - METHOD(&Source::getMaxOverscaleFactorForParentTiles, "nativeGetMaxOverscaleFactorForParentTiles")); + METHOD(&Source::getMaxOverscaleFactorForParentTiles, "nativeGetMaxOverscaleFactorForParentTiles"), + METHOD(&Source::isVolatile, "nativeIsVolatile"), + METHOD(&Source::setVolatile, "nativeSetVolatile"), + METHOD(&Source::setMinimumTileUpdateInterval, "nativeSetMinimumTileUpdateInterval"), + METHOD(&Source::getMinimumTileUpdateInterval, "nativeGetMinimumTileUpdateInterval")); + // Register subclasses GeoJSONSource::registerNative(env); @@ -225,6 +246,5 @@ static std::unique_ptr createSourcePeer(jni::JNIEnv& env, CustomGeometrySource::registerNative(env); RasterDEMSource::registerNative(env); } - } // namespace android } // namespace mbgl diff --git a/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp b/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp index fbeb201c7..bb398bf2a 100644 --- a/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp +++ b/MapboxGLAndroidSDK/src/cpp/style/sources/source.hpp @@ -54,6 +54,14 @@ public: void addToStyle(JNIEnv& env, const jni::Object& obj, mbgl::style::Style& style); + jni::Local isVolatile(JNIEnv&); + + void setVolatile(JNIEnv&, jni::Boolean&); + + void setMinimumTileUpdateInterval(JNIEnv&, jni::Long &); + + jni::Local getMinimumTileUpdateInterval(JNIEnv&); + protected: // Set on newly created sources until added to the map. std::unique_ptr ownedSource; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index f19544922..4686deee9 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -1,12 +1,12 @@ package com.mapbox.mapboxsdk.style.sources; +import com.mapbox.mapboxsdk.LibraryLoader; +import com.mapbox.mapboxsdk.utils.ThreadUtils; + import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.mapbox.mapboxsdk.LibraryLoader; -import com.mapbox.mapboxsdk.utils.ThreadUtils; - /** * Base Peer class for sources. see source.hpp for the other half of the peer. */ @@ -115,6 +115,44 @@ public abstract class Source { return nativeGetMaxOverscaleFactorForParentTiles(); } + /** + * Retrieve whether or not the fetched tiles for the given source should be stored in the local cache + * + @return true if tiles are volatile, false if they will be stored in local cache. Default value is false. + */ + @NonNull + public Boolean isVolatile() { + return nativeIsVolatile(); + } + + /** + * Set a flag defining whether or not the fetched tiles for the given source should be stored in the local cache + * + * @param value current setting for volatile. + */ + public void setVolatile(Boolean value) { + nativeSetVolatile(value); + } + + /** + * Sets the minimum tile update interval, which is used to throttle the tile update network requests. + * + * @param interval the update interval in milliseconds. + */ + public void setMinimumTileUpdateInterval(Long interval) { + nativeSetMinimumTileUpdateInterval(interval); + } + + /** + * Retrieve the minimum tile update interval, which is used to throttle the tile update network requests. + * + * @return the update interval in milliseconds, default valuse is 0. + */ + @NonNull + public Long getMinimumTileUpdateInterval() { + return nativeGetMinimumTileUpdateInterval(); + } + /** * Internal use * @@ -148,6 +186,22 @@ public abstract class Source { @Keep protected native Integer nativeGetMaxOverscaleFactorForParentTiles(); + @NonNull + @Keep + protected native Boolean nativeIsVolatile(); + + @NonNull + @Keep + protected native void nativeSetVolatile(Boolean value); + + @NonNull + @Keep + protected native void nativeSetMinimumTileUpdateInterval(Long interval); + + @NonNull + @Keep + protected native Long nativeGetMinimumTileUpdateInterval(); + public void setDetached() { detached = true; } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index cc4a04ecd..799bcc1a1 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -83,4 +83,28 @@ class CustomGeometrySourceTest : BaseTest() { } } } + + @Test + fun isVolatileTest() { + validateTestSetup() + invoke(mapboxMap) { uiController, mapboxMap -> + mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let { + assertFalse(it.isVolatile) + it.isVolatile = true + assertTrue(it.isVolatile) + } + } + } + + @Test + fun minimumTileUpdateIntervalTest() { + validateTestSetup() + invoke(mapboxMap) { uiController, mapboxMap -> + mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let { + assertEquals(0, it.minimumTileUpdateInterval) + it.minimumTileUpdateInterval = 1000 + assertEquals(1000, it.minimumTileUpdateInterval) + } + } + } } \ No newline at end of file From 9bfe77df403c21357c5d56b9a9757022b3a1fa86 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Thu, 30 Apr 2020 03:28:36 -0700 Subject: [PATCH 145/185] Adding pulsing circle to LocationComponent options (#172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [location] added pulsing locationcomponent circle * adjusting style switching to roll through all styles * refactored methods and variables for prefix continuity * refactoring to after making start and stop private methods * refactoring to stop pulsing when LocationComponent is disabled and color/speed is then selected * refactoring to swap interpolator string paramete for interpolator interface parameter * LocationLayerControllerTest adjustments * removing unneeded test * more rebase adjustments * [location] added pulsing locationcomponent circle * refactoring to swap interpolator string paramete for interpolator interface parameter * consolidating pulse ui update methods * gl-native vendor bump * refactor to check for activation with locationcomponent * Update MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java Co-Authored-By: Łukasz Paczos * Update MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java Co-Authored-By: Łukasz Paczos * Update MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java Co-Authored-By: Łukasz Paczos * Update MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java Co-Authored-By: Łukasz Paczos * Update MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java Co-Authored-By: Łukasz Paczos * Added incompatibility docs * Added pulse alpha range explanation * Do not wrap pulsing circle animator with an animator set to avoid leaks Co-authored-by: Łukasz Paczos --- .../IndicatorLocationLayerRenderer.java | 28 +- .../location/LayerSourceProvider.java | 19 +- .../location/LocationAnimatorCoordinator.java | 43 ++ .../mapboxsdk/location/LocationComponent.java | 33 + .../LocationComponentActivationOptions.java | 8 + .../location/LocationComponentConstants.java | 7 + .../location/LocationComponentOptions.java | 699 +++++++++++++----- .../location/LocationLayerController.java | 32 +- .../location/LocationLayerRenderer.java | 6 + .../mapboxsdk/location/MapboxAnimator.java | 13 +- .../location/MapboxAnimatorProvider.java | 30 + .../location/MapboxAnimatorSetProvider.java | 3 +- .../PulsingLocationCircleAnimator.java | 19 + .../location/SymbolLocationLayerRenderer.java | 53 ++ .../src/main/res-public/values/public.xml | 9 + .../src/main/res/values/attrs.xml | 9 + .../src/main/res/values/styles.xml | 9 + .../LocationAnimatorCoordinatorTest.kt | 4 +- ...ocationComponentActivationOptionsTest.java | 41 + .../LocationComponentOptionsTest.java | 2 +- .../location/LocationLayerControllerTest.java | 27 +- .../location/LocationLayerControllerTest.kt | 170 +++++ .../utils/StyleChangeIdlingResource.kt | 2 +- .../src/main/AndroidManifest.xml | 22 + .../BasicLocationPulsingCircleActivity.java | 215 ++++++ ...stomizedLocationPulsingCircleActivity.java | 360 +++++++++ .../testapp/activity/location/Utils.java | 2 +- ...ty_location_layer_basic_pulsing_circle.xml | 13 + ...cation_layer_customized_pulsing_circle.xml | 78 ++ .../res/menu/menu_pulsing_location_mode.xml | 25 + .../src/main/res/values/descriptions.xml | 2 + .../src/main/res/values/titles.xml | 2 + 32 files changed, 1772 insertions(+), 213 deletions(-) create mode 100644 MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/BasicLocationPulsingCircleActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/CustomizedLocationPulsingCircleActivity.java create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_basic_pulsing_circle.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_customized_pulsing_circle.xml create mode 100644 MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_pulsing_location_mode.xml diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java index 5cb1f37df..10c22107b 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/IndicatorLocationLayerRenderer.java @@ -2,8 +2,6 @@ package com.mapbox.mapboxsdk.location; import android.graphics.Bitmap; -import androidx.annotation.Nullable; - import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.Style; @@ -12,6 +10,8 @@ import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.mapboxsdk.utils.ColorUtils; +import androidx.annotation.Nullable; + import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BACKGROUND_STALE_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.BEARING_ICON; @@ -181,6 +181,30 @@ class IndicatorLocationLayerRenderer implements LocationLayerRenderer { lastBearing = bearing; } + /** + * Adjust the visibility of the pulsing LocationComponent circle. + */ + @Override + public void adjustPulsingCircleLayerVisibility(boolean visible) { + // not supported at this time + } + + /** + * Adjust the the pulsing LocationComponent circle based on the set options. + */ + @Override + public void stylePulsingCircle(LocationComponentOptions options) { + // not supported at this time + } + + /** + * Adjust the visual appearance of the pulsing LocationComponent circle. + */ + @Override + public void updatePulsingUi(float radius, @Nullable Float opacity) { + // not supported at this time + } + private void setImages(@RenderMode.Mode int renderMode, boolean isStale) { String topImage = ""; String bearingImage = ""; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index 053fdb24f..96d073dac 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -32,6 +32,7 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PULSING_CIRCLE_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; @@ -131,9 +132,23 @@ class LayerSourceProvider { LocationIndicatorLayer layer = new LocationIndicatorLayer(FOREGROUND_LAYER); layer.setLocationTransition(new TransitionOptions(0, 0)); layer.setProperties( - LocationPropertyFactory.perspectiveCompensation(0.9f), - LocationPropertyFactory.imageTiltDisplacement(4f) + LocationPropertyFactory.perspectiveCompensation(0.9f), + LocationPropertyFactory.imageTiltDisplacement(4f) ); return layer; } + + /** + * Adds a {@link CircleLayer} to the map to support the {@link LocationComponent} pulsing UI functionality. + * + * @return a {@link CircleLayer} with the correct data-driven styling. Tilting the map will keep the pulsing + * layer aligned with the map plane. + */ + @NonNull + Layer generatePulsingCircleLayer() { + return new CircleLayer(PULSING_CIRCLE_LAYER, LOCATION_SOURCE) + .withProperties( + circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) + ); + } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 50b2d6384..ab8eec709 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.location.Location; import android.os.SystemClock; import android.util.SparseArray; +import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import androidx.annotation.NonNull; @@ -32,6 +33,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURA import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_PULSING_CIRCLE; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation; @@ -186,6 +188,28 @@ final class LocationAnimatorCoordinator { this.previousAccuracyRadius = targetAccuracyRadius; } + /** + * Initializes the {@link PulsingLocationCircleAnimator}, which is a type of {@link MapboxAnimator}. + * This method also adds the animator to this class' animator array. + * + * @param options the {@link LocationComponentOptions} passed to this class upstream from the + * {@link LocationComponent}. + */ + void startLocationComponentCirclePulsing(LocationComponentOptions options) { + cancelAnimator(ANIMATOR_PULSING_CIRCLE); + MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(ANIMATOR_PULSING_CIRCLE); + if (listener != null) { + PulsingLocationCircleAnimator pulsingLocationCircleAnimator = animatorProvider.pulsingCircleAnimator( + listener, + maxAnimationFps, + options.pulseSingleDuration(), + options.pulseMaxRadius(), + options.pulseInterpolator() == null ? new DecelerateInterpolator() : options.pulseInterpolator()); + animatorArray.put(ANIMATOR_PULSING_CIRCLE, pulsingLocationCircleAnimator); + playPulsingAnimator(); + } + } + void feedNewZoomLevel(double targetZoomLevel, @NonNull CameraPosition currentCameraPosition, long animationDuration, @Nullable MapboxMap.CancelableCallback callback) { updateZoomAnimator((float) targetZoomLevel, (float) currentCameraPosition.zoom, callback); @@ -349,6 +373,18 @@ final class LocationAnimatorCoordinator { animatorSetProvider.startAnimation(animators, new LinearInterpolator(), duration); } + /** + * Starts the {@link PulsingLocationCircleAnimator} in the animator array. This method is separate + * from {@link #playAnimators(long, int...)} because the MapboxAnimatorSetProvider has many more + * customizable animation parameters than the other {@link MapboxAnimator}s. + */ + private void playPulsingAnimator() { + Animator animator = animatorArray.get(ANIMATOR_PULSING_CIRCLE); + if (animator != null) { + animator.start(); + } + } + void resetAllCameraAnimations(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { resetCameraCompassAnimation(currentCameraPosition); boolean snap = resetCameraLocationAnimations(currentCameraPosition, isGpsNorth); @@ -446,6 +482,13 @@ final class LocationAnimatorCoordinator { cancelAnimator(ANIMATOR_TILT); } + /** + * Cancel the pulsing circle location animator. + */ + void stopPulsingCircleAnimation() { + cancelAnimator(ANIMATOR_PULSING_CIRCLE); + } + void cancelAllAnimations() { for (int i = 0; i < animatorArray.size(); i++) { @MapboxAnimator.Type int animatorType = animatorArray.keyAt(i); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index bbb60289d..c7792e692 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -726,10 +726,25 @@ public final class LocationComponent { locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); locationAnimatorCoordinator.setCompassAnimationEnabled(options.compassAnimationEnabled()); locationAnimatorCoordinator.setAccuracyAnimationEnabled(options.accuracyAnimationEnabled()); + if (options.pulseEnabled()) { + startPulsingLocationCircle(); + } else { + stopPulsingLocationCircle(); + } updateMapWithOptions(options); } } + /** + * Starts the LocationComponent's pulsing circle UI. + */ + private void startPulsingLocationCircle() { + if (isEnabled && isLayerReady) { + locationAnimatorCoordinator.startLocationComponentCirclePulsing(options); + locationLayerController.adjustPulsingCircleLayerVisibility(true); + } + } + /** * Zooms to the desired zoom level. * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}. @@ -1215,6 +1230,14 @@ public final class LocationComponent { } } + /** + * Stop the LocationComponent's pulsing circle animation. + */ + private void stopPulsingLocationCircle() { + locationAnimatorCoordinator.stopPulsingCircleAnimation(); + locationLayerController.adjustPulsingCircleLayerVisibility(false); + } + @SuppressLint("MissingPermission") private void onLocationLayerStart() { if (!isComponentInitialized || !isComponentStarted || mapboxMap.getStyle() == null) { @@ -1240,6 +1263,11 @@ public final class LocationComponent { } } setCameraMode(locationCameraController.getCameraMode()); + if (options.pulseEnabled()) { + startPulsingLocationCircle(); + } else { + stopPulsingLocationCircle(); + } setLastLocation(); updateCompassListenerState(true); setLastCompassHeading(); @@ -1256,6 +1284,8 @@ public final class LocationComponent { if (compassEngine != null) { updateCompassListenerState(false); } + + stopPulsingLocationCircle(); locationAnimatorCoordinator.cancelAllAnimations(); if (locationEngine != null) { locationEngine.removeLocationUpdates(currentLocationEngineListener); @@ -1430,6 +1460,9 @@ public final class LocationComponent { boolean isLocationLayerHidden = locationLayerController.isHidden(); if (isEnabled && isComponentStarted && isLocationLayerHidden) { locationLayerController.show(); + if (options.pulseEnabled()) { + locationLayerController.adjustPulsingCircleLayerVisibility(true); + } } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java index bc295e920..e4c86e655 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptions.java @@ -131,6 +131,10 @@ public class LocationComponentActivationOptions { * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. *

  • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. * Use {@link LocationComponentOptions#foregroundDrawable()} to alter the image rendered as the puck. + *
  • The LocationComponent's pulsing effect. Any of the {@link LocationComponentOptions}' + * pulsing methods such as {@link LocationComponentOptions#pulseEnabled()} or + * {@link LocationComponentOptions#pulseColor()}, are useless when using the + * the specialized location layer. *
* * @return whether the default specialized location layer is used @@ -244,6 +248,10 @@ public class LocationComponentActivationOptions { * or {@link LocationComponentConstants#LOCATION_SOURCE} are ignored. *
  • All options that alter the image ID, like {@link LocationComponentOptions#foregroundName()}, are ignored. * Use {@link LocationComponentOptions#foregroundDrawable()} to alter the image rendered as the puck. + *
  • The LocationComponent's pulsing effect. Any of the {@link LocationComponentOptions}' + * pulsing methods such as {@link LocationComponentOptions#pulseEnabled()} or + * {@link LocationComponentOptions#pulseColor()}, are useless when using the + * the specialized location layer. * * * @param useSpecializedLocationLayer true if you want to initialize and use the diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index a3b4804b7..596f9c649 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -52,6 +52,8 @@ public final class LocationComponentConstants { static final String PROPERTY_FOREGROUND_STALE_ICON = "mapbox-property-foreground-stale-icon"; static final String PROPERTY_BACKGROUND_STALE_ICON = "mapbox-property-background-stale-icon"; static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon"; + static final String PROPERTY_PULSING_RADIUS = "mapbox-property-pulsing-circle-radius"; + static final String PROPERTY_PULSING_OPACITY = "mapbox-property-pulsing-circle-opacity"; // Layers @@ -80,6 +82,11 @@ public final class LocationComponentConstants { */ public static final String BEARING_LAYER = "mapbox-location-bearing-layer"; + /** + * Layer ID of the location pulsing circle. + */ + public static final String PULSING_CIRCLE_LAYER = "mapbox-location-pulsing-circle-layer"; + // Icons static final String FOREGROUND_ICON = "mapbox-location-icon"; static final String BACKGROUND_ICON = "mapbox-location-stroke-icon"; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java index e5b56865d..781d67eb3 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -5,12 +5,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; -import androidx.annotation.ColorInt; -import androidx.annotation.Dimension; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StyleRes; +import android.view.animation.Interpolator; import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.mapboxsdk.R; @@ -18,6 +13,13 @@ import com.mapbox.mapboxsdk.style.layers.Layer; import java.util.Arrays; +import androidx.annotation.ColorInt; +import androidx.annotation.Dimension; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; + /** * This class exposes options for the Location Component. The options can be set by defining a * style in your apps style.xml file and passing in directly into the {@link LocationComponent} @@ -69,6 +71,21 @@ public class LocationComponentOptions implements Parcelable { */ private static final float TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT = 1.1f; + /** + * Default duration of a single LocationComponent circle pulse. + */ + private static final long CIRCLE_PULSING_DURATION_DEFAULT_MS = 2300; + + /** + * Default opacity of the LocationComponent circle when it ends a single pulse. + */ + private static final float CIRCLE_PULSING_ALPHA_DEFAULT = 1f; + + /** + * Default maximum radius of the LocationComponent circle when it's pulsing. + */ + public static final float CIRCLE_PULSING_MAX_RADIUS_DEFAULT = 35f; + private float accuracyAlpha; private int accuracyColor; private int backgroundDrawableStale; @@ -114,41 +131,56 @@ public class LocationComponentOptions implements Parcelable { private float trackingAnimationDurationMultiplier; private boolean compassAnimationEnabled; private boolean accuracyAnimationEnabled; + private Boolean pulseEnabled; + private Boolean pulseFadeEnabled; + private Integer pulseColor; + private float pulseSingleDuration; + private float pulseMaxRadius; + private float pulseAlpha; + @Nullable + private Interpolator pulseInterpolator; public LocationComponentOptions( - float accuracyAlpha, - int accuracyColor, - int backgroundDrawableStale, - @Nullable String backgroundStaleName, - int foregroundDrawableStale, - @Nullable String foregroundStaleName, - int gpsDrawable, - @Nullable String gpsName, - int foregroundDrawable, - @Nullable String foregroundName, - int backgroundDrawable, - @Nullable String backgroundName, - int bearingDrawable, - @Nullable String bearingName, - @Nullable Integer bearingTintColor, - @Nullable Integer foregroundTintColor, - @Nullable Integer backgroundTintColor, - @Nullable Integer foregroundStaleTintColor, - @Nullable Integer backgroundStaleTintColor, - float elevation, - boolean enableStaleState, - long staleStateTimeout, - @Nullable int[] padding, - float maxZoomIconScale, - float minZoomIconScale, - boolean trackingGesturesManagement, - float trackingInitialMoveThreshold, - float trackingMultiFingerMoveThreshold, - String layerAbove, - String layerBelow, - float trackingAnimationDurationMultiplier, - boolean compassAnimationEnabled, - boolean accuracyAnimationEnabled) { + float accuracyAlpha, + int accuracyColor, + int backgroundDrawableStale, + @Nullable String backgroundStaleName, + int foregroundDrawableStale, + @Nullable String foregroundStaleName, + int gpsDrawable, + @Nullable String gpsName, + int foregroundDrawable, + @Nullable String foregroundName, + int backgroundDrawable, + @Nullable String backgroundName, + int bearingDrawable, + @Nullable String bearingName, + @Nullable Integer bearingTintColor, + @Nullable Integer foregroundTintColor, + @Nullable Integer backgroundTintColor, + @Nullable Integer foregroundStaleTintColor, + @Nullable Integer backgroundStaleTintColor, + float elevation, + boolean enableStaleState, + long staleStateTimeout, + @Nullable int[] padding, + float maxZoomIconScale, + float minZoomIconScale, + boolean trackingGesturesManagement, + float trackingInitialMoveThreshold, + float trackingMultiFingerMoveThreshold, + String layerAbove, + String layerBelow, + float trackingAnimationDurationMultiplier, + boolean compassAnimationEnabled, + boolean accuracyAnimationEnabled, + Boolean pulseEnabled, + Boolean pulseFadeEnabled, + Integer pulseColor, + float pulseSingleDuration, + float pulseMaxRadius, + float pulseAlpha, + @Nullable Interpolator pulseInterpolator) { this.accuracyAlpha = accuracyAlpha; this.accuracyColor = accuracyColor; this.backgroundDrawableStale = backgroundDrawableStale; @@ -185,6 +217,13 @@ public class LocationComponentOptions implements Parcelable { this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; this.compassAnimationEnabled = compassAnimationEnabled; this.accuracyAnimationEnabled = accuracyAnimationEnabled; + this.pulseEnabled = pulseEnabled; + this.pulseFadeEnabled = pulseFadeEnabled; + this.pulseColor = pulseColor; + this.pulseSingleDuration = pulseSingleDuration; + this.pulseMaxRadius = pulseMaxRadius; + this.pulseAlpha = pulseAlpha; + this.pulseInterpolator = pulseInterpolator; } /** @@ -202,106 +241,131 @@ public class LocationComponentOptions implements Parcelable { @StyleRes int styleRes) { TypedArray typedArray = context.obtainStyledAttributes( - styleRes, R.styleable.mapbox_LocationComponent); + styleRes, R.styleable.mapbox_LocationComponent); LocationComponentOptions.Builder builder = new LocationComponentOptions.Builder() - .enableStaleState(true) - .staleStateTimeout(STALE_STATE_DELAY_MS) - .maxZoomIconScale(MAX_ZOOM_ICON_SCALE_DEFAULT) - .minZoomIconScale(MIN_ZOOM_ICON_SCALE_DEFAULT) - .padding(PADDING_DEFAULT); + .enableStaleState(true) + .staleStateTimeout(STALE_STATE_DELAY_MS) + .maxZoomIconScale(MAX_ZOOM_ICON_SCALE_DEFAULT) + .minZoomIconScale(MIN_ZOOM_ICON_SCALE_DEFAULT) + .padding(PADDING_DEFAULT); builder.foregroundDrawable(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawable, -1)); + R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawable, -1)); if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_foregroundTintColor)) { builder.foregroundTintColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_foregroundTintColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_foregroundTintColor, -1)); } builder.backgroundDrawable(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawable, -1)); + R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawable, -1)); if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_backgroundTintColor)) { builder.backgroundTintColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_backgroundTintColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_backgroundTintColor, -1)); } builder.foregroundDrawableStale(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawableStale, -1)); + R.styleable.mapbox_LocationComponent_mapbox_foregroundDrawableStale, -1)); if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_foregroundStaleTintColor)) { builder.foregroundStaleTintColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_foregroundStaleTintColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_foregroundStaleTintColor, -1)); } builder.backgroundDrawableStale(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawableStale, -1)); + R.styleable.mapbox_LocationComponent_mapbox_backgroundDrawableStale, -1)); if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_backgroundStaleTintColor)) { builder.backgroundStaleTintColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_backgroundStaleTintColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_backgroundStaleTintColor, -1)); } builder.bearingDrawable(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_bearingDrawable, -1)); + R.styleable.mapbox_LocationComponent_mapbox_bearingDrawable, -1)); if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_bearingTintColor)) { builder.bearingTintColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_bearingTintColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_bearingTintColor, -1)); } if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_enableStaleState)) { builder.enableStaleState(typedArray.getBoolean( - R.styleable.mapbox_LocationComponent_mapbox_enableStaleState, true)); + R.styleable.mapbox_LocationComponent_mapbox_enableStaleState, true)); } if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_staleStateTimeout)) { builder.staleStateTimeout(typedArray.getInteger( - R.styleable.mapbox_LocationComponent_mapbox_staleStateTimeout, (int) STALE_STATE_DELAY_MS)); + R.styleable.mapbox_LocationComponent_mapbox_staleStateTimeout, (int) STALE_STATE_DELAY_MS)); } builder.gpsDrawable(typedArray.getResourceId( - R.styleable.mapbox_LocationComponent_mapbox_gpsDrawable, -1)); + R.styleable.mapbox_LocationComponent_mapbox_gpsDrawable, -1)); float elevation = typedArray.getDimension( - R.styleable.mapbox_LocationComponent_mapbox_elevation, 0); + R.styleable.mapbox_LocationComponent_mapbox_elevation, 0); builder.accuracyColor(typedArray.getColor( - R.styleable.mapbox_LocationComponent_mapbox_accuracyColor, -1)); + R.styleable.mapbox_LocationComponent_mapbox_accuracyColor, -1)); builder.accuracyAlpha(typedArray.getFloat( - R.styleable.mapbox_LocationComponent_mapbox_accuracyAlpha, ACCURACY_ALPHA_DEFAULT)); + R.styleable.mapbox_LocationComponent_mapbox_accuracyAlpha, ACCURACY_ALPHA_DEFAULT)); builder.elevation(elevation); builder.trackingGesturesManagement(typedArray.getBoolean( - R.styleable.mapbox_LocationComponent_mapbox_trackingGesturesManagement, false)); + R.styleable.mapbox_LocationComponent_mapbox_trackingGesturesManagement, false)); builder.trackingInitialMoveThreshold(typedArray.getDimension( - R.styleable.mapbox_LocationComponent_mapbox_trackingInitialMoveThreshold, - context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingInitialMoveThreshold))); + R.styleable.mapbox_LocationComponent_mapbox_trackingInitialMoveThreshold, + context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingInitialMoveThreshold))); builder.trackingMultiFingerMoveThreshold(typedArray.getDimension( - R.styleable.mapbox_LocationComponent_mapbox_trackingMultiFingerMoveThreshold, - context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold))); + R.styleable.mapbox_LocationComponent_mapbox_trackingMultiFingerMoveThreshold, + context.getResources().getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold))); - builder.padding(new int[] { - typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingLeft, 0), - typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingTop, 0), - typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingRight, 0), - typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingBottom, 0), + builder.padding(new int[]{ + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingLeft, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingTop, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingRight, 0), + typedArray.getInt(R.styleable.mapbox_LocationComponent_mapbox_iconPaddingBottom, 0), }); builder.layerAbove( - typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_above)); + typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_above)); builder.layerBelow( - typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_below)); + typedArray.getString(R.styleable.mapbox_LocationComponent_mapbox_layer_below)); float minScale = typedArray.getFloat( - R.styleable.mapbox_LocationComponent_mapbox_minZoomIconScale, MIN_ZOOM_ICON_SCALE_DEFAULT); + R.styleable.mapbox_LocationComponent_mapbox_minZoomIconScale, MIN_ZOOM_ICON_SCALE_DEFAULT); float maxScale = typedArray.getFloat( - R.styleable.mapbox_LocationComponent_mapbox_maxZoomIconScale, MAX_ZOOM_ICON_SCALE_DEFAULT); + R.styleable.mapbox_LocationComponent_mapbox_maxZoomIconScale, MAX_ZOOM_ICON_SCALE_DEFAULT); builder.minZoomIconScale(minScale); builder.maxZoomIconScale(maxScale); float trackingAnimationDurationMultiplier = typedArray.getFloat( - R.styleable.mapbox_LocationComponent_mapbox_trackingAnimationDurationMultiplier, - TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT + R.styleable.mapbox_LocationComponent_mapbox_trackingAnimationDurationMultiplier, + TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT ); builder.trackingAnimationDurationMultiplier(trackingAnimationDurationMultiplier); builder.compassAnimationEnabled = typedArray.getBoolean( - R.styleable.mapbox_LocationComponent_mapbox_compassAnimationEnabled, true + R.styleable.mapbox_LocationComponent_mapbox_compassAnimationEnabled, true ); builder.accuracyAnimationEnabled = typedArray.getBoolean( - R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true + R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true ); + builder.pulseEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleEnabled, false + ); + + builder.pulseFadeEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleFadeEnabled, true + ); + + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleColor)) { + builder.pulseColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleColor, + -1)); + } + + builder.pulseSingleDuration = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleDuration, CIRCLE_PULSING_DURATION_DEFAULT_MS + ); + + builder.pulseMaxRadius = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleRadius, CIRCLE_PULSING_MAX_RADIUS_DEFAULT + ); + + builder.pulseAlpha = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleAlpha, CIRCLE_PULSING_ALPHA_DEFAULT); + typedArray.recycle(); return builder.build(); @@ -330,7 +394,7 @@ public class LocationComponentOptions implements Parcelable { @NonNull public static Builder builder(@NonNull Context context) { return LocationComponentOptions.createFromAttributes(context, - R.style.mapbox_LocationComponent).toBuilder(); + R.style.mapbox_LocationComponent).toBuilder(); } /** @@ -740,42 +804,114 @@ public class LocationComponentOptions implements Parcelable { return accuracyAnimationEnabled; } + /** + * Enable or disable the LocationComponent's pulsing circle. + * + * @return whether the LocationComponent's pulsing circle is enabled + */ + public Boolean pulseEnabled() { + return pulseEnabled; + } + + /** + * Enable or disable fading of the LocationComponent's pulsing circle. If it fades, the circle's + * opacity decreases as its radius increases. + * + * @return whether fading of the LocationComponent's pulsing circle is enabled + */ + public Boolean pulseFadeEnabled() { + return pulseFadeEnabled; + } + + /** + * Color of the LocationComponent's pulsing circle as it pulses. + * + * @return the current set color of the circle + */ + public Integer pulseColor() { + return pulseColor; + } + + /** + * The number of milliseconds it takes for a single pulse of the LocationComponent's pulsing circle. + * + * @return the current set length of time for a single pulse + */ + public float pulseSingleDuration() { + return pulseSingleDuration; + } + + /** + * The maximum radius that a single pulse should expand the LocationComponent's pulsing circle to. + * + * @return the maximum radius that the pulsing circle will expand to. + */ + public float pulseMaxRadius() { + return pulseMaxRadius; + } + + /** + * The opacity of the LocationComponent's circle as it pulses. The expected range is + * 0 to 1. An opacity of 1 makes the layer fully visible. + * + * @return the current opacity of the LocationComponent's pulsing circle + */ + public float pulseAlpha() { + return pulseAlpha; + } + + /** + * The interpolator type of animation for the movement of the LocationComponent's circle + * + * @return the current set type of animation interpolator for the pulsing circle + */ + @Nullable + public Interpolator pulseInterpolator() { + return pulseInterpolator; + } + @NonNull @Override public String toString() { return "LocationComponentOptions{" - + "accuracyAlpha=" + accuracyAlpha + ", " - + "accuracyColor=" + accuracyColor + ", " - + "backgroundDrawableStale=" + backgroundDrawableStale + ", " - + "backgroundStaleName=" + backgroundStaleName + ", " - + "foregroundDrawableStale=" + foregroundDrawableStale + ", " - + "foregroundStaleName=" + foregroundStaleName + ", " - + "gpsDrawable=" + gpsDrawable + ", " - + "gpsName=" + gpsName + ", " - + "foregroundDrawable=" + foregroundDrawable + ", " - + "foregroundName=" + foregroundName + ", " - + "backgroundDrawable=" + backgroundDrawable + ", " - + "backgroundName=" + backgroundName + ", " - + "bearingDrawable=" + bearingDrawable + ", " - + "bearingName=" + bearingName + ", " - + "bearingTintColor=" + bearingTintColor + ", " - + "foregroundTintColor=" + foregroundTintColor + ", " - + "backgroundTintColor=" + backgroundTintColor + ", " - + "foregroundStaleTintColor=" + foregroundStaleTintColor + ", " - + "backgroundStaleTintColor=" + backgroundStaleTintColor + ", " - + "elevation=" + elevation + ", " - + "enableStaleState=" + enableStaleState + ", " - + "staleStateTimeout=" + staleStateTimeout + ", " - + "padding=" + Arrays.toString(padding) + ", " - + "maxZoomIconScale=" + maxZoomIconScale + ", " - + "minZoomIconScale=" + minZoomIconScale + ", " - + "trackingGesturesManagement=" + trackingGesturesManagement + ", " - + "trackingInitialMoveThreshold=" + trackingInitialMoveThreshold + ", " - + "trackingMultiFingerMoveThreshold=" + trackingMultiFingerMoveThreshold + ", " - + "layerAbove=" + layerAbove - + "layerBelow=" + layerBelow - + "trackingAnimationDurationMultiplier=" + trackingAnimationDurationMultiplier - + "}"; + + "accuracyAlpha=" + accuracyAlpha + ", " + + "accuracyColor=" + accuracyColor + ", " + + "backgroundDrawableStale=" + backgroundDrawableStale + ", " + + "backgroundStaleName=" + backgroundStaleName + ", " + + "foregroundDrawableStale=" + foregroundDrawableStale + ", " + + "foregroundStaleName=" + foregroundStaleName + ", " + + "gpsDrawable=" + gpsDrawable + ", " + + "gpsName=" + gpsName + ", " + + "foregroundDrawable=" + foregroundDrawable + ", " + + "foregroundName=" + foregroundName + ", " + + "backgroundDrawable=" + backgroundDrawable + ", " + + "backgroundName=" + backgroundName + ", " + + "bearingDrawable=" + bearingDrawable + ", " + + "bearingName=" + bearingName + ", " + + "bearingTintColor=" + bearingTintColor + ", " + + "foregroundTintColor=" + foregroundTintColor + ", " + + "backgroundTintColor=" + backgroundTintColor + ", " + + "foregroundStaleTintColor=" + foregroundStaleTintColor + ", " + + "backgroundStaleTintColor=" + backgroundStaleTintColor + ", " + + "elevation=" + elevation + ", " + + "enableStaleState=" + enableStaleState + ", " + + "staleStateTimeout=" + staleStateTimeout + ", " + + "padding=" + Arrays.toString(padding) + ", " + + "maxZoomIconScale=" + maxZoomIconScale + ", " + + "minZoomIconScale=" + minZoomIconScale + ", " + + "trackingGesturesManagement=" + trackingGesturesManagement + ", " + + "trackingInitialMoveThreshold=" + trackingInitialMoveThreshold + ", " + + "trackingMultiFingerMoveThreshold=" + trackingMultiFingerMoveThreshold + ", " + + "layerAbove=" + layerAbove + + "layerBelow=" + layerBelow + + "trackingAnimationDurationMultiplier=" + trackingAnimationDurationMultiplier + + "pulseEnabled=" + pulseEnabled + + "pulseFadeEnabled=" + pulseFadeEnabled + + "pulseColor=" + pulseColor + + "pulseSingleDuration=" + pulseSingleDuration + + "pulseMaxRadius=" + pulseMaxRadius + + "pulseAlpha=" + pulseAlpha + + "}"; } @Override @@ -847,11 +983,11 @@ public class LocationComponentOptions implements Parcelable { return false; } if (backgroundStaleName != null ? !backgroundStaleName.equals(options.backgroundStaleName) : - options.backgroundStaleName != null) { + options.backgroundStaleName != null) { return false; } if (foregroundStaleName != null ? !foregroundStaleName.equals(options.foregroundStaleName) : - options.foregroundStaleName != null) { + options.foregroundStaleName != null) { return false; } if (gpsName != null ? !gpsName.equals(options.gpsName) : options.gpsName != null) { @@ -867,23 +1003,23 @@ public class LocationComponentOptions implements Parcelable { return false; } if (bearingTintColor != null ? !bearingTintColor.equals(options.bearingTintColor) : - options.bearingTintColor != null) { + options.bearingTintColor != null) { return false; } if (foregroundTintColor != null ? !foregroundTintColor.equals(options.foregroundTintColor) : - options.foregroundTintColor != null) { + options.foregroundTintColor != null) { return false; } if (backgroundTintColor != null ? !backgroundTintColor.equals(options.backgroundTintColor) : - options.backgroundTintColor != null) { + options.backgroundTintColor != null) { return false; } if (foregroundStaleTintColor != null ? !foregroundStaleTintColor.equals(options.foregroundStaleTintColor) : - options.foregroundStaleTintColor != null) { + options.foregroundStaleTintColor != null) { return false; } if (backgroundStaleTintColor != null ? !backgroundStaleTintColor.equals(options.backgroundStaleTintColor) : - options.backgroundStaleTintColor != null) { + options.backgroundStaleTintColor != null) { return false; } if (!Arrays.equals(padding, options.padding)) { @@ -892,6 +1028,31 @@ public class LocationComponentOptions implements Parcelable { if (layerAbove != null ? !layerAbove.equals(options.layerAbove) : options.layerAbove != null) { return false; } + + if (pulseEnabled != options.pulseEnabled) { + return false; + } + + if (pulseFadeEnabled != options.pulseFadeEnabled) { + return false; + } + + if (pulseColor != null ? !pulseColor.equals(options.pulseColor) : + options.pulseColor() != null) { + return false; + } + if (Float.compare(options.pulseSingleDuration, pulseSingleDuration) != 0) { + return false; + } + + if (Float.compare(options.pulseMaxRadius, pulseMaxRadius) != 0) { + return false; + } + + if (Float.compare(options.pulseAlpha, pulseAlpha) != 0) { + return false; + } + return layerBelow != null ? layerBelow.equals(options.layerBelow) : options.layerBelow == null; } @@ -924,57 +1085,70 @@ public class LocationComponentOptions implements Parcelable { result = 31 * result + (minZoomIconScale != +0.0f ? Float.floatToIntBits(minZoomIconScale) : 0); result = 31 * result + (trackingGesturesManagement ? 1 : 0); result = 31 * result + (trackingInitialMoveThreshold != +0.0f - ? Float.floatToIntBits(trackingInitialMoveThreshold) : 0); + ? Float.floatToIntBits(trackingInitialMoveThreshold) : 0); result = 31 * result + (trackingMultiFingerMoveThreshold != +0.0f - ? Float.floatToIntBits(trackingMultiFingerMoveThreshold) : 0); + ? Float.floatToIntBits(trackingMultiFingerMoveThreshold) : 0); result = 31 * result + (layerAbove != null ? layerAbove.hashCode() : 0); result = 31 * result + (layerBelow != null ? layerBelow.hashCode() : 0); result = 31 * result + (trackingAnimationDurationMultiplier != +0.0f - ? Float.floatToIntBits(trackingAnimationDurationMultiplier) : 0); + ? Float.floatToIntBits(trackingAnimationDurationMultiplier) : 0); result = 31 * result + (compassAnimationEnabled ? 1 : 0); result = 31 * result + (accuracyAnimationEnabled ? 1 : 0); + result = 31 * result + (pulseEnabled ? 1 : 0); + result = 31 * result + (pulseFadeEnabled ? 1 : 0); + result = 31 * result + (pulseColor != null ? pulseColor.hashCode() : 0); + result = 31 * result + (pulseSingleDuration != +0.0f ? Float.floatToIntBits(pulseSingleDuration) : 0); + result = 31 * result + (pulseMaxRadius != +0.0f ? Float.floatToIntBits(pulseMaxRadius) : 0); + result = 31 * result + (pulseAlpha != +0.0f ? Float.floatToIntBits(pulseAlpha) : 0); return result; } public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + new Parcelable.Creator() { @Override - public LocationComponentOptions createFromParcel(Parcel in) { + public LocationComponentOptions createFromParcel(Parcel in) { return new LocationComponentOptions( - in.readFloat(), - in.readInt(), - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt(), - in.readInt() == 0 ? in.readString() : null, - in.readInt() == 0 ? in.readInt() : null, - in.readInt() == 0 ? in.readInt() : null, - in.readInt() == 0 ? in.readInt() : null, - in.readInt() == 0 ? in.readInt() : null, - in.readInt() == 0 ? in.readInt() : null, - in.readFloat(), - in.readInt() == 1, - in.readLong(), - in.createIntArray(), - in.readFloat(), - in.readFloat(), - in.readInt() == 1, - in.readFloat(), - in.readFloat(), - in.readString(), - in.readString(), - in.readFloat(), - in.readInt() == 1, - in.readInt() == 1 - ); + in.readFloat(), + in.readInt(), + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt(), + in.readInt() == 0 ? in.readString() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readInt() == 0 ? in.readInt() : null, + in.readFloat(), + in.readInt() == 1, + in.readLong(), + in.createIntArray(), + in.readFloat(), + in.readFloat(), + in.readInt() == 1, + in.readFloat(), + in.readFloat(), + in.readString(), + in.readString(), + in.readFloat(), + in.readInt() == 1, + in.readInt() == 1, + in.readInt() == 1, + in.readInt() == 1, + in.readInt() == 0 ? in.readInt() : null, + in.readFloat(), + in.readFloat(), + in.readFloat(), + null + ); } @Override @@ -1073,6 +1247,17 @@ public class LocationComponentOptions implements Parcelable { dest.writeFloat(trackingAnimationDurationMultiplier); dest.writeInt(compassAnimationEnabled() ? 1 : 0); dest.writeInt(accuracyAnimationEnabled() ? 1 : 0); + dest.writeInt(pulseEnabled() ? 1 : 0); + dest.writeInt(pulseFadeEnabled() ? 1 : 0); + if (pulseColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(pulseColor()); + } + dest.writeFloat(pulseSingleDuration()); + dest.writeFloat(pulseMaxRadius()); + dest.writeFloat(pulseAlpha()); } @Override @@ -1095,19 +1280,45 @@ public class LocationComponentOptions implements Parcelable { LocationComponentOptions locationComponentOptions = autoBuild(); if (locationComponentOptions.accuracyAlpha() < 0 || locationComponentOptions.accuracyAlpha() > 1) { throw new IllegalArgumentException( - "Accuracy alpha value must be between 0.0 and 1.0."); + "Accuracy alpha value must be between 0.0 and 1.0."); } if (locationComponentOptions.elevation() < 0f) { throw new IllegalArgumentException("Invalid shadow size " - + locationComponentOptions.elevation() + ". Must be >= 0"); + + locationComponentOptions.elevation() + ". Must be >= 0"); } if (locationComponentOptions.layerAbove() != null && locationComponentOptions.layerBelow() != null) { throw new IllegalArgumentException("You cannot set both layerAbove and layerBelow options." - + "Choose one or the other."); + + " Choose one or the other."); } + if (locationComponentOptions.pulseEnabled() == null) { + String pulsingSetupError = ""; + if (locationComponentOptions.pulseFadeEnabled() != null) { + pulsingSetupError += " pulseFadeEnabled"; + } + if (locationComponentOptions.pulseColor() != null) { + pulsingSetupError += " pulseColor"; + } + if (locationComponentOptions.pulseSingleDuration() > 0) { + pulsingSetupError += " pulseSingleDuration"; + } + if (locationComponentOptions.pulseMaxRadius() > 0) { + pulsingSetupError += " pulseMaxRadius"; + } + if (locationComponentOptions.pulseAlpha() >= 0 && locationComponentOptions.pulseAlpha() <= 1) { + pulsingSetupError += " pulseAlpha"; + } + if (locationComponentOptions.pulseInterpolator() != null) { + pulsingSetupError += " pulseInterpolator"; + } + if (!pulsingSetupError.isEmpty()) { + throw new IllegalStateException("You've set up the following pulsing circle options but have not enabled" + + " the pulsing circle via the LocationComponentOptions builder:" + pulsingSetupError + + ". Enable the pulsing circle if you're going to set pulsing options."); + } + } return locationComponentOptions; } @@ -1156,6 +1367,14 @@ public class LocationComponentOptions implements Parcelable { private Float trackingAnimationDurationMultiplier; private Boolean compassAnimationEnabled; private Boolean accuracyAnimationEnabled; + private Boolean pulseEnabled; + private Boolean pulseFadeEnabled; + private int pulseColor; + private float pulseSingleDuration; + private float pulseMaxRadius; + private float pulseAlpha; + @Nullable + private Interpolator pulseInterpolator; Builder() { } @@ -1194,6 +1413,13 @@ public class LocationComponentOptions implements Parcelable { this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); this.compassAnimationEnabled = source.compassAnimationEnabled(); this.accuracyAnimationEnabled = source.accuracyAnimationEnabled(); + this.pulseEnabled = source.pulseEnabled; + this.pulseFadeEnabled = source.pulseFadeEnabled; + this.pulseColor = source.pulseColor; + this.pulseSingleDuration = source.pulseSingleDuration; + this.pulseMaxRadius = source.pulseMaxRadius; + this.pulseAlpha = source.pulseAlpha; + this.pulseInterpolator = source.pulseInterpolator; } /** @@ -1653,7 +1879,7 @@ public class LocationComponentOptions implements Parcelable { */ @NonNull public LocationComponentOptions.Builder trackingAnimationDurationMultiplier( - float trackingAnimationDurationMultiplier) { + float trackingAnimationDurationMultiplier) { this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; return this; } @@ -1674,11 +1900,85 @@ public class LocationComponentOptions implements Parcelable { * * @return whether smooth animation of the accuracy circle is enabled */ - public Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { + public LocationComponentOptions.Builder accuracyAnimationEnabled(boolean accuracyAnimationEnabled) { this.accuracyAnimationEnabled = accuracyAnimationEnabled; return this; } + /** + * Enable or disable the LocationComponent's pulsing circle. + * + * @return whether the LocationComponent's pulsing circle is enabled + */ + public LocationComponentOptions.Builder pulseEnabled(boolean pulseEnabled) { + this.pulseEnabled = pulseEnabled; + return this; + } + + /** + * Enable or disable fading of the LocationComponent's pulsing circle. If it fades, the circle's + * opacity decreases as its radius increases. + * + * @return whether fading of the LocationComponent's pulsing circle is enabled + */ + public LocationComponentOptions.Builder pulseFadeEnabled(boolean pulseFadeEnabled) { + this.pulseFadeEnabled = pulseFadeEnabled; + return this; + } + + /** + * Sets the color of the LocationComponent's pulsing circle. + * + * @return the current set color of the circle + */ + public LocationComponentOptions.Builder pulseColor(@ColorInt int pulseColor) { + this.pulseColor = pulseColor; + return this; + } + + /** + * Sets the number of milliseconds it takes for a single pulse of the LocationComponent's pulsing circle. + * + * @return the current set length of time for a single pulse + */ + public LocationComponentOptions.Builder pulseSingleDuration(float pulseSingleDuration) { + this.pulseSingleDuration = pulseSingleDuration; + return this; + } + + /** + * The maximum radius that a single pulse should expand the LocationComponent's pulsing circle to. + * + * @return the maximum radius that the pulsing circle will expand to. + */ + public LocationComponentOptions.Builder pulseMaxRadius(float pulseMaxRadius) { + this.pulseMaxRadius = pulseMaxRadius; + return this; + } + + /** + * Sets the opacity of the LocationComponent's pulsing circle. The expected range is + * 0 to 1. An opacity of 1 makes the layer fully visible. + * + * @return the current opacity of the LocationComponent's pulsing circle + */ + public LocationComponentOptions.Builder pulseAlpha(float pulseAlpha) { + this.pulseAlpha = pulseAlpha; + return this; + } + + /** + * Sets the pulsing circle's interpolator animation. + * + * @param pulseInterpolator the type of Android-system interpolator to use when + * creating the pulsing animation + * @return a String which represents the interpolator animation that the pulsing circle will use. + */ + public LocationComponentOptions.Builder pulseInterpolator(Interpolator pulseInterpolator) { + this.pulseInterpolator = pulseInterpolator; + return this; + } + @Nullable LocationComponentOptions autoBuild() { String missing = ""; @@ -1740,39 +2040,46 @@ public class LocationComponentOptions implements Parcelable { throw new IllegalStateException("Missing required properties:" + missing); } return new LocationComponentOptions( - this.accuracyAlpha, - this.accuracyColor, - this.backgroundDrawableStale, - this.backgroundStaleName, - this.foregroundDrawableStale, - this.foregroundStaleName, - this.gpsDrawable, - this.gpsName, - this.foregroundDrawable, - this.foregroundName, - this.backgroundDrawable, - this.backgroundName, - this.bearingDrawable, - this.bearingName, - this.bearingTintColor, - this.foregroundTintColor, - this.backgroundTintColor, - this.foregroundStaleTintColor, - this.backgroundStaleTintColor, - this.elevation, - this.enableStaleState, - this.staleStateTimeout, - this.padding, - this.maxZoomIconScale, - this.minZoomIconScale, - trackingGesturesManagement, - this.trackingInitialMoveThreshold, - this.trackingMultiFingerMoveThreshold, - this.layerAbove, - this.layerBelow, - this.trackingAnimationDurationMultiplier, - this.compassAnimationEnabled, - this.accuracyAnimationEnabled); + this.accuracyAlpha, + this.accuracyColor, + this.backgroundDrawableStale, + this.backgroundStaleName, + this.foregroundDrawableStale, + this.foregroundStaleName, + this.gpsDrawable, + this.gpsName, + this.foregroundDrawable, + this.foregroundName, + this.backgroundDrawable, + this.backgroundName, + this.bearingDrawable, + this.bearingName, + this.bearingTintColor, + this.foregroundTintColor, + this.backgroundTintColor, + this.foregroundStaleTintColor, + this.backgroundStaleTintColor, + this.elevation, + this.enableStaleState, + this.staleStateTimeout, + this.padding, + this.maxZoomIconScale, + this.minZoomIconScale, + trackingGesturesManagement, + this.trackingInitialMoveThreshold, + this.trackingMultiFingerMoveThreshold, + this.layerAbove, + this.layerBelow, + this.trackingAnimationDurationMultiplier, + this.compassAnimationEnabled, + this.accuracyAnimationEnabled, + this.pulseEnabled, + this.pulseFadeEnabled, + this.pulseColor, + this.pulseSingleDuration, + this.pulseMaxRadius, + this.pulseAlpha, + this.pulseInterpolator); } } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index 656191ddb..d2f3c478e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -98,6 +98,7 @@ final class LocationLayerController { styleBitmaps(options); locationLayerRenderer.styleAccuracy(options.accuracyAlpha(), options.accuracyColor()); styleScaling(options); + locationLayerRenderer.stylePulsingCircle(options); determineIconsSource(options); if (!isHidden) { @@ -258,7 +259,7 @@ final class LocationLayerController { public void onNewAnimationValue(LatLng value) { locationLayerRenderer.setLatLng(value); } - }; + }; private final MapboxAnimator.AnimationsValueChangeListener gpsBearingValueListener = new MapboxAnimator.AnimationsValueChangeListener() { @@ -266,7 +267,7 @@ final class LocationLayerController { public void onNewAnimationValue(Float value) { locationLayerRenderer.setGpsBearing(value); } - }; + }; private final MapboxAnimator.AnimationsValueChangeListener compassBearingValueListener = new MapboxAnimator.AnimationsValueChangeListener() { @@ -274,7 +275,7 @@ final class LocationLayerController { public void onNewAnimationValue(Float value) { locationLayerRenderer.setCompassBearing(value); } - }; + }; private final MapboxAnimator.AnimationsValueChangeListener accuracyValueListener = new MapboxAnimator.AnimationsValueChangeListener() { @@ -282,7 +283,22 @@ final class LocationLayerController { public void onNewAnimationValue(Float value) { locationLayerRenderer.setAccuracyRadius(value); } - }; + }; + + /** + * The listener that handles the updating of the pulsing circle's radius and opacity. + */ + private final MapboxAnimator.AnimationsValueChangeListener pulsingCircleRadiusListener = + new MapboxAnimator.AnimationsValueChangeListener() { + @Override + public void onNewAnimationValue(Float newPulseRadiusValue) { + Float newPulseOpacityValue = null; + if (options.pulseFadeEnabled()) { + newPulseOpacityValue = (float) 1 - ((newPulseRadiusValue / 100) * 3); + } + locationLayerRenderer.updatePulsingUi(newPulseRadiusValue, newPulseOpacityValue); + } + }; Set getAnimationListeners() { Set holders = new HashSet<>(); @@ -299,6 +315,10 @@ final class LocationLayerController { holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_ACCURACY, accuracyValueListener)); } + if (options.pulseEnabled()) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_PULSING_CIRCLE, + pulsingCircleRadiusListener)); + } return holders; } @@ -311,4 +331,8 @@ final class LocationLayerController { void cameraTiltUpdated(double tilt) { locationLayerRenderer.cameraTiltUpdated(tilt); } + + void adjustPulsingCircleLayerVisibility(boolean visible) { + locationLayerRenderer.adjustPulsingCircleLayerVisibility(visible); + } } \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java index 01d4d1272..13333372e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerRenderer.java @@ -38,6 +38,12 @@ interface LocationLayerRenderer { void setLocationStale(boolean isStale, int renderMode); + void adjustPulsingCircleLayerVisibility(boolean visible); + + void stylePulsingCircle(LocationComponentOptions options); + + void updatePulsingUi(float radius, @Nullable Float opacity); + void updateIconIds(String foregroundIconString, String foregroundStaleIconString, String backgroundIconString, String backgroundStaleIconString, String bearingIconString); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index 694594fa6..82853ef8c 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -28,7 +28,8 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. ANIMATOR_CAMERA_COMPASS_BEARING, ANIMATOR_LAYER_ACCURACY, ANIMATOR_ZOOM, - ANIMATOR_TILT + ANIMATOR_TILT, + ANIMATOR_PULSING_CIRCLE }) @interface Type { } @@ -42,6 +43,7 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. static final int ANIMATOR_LAYER_ACCURACY = 6; static final int ANIMATOR_ZOOM = 7; static final int ANIMATOR_TILT = 8; + static final int ANIMATOR_PULSING_CIRCLE = 9; private final AnimationsValueChangeListener updateListener; private final K target; @@ -68,6 +70,15 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. addListener(new AnimatorListener()); } + public MapboxAnimator(AnimationsValueChangeListener updateListener, K target, K animatedValue, + double minUpdateInterval, long timeElapsed) { + this.updateListener = updateListener; + this.target = target; + this.animatedValue = animatedValue; + this.minUpdateInterval = minUpdateInterval; + this.timeElapsed = timeElapsed; + } + @Override public void onAnimationUpdate(ValueAnimator animation) { animatedValue = (K) animation.getAnimatedValue(); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java index c1109b959..16324f18a 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java @@ -1,5 +1,8 @@ package com.mapbox.mapboxsdk.location; +import android.animation.ValueAnimator; +import android.view.animation.Interpolator; + import androidx.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -35,4 +38,31 @@ final class MapboxAnimatorProvider { @Nullable MapboxMap.CancelableCallback cancelableCallback) { return new MapboxCameraAnimatorAdapter(values, updateListener, cancelableCallback); } + + /** + * This animator is for the LocationComponent pulsing circle. + * + * @param updateListener the listener that is found in the {@link LocationAnimatorCoordinator}'s + * listener array. + * @param maxAnimationFps the max frames per second of the pulsing animation + * @param pulseSingleDuration the number of milliseconds it takes for the animator to create + * a single pulse. + * @param pulseMaxRadius the max radius when the circle is finished with a single pulse. + * @param pulseInterpolator the type of Android-system interpolator to use for + * the pulsing animation (linear, accelerate, bounce, etc.) + * @return a built {@link PulsingLocationCircleAnimator} object. + */ + PulsingLocationCircleAnimator pulsingCircleAnimator(MapboxAnimator.AnimationsValueChangeListener updateListener, + int maxAnimationFps, + float pulseSingleDuration, + float pulseMaxRadius, + Interpolator pulseInterpolator) { + PulsingLocationCircleAnimator pulsingLocationCircleAnimator = + new PulsingLocationCircleAnimator(updateListener, maxAnimationFps, pulseMaxRadius); + pulsingLocationCircleAnimator.setDuration((long) pulseSingleDuration); + pulsingLocationCircleAnimator.setRepeatMode(ValueAnimator.RESTART); + pulsingLocationCircleAnimator.setRepeatCount(ValueAnimator.INFINITE); + pulsingLocationCircleAnimator.setInterpolator(pulseInterpolator); + return pulsingLocationCircleAnimator; + } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java index af7a73644..40bdf67be 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java @@ -2,9 +2,10 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; import android.animation.AnimatorSet; -import androidx.annotation.NonNull; import android.view.animation.Interpolator; +import androidx.annotation.NonNull; + import java.util.List; class MapboxAnimatorSetProvider { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java new file mode 100644 index 000000000..1f09f6c4d --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java @@ -0,0 +1,19 @@ +package com.mapbox.mapboxsdk.location; + +/** + * Manages the logic of the interpolated animation which is applied to the LocationComponent's pulsing circle + */ +public class PulsingLocationCircleAnimator extends MapboxFloatAnimator { + + /** + * + * @param updateListener the {@link AnimationsValueChangeListener} associated with this animator. + * @param maxAnimationFps the maximum frames per second that the animator should use. Default + * is the {@link LocationAnimatorCoordinator#maxAnimationFps} variable. + */ + public PulsingLocationCircleAnimator(AnimationsValueChangeListener updateListener, + int maxAnimationFps, + float circleMaxRadius) { + super(new Float[]{0f, circleMaxRadius}, updateListener, maxAnimationFps); + } +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java index ae722b3d2..bd6151617 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/SymbolLocationLayerRenderer.java @@ -41,11 +41,19 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_PULSING_OPACITY; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_PULSING_RADIUS; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PULSING_CIRCLE_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; import static com.mapbox.mapboxsdk.style.layers.Property.NONE; import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; @@ -84,6 +92,7 @@ final class SymbolLocationLayerRenderer implements LocationLayerRenderer { addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); addAccuracyLayer(); + addPulsingCircleLayerToMap(); } @Override @@ -244,6 +253,42 @@ final class SymbolLocationLayerRenderer implements LocationLayerRenderer { } } + /** + * Adjust the visibility of the pulsing LocationComponent circle. + */ + @Override + public void adjustPulsingCircleLayerVisibility(boolean visible) { + setLayerVisibility(PULSING_CIRCLE_LAYER, visible); + } + + /** + * Adjust the the pulsing LocationComponent circle based on the set options. + */ + @Override + public void stylePulsingCircle(LocationComponentOptions options) { + if (style.getLayer(PULSING_CIRCLE_LAYER) != null) { + setLayerVisibility(PULSING_CIRCLE_LAYER, true); + style.getLayer(PULSING_CIRCLE_LAYER).setProperties( + circleRadius(get(PROPERTY_PULSING_RADIUS)), + circleColor(options.pulseColor()), + circleStrokeColor(options.pulseColor()), + circleOpacity(get(PROPERTY_PULSING_OPACITY)) + ); + } + } + + /** + * Adjust the visual appearance of the pulsing LocationComponent circle. + */ + @Override + public void updatePulsingUi(float radius, @Nullable Float opacity) { + locationFeature.addNumberProperty(PROPERTY_PULSING_RADIUS, radius); + if (opacity != null) { + locationFeature.addNumberProperty(PROPERTY_PULSING_OPACITY, opacity); + } + refreshSource(); + } + private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) { Layer layer = layerSourceProvider.generateLayer(layerId); addLayerToMap(layer, beforeLayerId); @@ -254,6 +299,14 @@ final class SymbolLocationLayerRenderer implements LocationLayerRenderer { addLayerToMap(accuracyLayer, BACKGROUND_LAYER); } + /** + * Add the pulsing LocationComponent circle to the map for future use, if need be. + */ + private void addPulsingCircleLayerToMap() { + Layer pulsingCircleLayer = layerSourceProvider.generatePulsingCircleLayer(); + addLayerToMap(pulsingCircleLayer, ACCURACY_LAYER); + } + private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { style.addLayerBelow(layer, idBelowLayer); layerSet.add(layer.getId()); diff --git a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index b79a5494d..a5e759f6c 100644 --- a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -165,4 +165,13 @@ + + + + + + + + + diff --git a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index 2b9022c96..4acf3301c 100644 --- a/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -188,5 +188,14 @@ + + + + + + + + + diff --git a/MapboxGLAndroidSDK/src/main/res/values/styles.xml b/MapboxGLAndroidSDK/src/main/res/values/styles.xml index c6c2d3fc7..b38b3758c 100644 --- a/MapboxGLAndroidSDK/src/main/res/values/styles.xml +++ b/MapboxGLAndroidSDK/src/main/res/values/styles.xml @@ -33,5 +33,14 @@ @dimen/mapbox_locationComponentTrackingInitialMoveThreshold @dimen/mapbox_locationComponentTrackingMultiFingerMoveThreshold + + false + true + @color/mapbox_location_layer_blue + 2300 + 35 + 0.4 + decelerate + \ No newline at end of file diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt index 7c4feb83b..bf479c973 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -35,7 +35,9 @@ class LocationAnimatorCoordinatorTest { @Before fun setUp() { - locationAnimatorCoordinator = LocationAnimatorCoordinator(projection, animatorSetProvider, animatorProvider) + locationAnimatorCoordinator = LocationAnimatorCoordinator(projection, + animatorSetProvider, + animatorProvider) configureAnimatorProvider() every { projection.getMetersPerPixelAtLatitude(any()) } answers { 1.0 } every { animatorSetProvider.startAnimation(any(), any(), any()) } answers {} diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java index d5256735c..9f4648468 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentActivationOptionsTest.java @@ -3,6 +3,9 @@ package com.mapbox.mapboxsdk.location; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Color; +import android.view.animation.LinearInterpolator; + import androidx.annotation.NonNull; import com.mapbox.mapboxsdk.R; @@ -66,6 +69,44 @@ public class LocationComponentActivationOptionsTest { assertNotNull(locationComponentActivationOptions); } + @Test + public void sanityWithDefaultPulsingCircle() throws Exception { + when(style.isFullyLoaded()).thenReturn(true); + + LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) + .accuracyAlpha(0.5f) + .pulseEnabled(true) + .build(); + assertNotNull(locationComponentOptions); + + LocationComponentActivationOptions locationComponentActivationOptions = + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(true) + .build(); + assertNotNull(locationComponentActivationOptions); + } + + @Test + public void sanityWithCustomizedPulsingCircle() throws Exception { + when(style.isFullyLoaded()).thenReturn(true); + + LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) + .accuracyAlpha(0.5f) + .pulseEnabled(true) + .pulseColor(Color.RED) + .pulseInterpolator(new LinearInterpolator()) + .build(); + assertNotNull(locationComponentOptions); + + LocationComponentActivationOptions locationComponentActivationOptions = + LocationComponentActivationOptions.builder(context, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(true) + .build(); + assertNotNull(locationComponentActivationOptions); + } + @Test public void includingBothStyleResAndComponentOptions_causesExceptionToBeThrown() throws Exception { diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java index 6e454a7f7..ccf968183 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentOptionsTest.java @@ -72,7 +72,7 @@ public class LocationComponentOptionsTest { public void passingBothLayerPositionOptions_throwsException() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("You cannot set both layerAbove and layerBelow options." - + "Choose one or the other."); + + " Choose one or the other."); LocationComponentOptions.builder(context) .layerAbove("above") .layerBelow("below") diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index 40726acbe..1d5ebb124 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -37,6 +37,7 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_ICON_OFFSET; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PULSING_CIRCLE_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURACY; @@ -167,6 +168,23 @@ public class LocationLayerControllerTest { verify(style).addLayerBelow(accuracyLayer, BACKGROUND_LAYER); } + @Test + public void onInitialization_pulsingCircleLayerIsAdded() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + Layer pulsingCircleLayer = mock(Layer.class); + when(sourceProvider.generatePulsingCircleLayer()).thenReturn(pulsingCircleLayer); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener, false); + + verify(style).addLayerBelow(pulsingCircleLayer, ACCURACY_LAYER); + } + @Test public void onInitialization_numberOfCachedLayerIdsIsConstant() { OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); @@ -184,7 +202,7 @@ public class LocationLayerControllerTest { controller.initializeComponents(mapboxMap.getStyle(), options); - assertEquals(5, layerSet.size()); + assertEquals(6, layerSet.size()); } @Test @@ -402,7 +420,7 @@ public class LocationLayerControllerTest { layerController.applyStyle(options); verify(style, times(0)).removeLayer(any(String.class)); - verify(style, times(5)).addLayerBelow(any(Layer.class), any(String.class)); + verify(style, times(6)).addLayerBelow(any(Layer.class), any(String.class)); } @Test @@ -424,7 +442,7 @@ public class LocationLayerControllerTest { verify(style, times(0)).removeLayer(any(String.class)); verify(style, times(1)).addLayer(any(Layer.class)); - verify(style, times(4)).addLayerBelow(any(Layer.class), Mockito.any()); + verify(style, times(5)).addLayerBelow(any(Layer.class), Mockito.any()); } @Test @@ -726,6 +744,9 @@ public class LocationLayerControllerTest { Layer accuracyLayer = mock(Layer.class); when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); when(layerSourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); + Layer pulsingCircleLayer = mock(Layer.class); + when(pulsingCircleLayer.getId()).thenReturn(PULSING_CIRCLE_LAYER); + when(layerSourceProvider.generatePulsingCircleLayer()).thenReturn(pulsingCircleLayer); return layerSourceProvider; } diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt index 03c395a59..6700bda76 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.location import android.Manifest import android.content.Context +import android.graphics.Color import android.location.Location import androidx.test.annotation.UiThreadTest import androidx.test.espresso.Espresso.onView @@ -123,11 +124,49 @@ class LocationLayerControllerTest : EspressoTest() { assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false)) + assertThat(mapboxMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(false)) } } executeComponentTest(componentAction) } + @Test + fun onMapChange_locationComponentPulsingCircleLayerGetsRedrawn() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent( + LocationComponentActivationOptions + .builder(context, style) + .locationComponentOptions(LocationComponentOptions.builder(context) + .pulseEnabled(true) + .build()) + .useDefaultLocationEngine(false) + .build() + ) + component.isLocationComponentEnabled = true + component.renderMode = RenderMode.NORMAL + component.forceLocationUpdate(location) + styleChangeIdlingResource.waitForStyle(mapboxMap, Style.LIGHT) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL))) + + // Check that the Source has been re-added to the new map style + val source: GeoJsonSource? = mapboxMap.style!!.getSourceAs(LOCATION_SOURCE) + assertThat(source, notNullValue()) + + // Check that the pulsing circle layer visibilities is set to visible + assertThat(mapboxMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(true)) + } + } + } + @Test fun renderModeCompass_bearingLayersDoGetAdded() { val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { @@ -159,6 +198,137 @@ class LocationLayerControllerTest : EspressoTest() { executeComponentTest(componentAction) } + @Test + fun pulsingCircle_enableLocationComponent_pulsingLayerVisibility() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent( + LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build() + ) + component.isLocationComponentEnabled = true + component.forceLocationUpdate(location) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + component.applyStyle(LocationComponentOptions.builder(context) + .pulseEnabled(true).build()) + + assertThat(mapboxMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(true)) + } + } + executeComponentTest(componentAction) + } + + @Test + fun pulsingCircle_disableLocationComponent_pulsingLayerVisibility() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent( + LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build() + ) + component.isLocationComponentEnabled = false + component.forceLocationUpdate(location) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + assertThat(mapboxMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(false)) + } + } + executeComponentTest(componentAction) + } + + @Test + fun pulsingCircle_changeColorCheck() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent( + LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build() + ) + component.isLocationComponentEnabled = true + component.forceLocationUpdate(location) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + component.applyStyle(LocationComponentOptions.builder(context) + .pulseEnabled(true) + .pulseColor(Color.RED) + .build()) + + component.applyStyle(LocationComponentOptions.builder(context) + .pulseEnabled(true) + .pulseColor(Color.BLUE) + .build()) + + mapboxMap.style.apply { + assertThat(component.locationComponentOptions.pulseColor(), `is`(Color.BLUE)) + } + } + } + executeComponentTest(componentAction) + } + + @Test + fun pulsingCircle_changeSpeedCheck() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction( + component: LocationComponent, + mapboxMap: MapboxMap, + style: Style, + uiController: UiController, + context: Context + ) { + component.activateLocationComponent( + LocationComponentActivationOptions + .builder(context, style) + .useDefaultLocationEngine(false) + .build() + ) + component.isLocationComponentEnabled = true + component.forceLocationUpdate(location) + TestingAsyncUtils.waitForLayer(uiController, mapView) + + component.applyStyle(LocationComponentOptions.builder(context) + .pulseEnabled(true) + .pulseSingleDuration(8000f) + .build()) + + component.applyStyle(LocationComponentOptions.builder(context) + .pulseEnabled(true) + .pulseSingleDuration(400f) + .build()) + + mapboxMap.style.apply { + assertThat(component.locationComponentOptions.pulseSingleDuration(), `is`(400f)) + } + } + } + executeComponentTest(componentAction) + } + @Test fun renderModeGps_navigationLayersDoGetAdded() { val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { diff --git a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt index 43e6d55f6..12bcfc78f 100644 --- a/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt +++ b/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt @@ -33,7 +33,7 @@ class StyleChangeIdlingResource : IdlingResource { fun waitForStyle(mapboxMap: MapboxMap, styleUrl: String) { isIdle = false - mapboxMap.setStyle(Style.Builder().fromUrl(styleUrl)) { + mapboxMap.setStyle(Style.Builder().fromUri(styleUrl)) { setIdle() } } diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index ba26ee8d6..5077894dd 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1015,6 +1015,28 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + + + + + { + locationComponent = mapboxMap.getLocationComponent(); + + LocationComponentOptions locationComponentOptions = + LocationComponentOptions.builder(BasicLocationPulsingCircleActivity.this) + .pulseEnabled(true) + .build(); + + LocationComponentActivationOptions locationComponentActivationOptions = + buildLocationComponentActivationOptions(style,locationComponentOptions); + + locationComponent.activateLocationComponent(locationComponentActivationOptions); + locationComponent.setLocationComponentEnabled(true); + locationComponent.setCameraMode(CameraMode.TRACKING); + locationComponent.forceLocationUpdate(lastLocation); + }); + } + + private LocationComponentActivationOptions buildLocationComponentActivationOptions(@NonNull Style style, + @NonNull LocationComponentOptions + locationComponentOptions) { + return LocationComponentActivationOptions + .builder(this, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(true) + .locationEngineRequest(new LocationEngineRequest.Builder(750) + .setFastestInterval(750) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .build()) + .build(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_pulsing_location_mode, menu); + return true; + } + + @SuppressLint("MissingPermission") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (locationComponent == null) { + return super.onOptionsItemSelected(item); + } + + int id = item.getItemId(); + if (id == R.id.action_map_style_change) { + loadNewStyle(); + return true; + } else if (id == R.id.action_component_disable) { + locationComponent.setLocationComponentEnabled(false); + return true; + } else if (id == R.id.action_component_enabled) { + locationComponent.setLocationComponentEnabled(true); + return true; + } else if (id == R.id.action_stop_pulsing) { + locationComponent.applyStyle(LocationComponentOptions.builder( + BasicLocationPulsingCircleActivity.this) + .pulseEnabled(false) + .build()); + return true; + } else if (id == R.id.action_start_pulsing) { + locationComponent.applyStyle(LocationComponentOptions.builder( + BasicLocationPulsingCircleActivity.this) + .pulseEnabled(true) + .build()); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void loadNewStyle() { + mapboxMap.setStyle(new Style.Builder().fromUri(getNextStyle())); + } + + private void checkPermissions() { + if (PermissionsManager.areLocationPermissionsGranted(this)) { + mapView.getMapAsync(this); + } else { + permissionsManager = new PermissionsManager(new PermissionsListener() { + @Override + public void onExplanationNeeded(List permissionsToExplain) { + Toast.makeText(BasicLocationPulsingCircleActivity.this, "You need to accept location permissions.", + Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean granted) { + if (granted) { + mapView.getMapAsync(BasicLocationPulsingCircleActivity.this); + } else { + finish(); + } + } + }); + permissionsManager.requestLocationPermissions(this); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @SuppressLint("MissingPermission") + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + if (locationComponent != null) { + outState.putParcelable(SAVED_STATE_LOCATION, locationComponent.getLastKnownLocation()); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/CustomizedLocationPulsingCircleActivity.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/CustomizedLocationPulsingCircleActivity.java new file mode 100644 index 000000000..0125eded6 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/CustomizedLocationPulsingCircleActivity.java @@ -0,0 +1,360 @@ +package com.mapbox.mapboxsdk.testapp.activity.location; + +import android.annotation.SuppressLint; +import android.graphics.Color; +import android.location.Location; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Toast; + +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.android.core.permissions.PermissionsListener; +import com.mapbox.android.core.permissions.PermissionsManager; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions; +import com.mapbox.mapboxsdk.location.LocationComponentOptions; +import com.mapbox.mapboxsdk.location.modes.CameraMode; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.ArrayList; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.ListPopupWindow; + +import static com.mapbox.mapboxsdk.testapp.activity.location.Utils.getNextStyle; + +/** + * This activity shows how to customize the LocationComponent's pulsing circle. + */ +public class CustomizedLocationPulsingCircleActivity extends AppCompatActivity implements OnMapReadyCallback { + + //region + + // Adjust these variables to customize the example's pulsing circle UI + private static final float DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS = 2300; + private static final float SECOND_LOCATION_CIRCLE_PULSE_DURATION_MS = 800; + private static final float THIRD_LOCATION_CIRCLE_PULSE_DURATION_MS = 8000; + private static final float DEFAULT_LOCATION_CIRCLE_PULSE_RADIUS = 35; + private static final float DEFAULT_LOCATION_CIRCLE_PULSE_ALPHA = .55f; + private static final Interpolator DEFAULT_LOCATION_CIRCLE_INTERPOLATOR_PULSE_MODE + = new DecelerateInterpolator(); + private static final boolean DEFAULT_LOCATION_CIRCLE_PULSE_FADE_MODE = true; + //endregion + + //region + private static int LOCATION_CIRCLE_PULSE_COLOR; + private static float LOCATION_CIRCLE_PULSE_DURATION = DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS; + private static final String SAVED_STATE_LOCATION = "saved_state_location"; + private static final String SAVED_STATE_LOCATION_CIRCLE_PULSE_COLOR = "saved_state_color"; + private static final String SAVED_STATE_LOCATION_CIRCLE_PULSE_DURATION = "saved_state_duration"; + private static final String LAYER_BELOW_ID = "waterway-label"; + + private Location lastLocation; + private MapView mapView; + private Button pulsingCircleDurationButton; + private Button pulsingCircleColorButton; + private PermissionsManager permissionsManager; + private LocationComponent locationComponent; + private MapboxMap mapboxMap; + private float currentPulseDuration; + //endregion + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_location_layer_customized_pulsing_circle); + + LOCATION_CIRCLE_PULSE_COLOR = Color.BLUE; + + mapView = findViewById(R.id.mapView); + + if (savedInstanceState != null) { + lastLocation = savedInstanceState.getParcelable(SAVED_STATE_LOCATION); + LOCATION_CIRCLE_PULSE_COLOR = savedInstanceState.getInt(SAVED_STATE_LOCATION_CIRCLE_PULSE_COLOR); + LOCATION_CIRCLE_PULSE_DURATION = savedInstanceState.getFloat(SAVED_STATE_LOCATION_CIRCLE_PULSE_DURATION); + } + + pulsingCircleDurationButton = findViewById(R.id.button_location_circle_duration); + pulsingCircleDurationButton.setText(String.format("%sms", + String.valueOf(LOCATION_CIRCLE_PULSE_DURATION))); + pulsingCircleDurationButton.setOnClickListener(v -> { + if (locationComponent == null) { + return; + } + showDurationListDialog(); + }); + + pulsingCircleColorButton = findViewById(R.id.button_location_circle_color); + pulsingCircleColorButton.setOnClickListener(v -> { + if (locationComponent == null) { + return; + } + showColorListDialog(); + }); + + mapView.onCreate(savedInstanceState); + + checkPermissions(); + } + + @SuppressLint("MissingPermission") + @Override + public void onMapReady(@NonNull MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + + mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { + locationComponent = mapboxMap.getLocationComponent(); + + LocationComponentOptions locationComponentOptions = + buildLocationComponentOptions( + LOCATION_CIRCLE_PULSE_COLOR, + LOCATION_CIRCLE_PULSE_DURATION) + .pulseEnabled(true) + .build(); + + LocationComponentActivationOptions locationComponentActivationOptions = + buildLocationComponentActivationOptions(style,locationComponentOptions); + + locationComponent.activateLocationComponent(locationComponentActivationOptions); + locationComponent.setLocationComponentEnabled(true); + locationComponent.setCameraMode(CameraMode.TRACKING); + locationComponent.forceLocationUpdate(lastLocation); + }); + } + + private LocationComponentOptions.Builder buildLocationComponentOptions(int pulsingCircleColor, + float pulsingCircleDuration + ) { + currentPulseDuration = pulsingCircleDuration; + return LocationComponentOptions.builder(this) + .layerBelow(LAYER_BELOW_ID) + .pulseFadeEnabled(DEFAULT_LOCATION_CIRCLE_PULSE_FADE_MODE) + .pulseInterpolator(DEFAULT_LOCATION_CIRCLE_INTERPOLATOR_PULSE_MODE) + .pulseColor(pulsingCircleColor) + .pulseAlpha(DEFAULT_LOCATION_CIRCLE_PULSE_ALPHA) + .pulseSingleDuration(pulsingCircleDuration) + .pulseMaxRadius(DEFAULT_LOCATION_CIRCLE_PULSE_RADIUS); + } + + @SuppressLint("MissingPermission") + private void setNewLocationComponentOptions(float newPulsingDuration, + int newPulsingColor) { + mapboxMap.getStyle(style -> locationComponent.applyStyle( + buildLocationComponentOptions( + newPulsingColor, + newPulsingDuration) + .pulseEnabled(true) + .build())); + } + + private LocationComponentActivationOptions buildLocationComponentActivationOptions( + @NonNull Style style, + @NonNull LocationComponentOptions locationComponentOptions) { + return LocationComponentActivationOptions + .builder(this, style) + .locationComponentOptions(locationComponentOptions) + .useDefaultLocationEngine(true) + .locationEngineRequest(new LocationEngineRequest.Builder(750) + .setFastestInterval(750) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .build()) + .build(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_pulsing_location_mode, menu); + return true; + } + + @SuppressLint("MissingPermission") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (locationComponent == null) { + return super.onOptionsItemSelected(item); + } + + int id = item.getItemId(); + if (id == R.id.action_map_style_change) { + loadNewStyle(); + return true; + } else if (id == R.id.action_component_disable) { + locationComponent.setLocationComponentEnabled(false); + return true; + } else if (id == R.id.action_component_enabled) { + locationComponent.setLocationComponentEnabled(true); + return true; + } else if (id == R.id.action_stop_pulsing) { + locationComponent.applyStyle(LocationComponentOptions.builder( + CustomizedLocationPulsingCircleActivity.this) + .pulseEnabled(false) + .build()); + return true; + } else if (id == R.id.action_start_pulsing) { + locationComponent.applyStyle(buildLocationComponentOptions( + LOCATION_CIRCLE_PULSE_COLOR, + LOCATION_CIRCLE_PULSE_DURATION) + .pulseEnabled(true) + .build()); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void loadNewStyle() { + mapboxMap.setStyle(new Style.Builder().fromUri(getNextStyle())); + } + + private void checkPermissions() { + if (PermissionsManager.areLocationPermissionsGranted(this)) { + mapView.getMapAsync(this); + } else { + permissionsManager = new PermissionsManager(new PermissionsListener() { + @Override + public void onExplanationNeeded(List permissionsToExplain) { + Toast.makeText(CustomizedLocationPulsingCircleActivity.this, "You need to accept location permissions.", + Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean granted) { + if (granted) { + mapView.getMapAsync(CustomizedLocationPulsingCircleActivity.this); + } else { + finish(); + } + } + }); + permissionsManager.requestLocationPermissions(this); + } + } + + private void showDurationListDialog() { + List modes = new ArrayList<>(); + modes.add(String.format("%sms", String.valueOf(DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS))); + modes.add(String.format("%sms", String.valueOf(SECOND_LOCATION_CIRCLE_PULSE_DURATION_MS))); + modes.add(String.format("%sms", String.valueOf(THIRD_LOCATION_CIRCLE_PULSE_DURATION_MS))); + ArrayAdapter profileAdapter = new ArrayAdapter<>(this, + android.R.layout.simple_list_item_1, modes); + ListPopupWindow listPopup = new ListPopupWindow(this); + listPopup.setAdapter(profileAdapter); + listPopup.setAnchorView(pulsingCircleDurationButton); + listPopup.setOnItemClickListener((parent, itemView, position, id) -> { + String selectedMode = modes.get(position); + pulsingCircleDurationButton.setText(selectedMode); + if (selectedMode.contentEquals(String.format("%sms", + String.valueOf(DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS)))) { + LOCATION_CIRCLE_PULSE_DURATION = DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS; + setNewLocationComponentOptions(DEFAULT_LOCATION_CIRCLE_PULSE_DURATION_MS, LOCATION_CIRCLE_PULSE_COLOR); + } else if (selectedMode.contentEquals(String.format("%sms", + String.valueOf(SECOND_LOCATION_CIRCLE_PULSE_DURATION_MS)))) { + LOCATION_CIRCLE_PULSE_DURATION = SECOND_LOCATION_CIRCLE_PULSE_DURATION_MS; + setNewLocationComponentOptions(SECOND_LOCATION_CIRCLE_PULSE_DURATION_MS, LOCATION_CIRCLE_PULSE_COLOR); + } else if (selectedMode.contentEquals(String.format("%sms", + String.valueOf(THIRD_LOCATION_CIRCLE_PULSE_DURATION_MS)))) { + LOCATION_CIRCLE_PULSE_DURATION = THIRD_LOCATION_CIRCLE_PULSE_DURATION_MS; + setNewLocationComponentOptions(THIRD_LOCATION_CIRCLE_PULSE_DURATION_MS, LOCATION_CIRCLE_PULSE_COLOR); + } + listPopup.dismiss(); + }); + listPopup.show(); + } + + private void showColorListDialog() { + List trackingTypes = new ArrayList<>(); + trackingTypes.add("Blue"); + trackingTypes.add("Red"); + trackingTypes.add("Green"); + trackingTypes.add("Gray"); + ArrayAdapter profileAdapter = new ArrayAdapter<>(this, + android.R.layout.simple_list_item_1, trackingTypes); + ListPopupWindow listPopup = new ListPopupWindow(this); + listPopup.setAdapter(profileAdapter); + listPopup.setAnchorView(pulsingCircleColorButton); + listPopup.setOnItemClickListener((parent, itemView, position, id) -> { + String selectedTrackingType = trackingTypes.get(position); + pulsingCircleColorButton.setText(selectedTrackingType); + if (selectedTrackingType.contentEquals("Blue")) { + LOCATION_CIRCLE_PULSE_COLOR = Color.BLUE; + setNewLocationComponentOptions(currentPulseDuration, Color.BLUE); + } else if (selectedTrackingType.contentEquals("Red")) { + LOCATION_CIRCLE_PULSE_COLOR = Color.RED; + setNewLocationComponentOptions(currentPulseDuration, Color.RED); + } else if (selectedTrackingType.contentEquals("Green")) { + LOCATION_CIRCLE_PULSE_COLOR = Color.GREEN; + setNewLocationComponentOptions(currentPulseDuration, Color.GREEN); + } else if (selectedTrackingType.contentEquals("Gray")) { + LOCATION_CIRCLE_PULSE_COLOR = Color.parseColor("#4a4a4a"); + setNewLocationComponentOptions(currentPulseDuration, Color.parseColor("#4a4a4a")); + } + listPopup.dismiss(); + }); + listPopup.show(); + } + + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @SuppressLint("MissingPermission") + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + if (locationComponent != null) { + outState.putParcelable(SAVED_STATE_LOCATION, locationComponent.getLastKnownLocation()); + outState.putInt(SAVED_STATE_LOCATION_CIRCLE_PULSE_COLOR, LOCATION_CIRCLE_PULSE_COLOR); + outState.putFloat(SAVED_STATE_LOCATION_CIRCLE_PULSE_DURATION, LOCATION_CIRCLE_PULSE_DURATION); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } +} \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/Utils.java b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/Utils.java index fdc2353f9..b9a8aad84 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/Utils.java +++ b/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/Utils.java @@ -10,7 +10,7 @@ import java.util.Random; import timber.log.Timber; /** - * Useful utilities used throughout the testapp. + * Useful utilities used throughout the test app. */ public class Utils { diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_basic_pulsing_circle.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_basic_pulsing_circle.xml new file mode 100644 index 000000000..9b4c82b37 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_basic_pulsing_circle.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_customized_pulsing_circle.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_customized_pulsing_circle.xml new file mode 100644 index 000000000..d277e4485 --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_layer_customized_pulsing_circle.xml @@ -0,0 +1,78 @@ + + + + + + + + + +