summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--.gitmodules2
-rw-r--r--.jazzy.yaml6
-rw-r--r--.travis.yml11
-rw-r--r--CHANGELOG.md3
-rw-r--r--Makefile23
-rw-r--r--README.md2
-rw-r--r--bin/offline.cpp76
-rw-r--r--bin/offline.gypi44
-rw-r--r--gyp/common.gypi63
-rw-r--r--gyp/core.gypi1
-rw-r--r--gyp/http-nsurl.gypi2
-rw-r--r--gyp/ios.gyp6
-rw-r--r--gyp/linux.gyp1
-rw-r--r--gyp/osx.gyp8
-rw-r--r--gyp/platform-android.gypi10
-rw-r--r--gyp/platform-ios.gypi61
-rw-r--r--gyp/platform-linux.gypi10
-rw-r--r--gyp/platform-osx.gypi58
-rw-r--r--include/mbgl/gl/gl.hpp (renamed from include/mbgl/platform/gl.hpp)30
-rw-r--r--include/mbgl/gl/gl_helper.hpp23
-rw-r--r--include/mbgl/gl/gl_values.hpp (renamed from src/mbgl/renderer/gl_config.hpp)111
-rw-r--r--include/mbgl/map/map.hpp2
-rw-r--r--include/mbgl/platform/default/glfw_view.hpp6
-rw-r--r--include/mbgl/platform/default/headless_view.hpp2
-rw-r--r--include/mbgl/storage/default_file_source.hpp87
-rw-r--r--include/mbgl/storage/offline.hpp181
-rw-r--r--include/mbgl/storage/online_file_source.hpp7
-rw-r--r--include/mbgl/storage/resource.hpp6
-rw-r--r--include/mbgl/storage/response.hpp8
-rw-r--r--include/mbgl/util/constants.hpp2
-rw-r--r--include/mbgl/util/gl_helper.hpp90
-rw-r--r--include/mbgl/util/math.hpp5
-rw-r--r--include/mbgl/util/run_loop.hpp3
-rw-r--r--ios/README.md1
-rw-r--r--ios/benchmark/MBXBenchAppDelegate.m15
-rw-r--r--package.json2
-rw-r--r--platform/android/INSTALL_LINUX.md2
-rw-r--r--platform/android/INSTALL_OSX.md2
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle5
-rw-r--r--platform/android/MapboxGLAndroidSDK/proguard-rules.pro7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java41
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java44
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java (renamed from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdate.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java (renamed from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdateFactory.java)54
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationService.java166
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java133
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java795
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java694
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java116
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java27
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java121
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java207
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java36
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java (renamed from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassView.java)20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java (renamed from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UserLocationView.java)88
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java532
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java71
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java145
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ApiAccess.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/attribution_telemetry_view.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/infowindow_content.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CameraActivityTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DirectionsActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivityTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivityTest.java33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/GeocoderActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/InfoWindowConcurrentActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/VisibleCoordinateBoundsActivityTest.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityScreenTest.java64
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityTest.java28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivityTest.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ScrollByActivityTest.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivityTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/DrawerUtils.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/GestureUtils.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ViewUtils.java15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/BulkMarkerActivity.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CameraActivity.java9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DirectionsActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivity.java145
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowAdapterActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapFragmentActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivity.java162
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivity.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MyLocationTrackingModeActivity.java40
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ScrollByActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/TiltActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarker.java18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarkerOptions.java68
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.pngbin0 -> 1178 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.pngbin0 -> 1692 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_dynamic_marker.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_map_padding.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_concurrent.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml49
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapboxmap.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java55
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java86
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java119
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolygonTest.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolylineTest.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java77
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java42
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java390
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MarkerTest.java76
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java53
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java30
-rw-r--r--platform/android/mapboxgl-app.gypi4
-rw-r--r--platform/android/src/asset_file_source.cpp4
-rw-r--r--platform/android/src/http_request_android.cpp21
-rwxr-xr-xplatform/android/src/jni.cpp51
-rwxr-xr-xplatform/android/src/native_map_view.cpp2
-rw-r--r--platform/darwin/include/MGLAnnotation.h (renamed from include/mbgl/darwin/MGLAnnotation.h)0
-rw-r--r--platform/darwin/include/MGLGeometry.h (renamed from include/mbgl/darwin/MGLGeometry.h)3
-rw-r--r--platform/darwin/include/MGLMapCamera.h (renamed from include/mbgl/darwin/MGLMapCamera.h)0
-rw-r--r--platform/darwin/include/MGLMultiPoint.h (renamed from include/mbgl/darwin/MGLMultiPoint.h)0
-rw-r--r--platform/darwin/include/MGLOverlay.h (renamed from include/mbgl/darwin/MGLOverlay.h)0
-rw-r--r--platform/darwin/include/MGLPointAnnotation.h (renamed from include/mbgl/darwin/MGLPointAnnotation.h)0
-rw-r--r--platform/darwin/include/MGLPolygon.h (renamed from include/mbgl/darwin/MGLPolygon.h)0
-rw-r--r--platform/darwin/include/MGLPolyline.h (renamed from include/mbgl/darwin/MGLPolyline.h)0
-rw-r--r--platform/darwin/include/MGLShape.h (renamed from include/mbgl/darwin/MGLShape.h)0
-rw-r--r--platform/darwin/include/MGLStyle.h (renamed from include/mbgl/darwin/MGLStyle.h)0
-rw-r--r--platform/darwin/include/MGLTypes.h (renamed from include/mbgl/darwin/MGLTypes.h)0
-rw-r--r--platform/darwin/src/MGLGeometry.mm (renamed from platform/darwin/MGLGeometry.mm)0
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h (renamed from platform/darwin/MGLGeometry_Private.h)0
-rw-r--r--platform/darwin/src/MGLMapCamera.mm (renamed from platform/darwin/MGLMapCamera.mm)0
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm (renamed from platform/darwin/MGLMultiPoint.mm)0
-rw-r--r--platform/darwin/src/MGLMultiPoint_Private.h (renamed from platform/darwin/MGLMultiPoint_Private.h)0
-rw-r--r--platform/darwin/src/MGLPointAnnotation.m (renamed from platform/darwin/MGLPointAnnotation.m)0
-rw-r--r--platform/darwin/src/MGLPolygon.mm (renamed from platform/darwin/MGLPolygon.mm)0
-rw-r--r--platform/darwin/src/MGLPolyline.mm (renamed from platform/darwin/MGLPolyline.mm)0
-rw-r--r--platform/darwin/src/MGLShape.m (renamed from platform/darwin/MGLShape.m)0
-rw-r--r--platform/darwin/src/MGLStyle.mm (renamed from platform/darwin/MGLStyle.mm)0
-rw-r--r--platform/darwin/src/MGLTypes.m (renamed from platform/darwin/MGLTypes.m)0
-rw-r--r--platform/darwin/src/NSException+MGLAdditions.h (renamed from platform/darwin/NSException+MGLAdditions.h)0
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h (renamed from platform/darwin/NSString+MGLAdditions.h)0
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m (renamed from platform/darwin/NSString+MGLAdditions.m)0
-rw-r--r--platform/darwin/src/application_root.mm (renamed from platform/darwin/application_root.mm)0
-rw-r--r--platform/darwin/src/http_request_nsurl.mm (renamed from platform/darwin/http_request_nsurl.mm)67
-rw-r--r--platform/darwin/src/image.mm (renamed from platform/darwin/image.mm)0
-rw-r--r--platform/darwin/src/log_nslog.mm (renamed from platform/darwin/log_nslog.mm)0
-rw-r--r--platform/darwin/src/nsthread.mm (renamed from platform/darwin/nsthread.mm)0
-rw-r--r--platform/darwin/src/reachability.m (renamed from platform/darwin/reachability.m)0
-rw-r--r--platform/darwin/src/settings_nsuserdefaults.mm (renamed from platform/darwin/settings_nsuserdefaults.mm)0
-rw-r--r--platform/darwin/src/string_nsstring.mm (renamed from platform/darwin/string_nsstring.mm)0
-rw-r--r--platform/default/default_file_source.cpp194
-rw-r--r--platform/default/glfw_view.cpp73
-rw-r--r--platform/default/http_request_curl.cpp21
-rw-r--r--platform/default/jpeg_reader.cpp2
-rw-r--r--platform/default/mbgl/storage/offline.cpp122
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp523
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp94
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp241
-rw-r--r--platform/default/mbgl/storage/offline_download.hpp62
-rw-r--r--platform/default/mbgl/storage/offline_schema.cpp.include53
-rw-r--r--platform/default/mbgl/storage/offline_schema.js24
-rw-r--r--platform/default/mbgl/storage/offline_schema.sql62
-rw-r--r--platform/default/online_file_source.cpp320
-rw-r--r--platform/default/resources/api_mapbox_com-digicert.derbin0 -> 2077 bytes
-rw-r--r--platform/default/resources/api_mapbox_com-geotrust.derbin0 -> 1969 bytes
-rw-r--r--platform/default/resources/star_tilestream_net.derbin0 -> 1273 bytes
-rw-r--r--platform/default/run_loop.cpp26
-rw-r--r--platform/default/sqlite3.cpp94
-rw-r--r--platform/default/sqlite3.hpp21
-rw-r--r--platform/default/sqlite_cache.cpp505
-rw-r--r--platform/default/sqlite_cache_impl.hpp68
-rw-r--r--platform/ios/DEVELOPING.md2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec (renamed from ios/Mapbox-iOS-SDK.podspec)0
-rw-r--r--platform/ios/README.md2
-rw-r--r--platform/ios/app/MBXAppDelegate.h (renamed from ios/app/MBXAppDelegate.h)0
-rw-r--r--platform/ios/app/MBXAppDelegate.m (renamed from ios/app/MBXAppDelegate.m)0
-rw-r--r--platform/ios/app/MBXCustomCalloutView.h (renamed from ios/app/MBXCustomCalloutView.h)0
-rw-r--r--platform/ios/app/MBXCustomCalloutView.m (renamed from ios/app/MBXCustomCalloutView.m)0
-rw-r--r--platform/ios/app/MBXViewController.h (renamed from ios/app/MBXViewController.h)0
-rw-r--r--platform/ios/app/MBXViewController.mm (renamed from ios/app/MBXViewController.mm)2
-rw-r--r--platform/ios/app/Settings.bundle/Root.plist (renamed from ios/app/Settings.bundle/Root.plist)0
-rw-r--r--platform/ios/app/Settings.bundle/en.lproj/Root.strings (renamed from ios/app/Settings.bundle/en.lproj/Root.strings)0
-rw-r--r--platform/ios/app/app-info.plist (renamed from ios/app/app-info.plist)0
-rw-r--r--platform/ios/app/img/Default-568h@2x.png (renamed from ios/app/img/Default-568h@2x.png)bin2239 -> 2239 bytes
-rw-r--r--platform/ios/app/img/Default-667h@2x.png (renamed from ios/app/img/Default-667h@2x.png)bin2797 -> 2797 bytes
-rw-r--r--platform/ios/app/img/Icon-40.png (renamed from ios/app/img/Icon-40.png)bin951 -> 951 bytes
-rw-r--r--platform/ios/app/img/Icon-40@2x.png (renamed from ios/app/img/Icon-40@2x.png)bin1528 -> 1528 bytes
-rw-r--r--platform/ios/app/img/Icon-60.png (renamed from ios/app/img/Icon-60.png)bin1313 -> 1313 bytes
-rw-r--r--platform/ios/app/img/Icon-60@2x.png (renamed from ios/app/img/Icon-60@2x.png)bin2091 -> 2091 bytes
-rw-r--r--platform/ios/app/img/Icon-60@3x.png (renamed from ios/app/img/Icon-60@3x.png)bin1300 -> 1300 bytes
-rw-r--r--platform/ios/app/img/Icon-72.png (renamed from ios/app/img/Icon-72.png)bin1418 -> 1418 bytes
-rw-r--r--platform/ios/app/img/Icon-72@2x.png (renamed from ios/app/img/Icon-72@2x.png)bin2442 -> 2442 bytes
-rw-r--r--platform/ios/app/img/Icon-76.png (renamed from ios/app/img/Icon-76.png)bin1447 -> 1447 bytes
-rw-r--r--platform/ios/app/img/Icon-76@2x.png (renamed from ios/app/img/Icon-76@2x.png)bin2520 -> 2520 bytes
-rw-r--r--platform/ios/app/img/Icon-76@3x.png (renamed from ios/app/img/Icon-76@3x.png)bin1741 -> 1741 bytes
-rw-r--r--platform/ios/app/img/Icon-Small-50.png (renamed from ios/app/img/Icon-Small-50.png)bin1118 -> 1118 bytes
-rw-r--r--platform/ios/app/img/Icon-Small-50@2x.png (renamed from ios/app/img/Icon-Small-50@2x.png)bin1839 -> 1839 bytes
-rw-r--r--platform/ios/app/img/Icon-Small.png (renamed from ios/app/img/Icon-Small.png)bin684 -> 684 bytes
-rw-r--r--platform/ios/app/img/Icon-Small@2x.png (renamed from ios/app/img/Icon-Small@2x.png)bin1231 -> 1231 bytes
-rw-r--r--platform/ios/app/img/Icon-Small@3x.png (renamed from ios/app/img/Icon-Small@3x.png)bin807 -> 807 bytes
-rw-r--r--platform/ios/app/img/Icon-Spotlight-40.png (renamed from ios/app/img/Icon-Spotlight-40.png)bin951 -> 951 bytes
-rw-r--r--platform/ios/app/img/Icon-Spotlight-40@2x.png (renamed from ios/app/img/Icon-Spotlight-40@2x.png)bin1528 -> 1528 bytes
-rw-r--r--platform/ios/app/img/Icon-Spotlight-40@3x.png (renamed from ios/app/img/Icon-Spotlight-40@3x.png)bin961 -> 961 bytes
-rw-r--r--platform/ios/app/img/Icon.png (renamed from ios/app/img/Icon.png)bin1171 -> 1171 bytes
-rw-r--r--platform/ios/app/img/Icon@2x.png (renamed from ios/app/img/Icon@2x.png)bin1931 -> 1931 bytes
-rw-r--r--platform/ios/app/img/TrackingHeadingMask.png (renamed from ios/app/img/TrackingHeadingMask.png)bin250 -> 250 bytes
-rw-r--r--platform/ios/app/img/TrackingHeadingMask@2x.png (renamed from ios/app/img/TrackingHeadingMask@2x.png)bin467 -> 467 bytes
-rw-r--r--platform/ios/app/img/TrackingHeadingMask@3x.png (renamed from ios/app/img/TrackingHeadingMask@3x.png)bin672 -> 672 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationMask.png (renamed from ios/app/img/TrackingLocationMask.png)bin407 -> 407 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationMask@2x.png (renamed from ios/app/img/TrackingLocationMask@2x.png)bin680 -> 680 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationMask@3x.png (renamed from ios/app/img/TrackingLocationMask@3x.png)bin903 -> 903 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationOffMask.png (renamed from ios/app/img/TrackingLocationOffMask.png)bin493 -> 493 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationOffMask@2x.png (renamed from ios/app/img/TrackingLocationOffMask@2x.png)bin973 -> 973 bytes
-rw-r--r--platform/ios/app/img/TrackingLocationOffMask@3x.png (renamed from ios/app/img/TrackingLocationOffMask@3x.png)bin1407 -> 1407 bytes
-rw-r--r--platform/ios/app/img/iTunesArtwork (renamed from ios/app/img/iTunesArtwork)bin264721 -> 264721 bytes
-rw-r--r--platform/ios/app/img/iTunesArtwork.png (renamed from ios/app/img/iTunesArtwork.png)bin5655 -> 5655 bytes
-rw-r--r--platform/ios/app/img/iTunesArtwork@2x (renamed from ios/app/img/iTunesArtwork@2x)bin661346 -> 661346 bytes
-rw-r--r--platform/ios/app/img/iTunesArtwork@2x.png (renamed from ios/app/img/iTunesArtwork@2x.png)bin9293 -> 9293 bytes
-rw-r--r--platform/ios/app/img/settings.png (renamed from ios/app/img/settings.png)bin528 -> 528 bytes
-rw-r--r--platform/ios/app/img/settings@2x.png (renamed from ios/app/img/settings@2x.png)bin1130 -> 1130 bytes
-rw-r--r--platform/ios/app/main.m (renamed from ios/app/main.m)0
-rw-r--r--platform/ios/app/mapboxgl-app.gypi (renamed from ios/app/mapboxgl-app.gypi)6
-rw-r--r--platform/ios/app/points.geojson (renamed from ios/app/points.geojson)0
-rw-r--r--platform/ios/app/polyline.geojson (renamed from ios/app/polyline.geojson)0
-rw-r--r--platform/ios/app/threestates.geojson (renamed from ios/app/threestates.geojson)0
-rw-r--r--platform/ios/benchmark/MBXBenchAppDelegate.h (renamed from ios/benchmark/MBXBenchAppDelegate.h)0
-rw-r--r--platform/ios/benchmark/MBXBenchAppDelegate.m32
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.h (renamed from ios/benchmark/MBXBenchViewController.h)0
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.mm (renamed from ios/benchmark/MBXBenchViewController.mm)10
-rw-r--r--platform/ios/benchmark/app-info.plist (renamed from ios/benchmark/app-info.plist)0
-rwxr-xr-xplatform/ios/benchmark/assets/glyphs/download.sh (renamed from ios/benchmark/assets/glyphs/download.sh)0
-rw-r--r--platform/ios/benchmark/assets/sprites/mapbox-streets.json (renamed from ios/benchmark/assets/sprites/mapbox-streets.json)0
-rw-r--r--platform/ios/benchmark/assets/sprites/mapbox-streets.png (renamed from ios/benchmark/assets/sprites/mapbox-streets.png)bin81643 -> 81643 bytes
-rw-r--r--platform/ios/benchmark/assets/sprites/mapbox-streets@2x.json (renamed from ios/benchmark/assets/sprites/mapbox-streets@2x.json)0
-rw-r--r--platform/ios/benchmark/assets/sprites/mapbox-streets@2x.png (renamed from ios/benchmark/assets/sprites/mapbox-streets@2x.png)bin192103 -> 192103 bytes
-rw-r--r--platform/ios/benchmark/assets/styles/streets-v8.json (renamed from ios/benchmark/assets/styles/streets-v8.json)0
-rwxr-xr-xplatform/ios/benchmark/assets/tiles/download.sh (renamed from ios/benchmark/assets/tiles/download.sh)0
-rw-r--r--platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json (renamed from ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json)0
-rw-r--r--platform/ios/benchmark/benchmark-ios.gypi (renamed from ios/benchmark/benchmark-ios.gypi)35
-rw-r--r--platform/ios/benchmark/img/Icon-40.png (renamed from ios/benchmark/img/Icon-40.png)bin1295 -> 1295 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-40@2x.png (renamed from ios/benchmark/img/Icon-40@2x.png)bin2971 -> 2971 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-40@3x.png (renamed from ios/benchmark/img/Icon-40@3x.png)bin5936 -> 5936 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-60.png (renamed from ios/benchmark/img/Icon-60.png)bin2051 -> 2051 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-60@2x.png (renamed from ios/benchmark/img/Icon-60@2x.png)bin5936 -> 5936 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-60@3x.png (renamed from ios/benchmark/img/Icon-60@3x.png)bin11806 -> 11806 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-72.png (renamed from ios/benchmark/img/Icon-72.png)bin2610 -> 2610 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-72@2x.png (renamed from ios/benchmark/img/Icon-72@2x.png)bin7894 -> 7894 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-76.png (renamed from ios/benchmark/img/Icon-76.png)bin2841 -> 2841 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-76@2x.png (renamed from ios/benchmark/img/Icon-76@2x.png)bin8633 -> 8633 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-Small-50.png (renamed from ios/benchmark/img/Icon-Small-50.png)bin1676 -> 1676 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-Small-50@2x.png (renamed from ios/benchmark/img/Icon-Small-50@2x.png)bin4490 -> 4490 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-Small.png (renamed from ios/benchmark/img/Icon-Small.png)bin1009 -> 1009 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-Small@2x.png (renamed from ios/benchmark/img/Icon-Small@2x.png)bin2046 -> 2046 bytes
-rw-r--r--platform/ios/benchmark/img/Icon-Small@3x.png (renamed from ios/benchmark/img/Icon-Small@3x.png)bin3371 -> 3371 bytes
-rw-r--r--platform/ios/benchmark/img/Icon.png (renamed from ios/benchmark/img/Icon.png)bin2009 -> 2009 bytes
-rw-r--r--platform/ios/benchmark/img/Icon.svg (renamed from ios/benchmark/img/Icon.svg)0
-rw-r--r--platform/ios/benchmark/img/Icon@2x.png (renamed from ios/benchmark/img/Icon@2x.png)bin5436 -> 5436 bytes
-rw-r--r--platform/ios/benchmark/img/iTunesArtwork.png (renamed from ios/benchmark/img/iTunesArtwork.png)bin113442 -> 113442 bytes
-rw-r--r--platform/ios/benchmark/img/iTunesArtwork@2x.png (renamed from ios/benchmark/img/iTunesArtwork@2x.png)bin399202 -> 399202 bytes
-rw-r--r--platform/ios/benchmark/locations.cpp (renamed from ios/benchmark/locations.cpp)0
-rw-r--r--platform/ios/benchmark/locations.hpp (renamed from ios/benchmark/locations.hpp)0
-rw-r--r--platform/ios/benchmark/main.m (renamed from ios/benchmark/main.m)0
-rw-r--r--platform/ios/bitrise.yml2
-rw-r--r--platform/ios/docs/doc-README.md (renamed from ios/docs/doc-README.md)0
-rwxr-xr-xplatform/ios/docs/install_docs.sh (renamed from ios/docs/install_docs.sh)2
-rw-r--r--platform/ios/docs/pod-README.md (renamed from ios/docs/pod-README.md)0
-rwxr-xr-xplatform/ios/docs/remove_docs.sh (renamed from ios/docs/remove_docs.sh)0
-rw-r--r--platform/ios/framework/Info.plist (renamed from ios/framework/Info.plist)0
-rw-r--r--platform/ios/framework/Mapbox.h (renamed from ios/framework/Mapbox.h)0
-rw-r--r--platform/ios/framework/Mapbox.m (renamed from ios/framework/Mapbox.m)6
-rw-r--r--platform/ios/framework/Settings.bundle/Root.plist (renamed from ios/framework/Settings.bundle/Root.plist)0
-rw-r--r--platform/ios/framework/Settings.bundle/en.lproj/Root.strings (renamed from ios/framework/Settings.bundle/en.lproj/Root.strings)bin552 -> 552 bytes
-rw-r--r--platform/ios/framework/framework-ios.gypi (renamed from ios/framework/framework-ios.gypi)6
-rw-r--r--platform/ios/framework/modulemap (renamed from ios/framework/modulemap)0
-rwxr-xr-xplatform/ios/framework/strip-frameworks.sh (renamed from ios/framework/strip-frameworks.sh)0
-rw-r--r--platform/ios/include/MGLAccountManager.h (renamed from include/mbgl/ios/MGLAccountManager.h)0
-rw-r--r--platform/ios/include/MGLAnnotationImage.h (renamed from include/mbgl/ios/MGLAnnotationImage.h)0
-rw-r--r--platform/ios/include/MGLCalloutView.h (renamed from include/mbgl/ios/MGLCalloutView.h)0
-rw-r--r--platform/ios/include/MGLMapView+IBAdditions.h (renamed from include/mbgl/ios/MGLMapView+IBAdditions.h)0
-rw-r--r--platform/ios/include/MGLMapView+MGLCustomStyleLayerAdditions.h (renamed from include/mbgl/ios/MGLMapView+MGLCustomStyleLayerAdditions.h)0
-rw-r--r--platform/ios/include/MGLMapView.h (renamed from include/mbgl/ios/MGLMapView.h)4
-rw-r--r--platform/ios/include/MGLUserLocation.h (renamed from include/mbgl/ios/MGLUserLocation.h)0
-rw-r--r--platform/ios/include/Mapbox.h (renamed from include/mbgl/ios/Mapbox.h)0
-rw-r--r--platform/ios/screenshot.png (renamed from ios/screenshot.png)bin302191 -> 302191 bytes
-rwxr-xr-xplatform/ios/scripts/benchmark.sh4
-rwxr-xr-xplatform/ios/scripts/document.sh2
-rwxr-xr-xplatform/ios/scripts/package.sh16
-rwxr-xr-xplatform/ios/scripts/test.sh2
-rw-r--r--platform/ios/src/MGLMapView.mm12
-rw-r--r--platform/ios/src/MGLMapboxEvents.m77
-rw-r--r--platform/ios/test/.gitignore (renamed from test/ios/.gitignore)0
-rw-r--r--platform/ios/test/App-Info.plist (renamed from test/ios/App-Info.plist)0
-rw-r--r--platform/ios/test/Bundle-Info.plist (renamed from test/ios/Bundle-Info.plist)0
-rw-r--r--platform/ios/test/Images.xcassets/AppIcon.appiconset/Contents.json (renamed from test/ios/Images.xcassets/AppIcon.appiconset/Contents.json)0
-rw-r--r--platform/ios/test/Images.xcassets/LaunchImage.launchimage/Contents.json (renamed from test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json)0
-rw-r--r--platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png (renamed from test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png)bin184 -> 184 bytes
-rw-r--r--platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default@2x.png (renamed from test/ios/Images.xcassets/LaunchImage.launchimage/Default@2x.png)bin170 -> 170 bytes
m---------platform/ios/test/KIF0
-rw-r--r--platform/ios/test/KIFTestActor+MapboxGL.h (renamed from test/ios/KIFTestActor+MapboxGL.h)0
-rw-r--r--platform/ios/test/KIFTestActor+MapboxGL.m (renamed from test/ios/KIFTestActor+MapboxGL.m)0
-rw-r--r--platform/ios/test/LaunchScreen.xib (renamed from test/ios/LaunchScreen.xib)0
-rw-r--r--platform/ios/test/MGLTAppDelegate.h (renamed from test/ios/MGLTAppDelegate.h)0
-rw-r--r--platform/ios/test/MGLTAppDelegate.m (renamed from test/ios/MGLTAppDelegate.m)0
-rw-r--r--platform/ios/test/MGLTViewController.h (renamed from test/ios/MGLTViewController.h)0
-rw-r--r--platform/ios/test/MGLTViewController.m (renamed from test/ios/MGLTViewController.m)0
-rw-r--r--platform/ios/test/MapViewTests.m (renamed from test/ios/MapViewTests.m)0
-rw-r--r--platform/ios/test/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h (renamed from test/ios/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMArg.h (renamed from test/ios/OCMock/OCMock/OCMArg.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMConstraint.h (renamed from test/ios/OCMock/OCMock/OCMConstraint.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMLocation.h (renamed from test/ios/OCMock/OCMock/OCMLocation.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMMacroState.h (renamed from test/ios/OCMock/OCMock/OCMMacroState.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMRecorder.h (renamed from test/ios/OCMock/OCMock/OCMRecorder.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMStubRecorder.h (renamed from test/ios/OCMock/OCMock/OCMStubRecorder.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMock.h (renamed from test/ios/OCMock/OCMock/OCMock.h)0
-rw-r--r--platform/ios/test/OCMock/OCMock/OCMockObject.h (renamed from test/ios/OCMock/OCMock/OCMockObject.h)0
-rw-r--r--platform/ios/test/OCMock/libOCMock.a (renamed from test/ios/OCMock/libOCMock.a)bin2071640 -> 2071640 bytes
-rw-r--r--platform/ios/test/OHHTTPStubs/.gitignore (renamed from test/ios/OHHTTPStubs/.gitignore)0
-rw-r--r--platform/ios/test/OHHTTPStubs/.travis.yml (renamed from test/ios/OHHTTPStubs/.travis.yml)0
-rw-r--r--platform/ios/test/OHHTTPStubs/CHANGELOG.md (renamed from test/ios/OHHTTPStubs/CHANGELOG.md)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.m (renamed from test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.xib (renamed from test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.xib)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme (renamed from test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme (renamed from test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Podfile)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile.lock (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Podfile.lock)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg)bin46859 -> 46859 bytes
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png)bin18594 -> 18594 bytes
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m (renamed from test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/AppDelegate.swift (renamed from test/ios/OHHTTPStubs/Examples/Swift/AppDelegate.swift)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Main.storyboard (renamed from test/ios/OHHTTPStubs/Examples/Swift/Main.storyboard)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/MainViewController.swift (renamed from test/ios/OHHTTPStubs/Examples/Swift/MainViewController.swift)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme (renamed from test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile (renamed from test/ios/OHHTTPStubs/Examples/Swift/Podfile)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile.lock (renamed from test/ios/OHHTTPStubs/Examples/Swift/Podfile.lock)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h)0
l---------platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig (renamed from test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg (renamed from test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg)bin46859 -> 46859 bytes
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.txt (renamed from test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.txt)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png (renamed from test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png)bin18594 -> 18594 bytes
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json (renamed from test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist (renamed from test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib (renamed from test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib)0
-rw-r--r--platform/ios/test/OHHTTPStubs/LICENSE (renamed from test/ios/OHHTTPStubs/LICENSE)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs.podspec (renamed from test/ios/OHHTTPStubs/OHHTTPStubs.podspec)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Podfile)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile.lock (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Podfile.lock)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h)0
l---------platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail)0
-rwxr-xr-xplatform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch)0
-rw-r--r--platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail (renamed from test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail)0
-rw-r--r--platform/ios/test/OHHTTPStubs/README.md (renamed from test/ios/OHHTTPStubs/README.md)0
-rw-r--r--platform/ios/test/OHHTTPStubs/Rakefile (renamed from test/ios/OHHTTPStubs/Rakefile)0
-rw-r--r--platform/ios/test/ios-tests.xcodeproj/project.pbxproj (renamed from test/ios/ios-tests.xcodeproj/project.pbxproj)10
-rw-r--r--platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata (renamed from test/ios/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata)0
-rw-r--r--platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout (renamed from test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout)0
-rw-r--r--platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout (renamed from test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout)0
-rw-r--r--platform/ios/test/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme (renamed from test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme)0
-rw-r--r--platform/ios/test/main.m (renamed from test/ios/main.m)0
-rw-r--r--platform/linux/main.cpp2
-rw-r--r--platform/linux/mapboxgl-app.gypi18
-rwxr-xr-xplatform/linux/scripts/coveralls.sh13
-rwxr-xr-xplatform/linux/scripts/run.sh3
-rw-r--r--platform/node/src/node_map.cpp26
-rw-r--r--platform/node/src/node_request.cpp2
-rw-r--r--platform/node/test/js/map.test.js56
-rw-r--r--platform/node/test/render.test.js4
-rw-r--r--platform/osx/INSTALL.md2
-rw-r--r--platform/osx/README.md2
-rw-r--r--platform/osx/app/MainMenu.xib16
-rw-r--r--platform/osx/app/MapDocument.m44
-rw-r--r--platform/osx/include/MGLAccountManager.h (renamed from include/mbgl/osx/MGLAccountManager.h)0
-rw-r--r--platform/osx/include/MGLAnnotationImage.h (renamed from include/mbgl/osx/MGLAnnotationImage.h)0
-rw-r--r--platform/osx/include/MGLMapView+IBAdditions.h (renamed from include/mbgl/osx/MGLMapView+IBAdditions.h)0
-rw-r--r--platform/osx/include/MGLMapView.h (renamed from include/mbgl/osx/MGLMapView.h)0
-rw-r--r--platform/osx/include/MGLMapViewDelegate.h (renamed from include/mbgl/osx/MGLMapViewDelegate.h)8
-rwxr-xr-xplatform/osx/scripts/run.sh5
-rw-r--r--platform/osx/sdk/Mapbox.m2
-rw-r--r--platform/osx/sdk/framework-osx.gypi2
-rw-r--r--platform/osx/src/MGLAccountManager.m2
-rw-r--r--platform/osx/src/MGLAccountManager_Private.h2
-rw-r--r--platform/osx/src/MGLAnnotationImage.m2
-rw-r--r--platform/osx/src/MGLMapView+IBAdditions.m2
-rw-r--r--platform/osx/src/MGLMapView.mm24
-rw-r--r--platform/osx/src/MGLMapView_Private.h2
-rw-r--r--platform/osx/src/MGLOpenGLLayer.mm2
-rw-r--r--platform/osx/test/MGLGeometryTests.mm2
-rw-r--r--platform/osx/test/osxtest.gypi4
-rwxr-xr-xscripts/build-shaders.py2
-rwxr-xr-xscripts/collect-coverage.sh66
-rwxr-xr-xscripts/coveralls.sh37
-rw-r--r--scripts/main.mk14
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp10
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp1
-rw-r--r--src/mbgl/annotation/annotation_tile.cpp2
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp2
-rw-r--r--src/mbgl/geometry/buffer.hpp31
-rw-r--r--src/mbgl/geometry/circle_buffer.cpp2
-rw-r--r--src/mbgl/geometry/collision_box_buffer.cpp2
-rw-r--r--src/mbgl/geometry/debug_font_buffer.cpp2
-rw-r--r--src/mbgl/geometry/fill_buffer.cpp2
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp21
-rw-r--r--src/mbgl/geometry/glyph_atlas.hpp9
-rw-r--r--src/mbgl/geometry/icon_buffer.cpp2
-rw-r--r--src/mbgl/geometry/line_atlas.cpp29
-rw-r--r--src/mbgl/geometry/line_atlas.hpp14
-rw-r--r--src/mbgl/geometry/line_buffer.cpp2
-rw-r--r--src/mbgl/geometry/static_vertex_buffer.cpp2
-rw-r--r--src/mbgl/geometry/text_buffer.cpp2
-rw-r--r--src/mbgl/geometry/vao.cpp52
-rw-r--r--src/mbgl/geometry/vao.hpp28
-rw-r--r--src/mbgl/gl/debugging.cpp2
-rw-r--r--src/mbgl/gl/gl.cpp (renamed from src/mbgl/platform/gl.cpp)2
-rw-r--r--src/mbgl/gl/gl_config.cpp (renamed from src/mbgl/renderer/gl_config.cpp)0
-rw-r--r--src/mbgl/gl/gl_config.hpp100
-rw-r--r--src/mbgl/gl/gl_object_store.cpp120
-rw-r--r--src/mbgl/gl/gl_object_store.hpp141
-rw-r--r--src/mbgl/gl/texture_pool.cpp41
-rw-r--r--src/mbgl/gl/texture_pool.hpp41
-rw-r--r--src/mbgl/layer/background_layer.hpp6
-rw-r--r--src/mbgl/layer/circle_layer.hpp6
-rw-r--r--src/mbgl/layer/custom_layer.cpp3
-rw-r--r--src/mbgl/layer/custom_layer.hpp5
-rw-r--r--src/mbgl/layer/fill_layer.hpp6
-rw-r--r--src/mbgl/layer/line_layer.cpp2
-rw-r--r--src/mbgl/layer/line_layer.hpp6
-rw-r--r--src/mbgl/layer/raster_layer.hpp6
-rw-r--r--src/mbgl/layer/symbol_layer.hpp8
-rw-r--r--src/mbgl/map/map.cpp5
-rw-r--r--src/mbgl/map/map_context.cpp31
-rw-r--r--src/mbgl/map/map_context.hpp10
-rw-r--r--src/mbgl/map/raster_tile_data.cpp88
-rw-r--r--src/mbgl/map/tile.cpp3
-rw-r--r--src/mbgl/map/tile_id.hpp23
-rw-r--r--src/mbgl/map/transform_state.cpp13
-rw-r--r--src/mbgl/map/transform_state.hpp4
-rw-r--r--src/mbgl/renderer/bucket.hpp8
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp10
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp6
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp14
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp10
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp22
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp10
-rw-r--r--src/mbgl/renderer/line_bucket.cpp70
-rw-r--r--src/mbgl/renderer/line_bucket.hpp14
-rw-r--r--src/mbgl/renderer/painter.cpp62
-rw-r--r--src/mbgl/renderer/painter.hpp17
-rw-r--r--src/mbgl/renderer/painter_circle.cpp4
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp39
-rw-r--r--src/mbgl/renderer/painter_debug.cpp20
-rw-r--r--src/mbgl/renderer/painter_fill.cpp18
-rw-r--r--src/mbgl/renderer/painter_line.cpp20
-rw-r--r--src/mbgl/renderer/painter_raster.cpp6
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp48
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp12
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp6
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp28
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp12
-rw-r--r--src/mbgl/shader/box_shader.cpp10
-rw-r--r--src/mbgl/shader/box_shader.hpp4
-rw-r--r--src/mbgl/shader/circle_shader.cpp6
-rw-r--r--src/mbgl/shader/circle_shader.hpp2
-rw-r--r--src/mbgl/shader/dot_shader.cpp5
-rw-r--r--src/mbgl/shader/dot_shader.hpp2
-rw-r--r--src/mbgl/shader/icon_shader.cpp11
-rw-r--r--src/mbgl/shader/icon_shader.hpp2
-rw-r--r--src/mbgl/shader/line_shader.cpp7
-rw-r--r--src/mbgl/shader/line_shader.hpp2
-rw-r--r--src/mbgl/shader/linepattern_shader.cpp8
-rw-r--r--src/mbgl/shader/linepattern_shader.hpp2
-rw-r--r--src/mbgl/shader/linesdf_shader.cpp8
-rw-r--r--src/mbgl/shader/linesdf_shader.hpp2
-rw-r--r--src/mbgl/shader/outline_shader.cpp6
-rw-r--r--src/mbgl/shader/outline_shader.hpp2
-rw-r--r--src/mbgl/shader/pattern_shader.cpp7
-rw-r--r--src/mbgl/shader/pattern_shader.hpp2
-rw-r--r--src/mbgl/shader/plain_shader.cpp5
-rw-r--r--src/mbgl/shader/plain_shader.hpp2
-rw-r--r--src/mbgl/shader/raster_shader.cpp6
-rw-r--r--src/mbgl/shader/raster_shader.hpp2
-rw-r--r--src/mbgl/shader/sdf_shader.cpp11
-rw-r--r--src/mbgl/shader/sdf_shader.hpp4
-rw-r--r--src/mbgl/shader/shader.cpp78
-rw-r--r--src/mbgl/shader/shader.hpp21
-rw-r--r--src/mbgl/shader/uniform.hpp8
-rw-r--r--src/mbgl/source/source.cpp (renamed from src/mbgl/map/source.cpp)210
-rw-r--r--src/mbgl/source/source.hpp (renamed from src/mbgl/map/source.hpp)20
-rw-r--r--src/mbgl/source/source_info.hpp (renamed from src/mbgl/map/source_info.hpp)0
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp23
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp9
-rw-r--r--src/mbgl/sprite/sprite_store.cpp34
-rw-r--r--src/mbgl/sprite/sprite_store.hpp4
-rw-r--r--src/mbgl/storage/http_context_base.hpp1
-rw-r--r--src/mbgl/storage/resource.cpp3
-rw-r--r--src/mbgl/storage/response.cpp23
-rw-r--r--src/mbgl/storage/sqlite_cache.hpp44
-rw-r--r--src/mbgl/style/filter_expression.cpp2
-rw-r--r--src/mbgl/style/function.hpp3
-rw-r--r--src/mbgl/style/style.cpp18
-rw-r--r--src/mbgl/style/style.hpp12
-rw-r--r--src/mbgl/style/style_bucket_parameters.cpp2
-rw-r--r--src/mbgl/style/style_bucket_parameters.hpp2
-rw-r--r--src/mbgl/style/style_layer.hpp27
-rw-r--r--src/mbgl/style/style_parser.cpp31
-rw-r--r--src/mbgl/style/style_parser.hpp7
-rw-r--r--src/mbgl/style/style_update_parameters.hpp10
-rw-r--r--src/mbgl/text/get_anchors.cpp16
-rw-r--r--src/mbgl/text/glyph_pbf.cpp33
-rw-r--r--src/mbgl/text/glyph_pbf.hpp4
-rw-r--r--src/mbgl/text/glyph_store.cpp7
-rw-r--r--src/mbgl/text/glyph_store.hpp4
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile.cpp (renamed from src/mbgl/map/geometry_tile.cpp)2
-rw-r--r--src/mbgl/tile/geometry_tile.hpp (renamed from src/mbgl/map/geometry_tile.hpp)0
-rw-r--r--src/mbgl/tile/raster_tile_data.cpp83
-rw-r--r--src/mbgl/tile/raster_tile_data.hpp (renamed from src/mbgl/map/raster_tile_data.hpp)10
-rw-r--r--src/mbgl/tile/tile.cpp3
-rw-r--r--src/mbgl/tile/tile.hpp (renamed from src/mbgl/map/tile.hpp)0
-rw-r--r--src/mbgl/tile/tile_cache.cpp (renamed from src/mbgl/map/tile_cache.cpp)3
-rw-r--r--src/mbgl/tile/tile_cache.hpp (renamed from src/mbgl/map/tile_cache.hpp)6
-rw-r--r--src/mbgl/tile/tile_data.cpp (renamed from src/mbgl/map/tile_data.cpp)2
-rw-r--r--src/mbgl/tile/tile_data.hpp (renamed from src/mbgl/map/tile_data.hpp)0
-rw-r--r--src/mbgl/tile/tile_worker.cpp (renamed from src/mbgl/map/tile_worker.cpp)4
-rw-r--r--src/mbgl/tile/tile_worker.hpp (renamed from src/mbgl/map/tile_worker.hpp)2
-rw-r--r--src/mbgl/tile/vector_tile.cpp (renamed from src/mbgl/map/vector_tile.cpp)33
-rw-r--r--src/mbgl/tile/vector_tile.hpp (renamed from src/mbgl/map/vector_tile.hpp)6
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp (renamed from src/mbgl/map/vector_tile_data.cpp)4
-rw-r--r--src/mbgl/tile/vector_tile_data.hpp (renamed from src/mbgl/map/vector_tile_data.hpp)4
-rw-r--r--src/mbgl/util/box.hpp16
-rw-r--r--src/mbgl/util/clip_id.cpp113
-rw-r--r--src/mbgl/util/clip_id.hpp20
-rw-r--r--src/mbgl/util/clip_lines.cpp16
-rw-r--r--src/mbgl/util/constants.cpp76
-rw-r--r--src/mbgl/util/get_geometries.cpp6
-rw-r--r--src/mbgl/util/get_geometries.hpp2
-rw-r--r--src/mbgl/util/gl_object_store.cpp50
-rw-r--r--src/mbgl/util/gl_object_store.hpp35
-rw-r--r--src/mbgl/util/mapbox.cpp93
-rw-r--r--src/mbgl/util/mapbox.hpp9
-rw-r--r--src/mbgl/util/raster.cpp19
-rw-r--r--src/mbgl/util/raster.hpp14
-rw-r--r--src/mbgl/util/texture_pool.cpp53
-rw-r--r--src/mbgl/util/texture_pool.hpp25
-rw-r--r--src/mbgl/util/thread_context.cpp32
-rw-r--r--src/mbgl/util/thread_context.hpp13
-rw-r--r--src/mbgl/util/tile_coordinate.hpp16
-rw-r--r--src/mbgl/util/tile_cover.cpp75
-rw-r--r--src/mbgl/util/tile_cover.hpp12
-rw-r--r--src/mbgl/util/worker.cpp2
-rw-r--r--src/mbgl/util/worker.hpp2
-rw-r--r--test/api/annotations.cpp46
-rw-r--r--test/api/api_misuse.cpp4
-rw-r--r--test/api/custom_layer.cpp6
-rw-r--r--test/api/offline.cpp50
-rw-r--r--test/api/set_style.cpp2
-rw-r--r--test/fixtures/annotations/update_icon/expected.pngbin0 -> 2949 bytes
-rw-r--r--test/fixtures/annotations/update_point/expected.pngbin2949 -> 2504 bytes
-rw-r--r--test/fixtures/offline/0-0-0.vector.pbf (renamed from test/fixtures/stale/0-0-0.vector.pbf)bin482553 -> 482553 bytes
-rw-r--r--test/fixtures/offline/empty.style.json5
-rw-r--r--test/fixtures/offline/expected.pngbin0 -> 47842 bytes
-rw-r--r--test/fixtures/offline/geojson.json4
-rw-r--r--test/fixtures/offline/geojson_source.style.json10
-rw-r--r--test/fixtures/offline/glyph.pbf (renamed from test/fixtures/stale/glyph.pbf)bin74722 -> 74722 bytes
-rw-r--r--test/fixtures/offline/inline_source.style.json17
-rw-r--r--test/fixtures/offline/sprite.json (renamed from test/fixtures/stale/sprite.json)0
-rw-r--r--test/fixtures/offline/sprite.png (renamed from test/fixtures/stale/sprite.png)bin3351 -> 3351 bytes
-rw-r--r--test/fixtures/offline/streets.json (renamed from test/fixtures/stale/streets.json)2
-rw-r--r--test/fixtures/offline/style.json (renamed from test/fixtures/stale/style_and_glyphs.json)10
-rw-r--r--test/fixtures/stale/stale_style/expected.pngbin13447 -> 0 bytes
-rw-r--r--test/fixtures/stale/stale_style_and_glyphs/expected.pngbin36120 -> 0 bytes
-rw-r--r--test/fixtures/stale/stale_style_and_sprite/expected.pngbin26859 -> 0 bytes
-rw-r--r--test/fixtures/stale/stale_style_and_tilejson/expected.pngbin13447 -> 0 bytes
-rw-r--r--test/fixtures/stale/style.json25
-rw-r--r--test/fixtures/stale/style_and_sprite.json26
-rw-r--r--test/fixtures/stale/style_and_tilejson.json25
-rw-r--r--test/fixtures/stub_file_source.cpp11
-rw-r--r--test/fixtures/stub_file_source.hpp18
-rw-r--r--test/fixtures/style_parser/font_stacks.json38
-rw-r--r--test/fixtures/style_parser/tilejson.raster.json2
-rw-r--r--test/fixtures/style_parser/tilejson.vector.json2
-rw-r--r--test/fixtures/util.cpp12
-rw-r--r--test/fixtures/util.hpp4
m---------test/ios/KIF0
-rw-r--r--test/map/map.cpp8
-rw-r--r--test/map/map_context.cpp2
-rw-r--r--test/sprite/sprite_store.cpp6
-rw-r--r--test/storage/asset_file_source.cpp22
-rw-r--r--test/storage/cache_response.cpp219
-rw-r--r--test/storage/cache_shared.cpp34
-rw-r--r--test/storage/cache_size.cpp241
-rw-r--r--test/storage/cache_stale.cpp131
-rw-r--r--test/storage/database.cpp349
-rw-r--r--test/storage/default_file_source.cpp (renamed from test/storage/cache_revalidate.cpp)64
-rw-r--r--test/storage/headers.cpp26
-rw-r--r--test/storage/http_cancel.cpp4
-rw-r--r--test/storage/http_error.cpp7
-rw-r--r--test/storage/http_header_parsing.cpp4
-rw-r--r--test/storage/http_issue_1369.cpp7
-rw-r--r--test/storage/http_load.cpp2
-rw-r--r--test/storage/http_other_loop.cpp2
-rw-r--r--test/storage/http_reading.cpp89
-rw-r--r--test/storage/http_retry_network_status.cpp9
-rw-r--r--test/storage/http_timeout.cpp2
-rw-r--r--test/storage/offline.cpp73
-rw-r--r--test/storage/offline_database.cpp573
-rw-r--r--test/storage/offline_download.cpp334
-rw-r--r--test/storage/resource.cpp26
-rwxr-xr-xtest/storage/server.js8
-rw-r--r--test/storage/storage.hpp17
-rw-r--r--test/style/comparisons.cpp2
-rw-r--r--test/style/glyph_store.cpp3
-rw-r--r--test/style/source.cpp84
-rw-r--r--test/style/style.cpp9
-rw-r--r--test/style/style_parser.cpp22
-rw-r--r--test/test.gypi35
-rw-r--r--test/util/clip_ids.cpp202
-rw-r--r--test/util/mapbox.cpp176
-rw-r--r--test/util/run_loop.cpp44
-rw-r--r--test/util/tile_cover.cpp118
912 files changed, 11189 insertions, 5280 deletions
diff --git a/.gitignore b/.gitignore
index f9fd16cd2b..1b6ed5386b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
*.actual.png
*.diff.png
*.pyc
+*.gcno
+*.gcda
+offline.db
/platform/android/debug
/platform/android/sdk
/platform/android/**/.classpath
@@ -23,8 +26,8 @@
/test/fixtures/api/1.png
/test/fixtures/api/2.png
/test/fixtures/database/*.db
-/test/fixtures/*/*/actual.png
-/test/fixtures/*/*/diff.png
+/test/fixtures/**/actual.png
+/test/fixtures/**/diff.png
/test/output
/include/mbgl/shader/shaders.hpp
/src/shader/shaders_gl.cpp
diff --git a/.gitmodules b/.gitmodules
index 782e549df2..e27b5bc8b7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -3,7 +3,7 @@
url = https://github.com/mapbox/mason.git
[submodule "test/ios/KIF"]
- path = test/ios/KIF
+ path = platform/ios/test/KIF
url = https://github.com/kif-framework/KIF.git
[submodule "platform/ios/vendor/SMCalloutView"]
diff --git a/.jazzy.yaml b/.jazzy.yaml
index 99224d9626..867c77e6b9 100644
--- a/.jazzy.yaml
+++ b/.jazzy.yaml
@@ -6,13 +6,13 @@ dash_url: https://www.mapbox.com/ios-sdk/docsets/Mapbox.xml
copyright: '© 2014–2016 [Mapbox](https://www.mapbox.com/). See [license](https://github.com/mapbox/mapbox-gl-native/blob/master/LICENSE.md) for more details.'
custom_head: |
- <link rel='shortcut icon' href='http://www.mapbox.com/img/favicon.ico' type='image/x-icon' />
+ <link rel='shortcut icon' href='https://www.mapbox.com/img/favicon.ico' type='image/x-icon' />
objc_mode: Yes
skip_undocumented: Yes
hide_documentation_coverage: Yes
-umbrella_header: include/mbgl/ios/Mapbox.h
-framework_root: include/mbgl/darwin
+umbrella_header: platform/ios/include/Mapbox.h
+framework_root: platform/darwin/include
custom_categories:
- name: Map
diff --git a/.travis.yml b/.travis.yml
index ecc3e2c0e3..69d1041dc5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -52,6 +52,11 @@ matrix:
env: FLAVOR=node BUILDTYPE=Release NODE_VERSION=4 _CXX=clang++-3.5 _CC=clang-3.5 CCACHE=1
addons: *clang35
+ # Linux - GCC 4.9 - Debug
+ - os: linux
+ compiler: ": linux-gcc49-debug"
+ env: FLAVOR=linux ACTION=coveralls _CXX=g++-4.9 _CC=gcc-4.9 CCACHE=1
+ addons: *gcc49
# Linux - GCC 4.9 - Release
- os: linux
@@ -96,6 +101,12 @@ env:
before_install:
- source ./scripts/set_compiler.sh
- source ./scripts/travis_helper.sh
+- if [[ ${ACTION:-0} == 'coveralls' ]]; then
+ rvm install 2.3.0;
+ rvm use 2.3.0;
+ rvm rubygems latest --force;
+ gem install coveralls-lcov;
+ fi
install:
- ./platform/${FLAVOR}/scripts/install.sh
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9324d8be85..6155ea6643 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -63,6 +63,9 @@ Known issues:
- Fixed an issue that incorrectly expanded the tappable area of an annotation and prevented the annotation’s alignment rect insets from having any effect on the tappable area. ([#3898](https://github.com/mapbox/mapbox-gl-native/pull/3898))
- Fixed an issue preventing `-[MGLMapViewDelegate mapView:tapOnCalloutForAnnotation:]` from being called when a non-custom callout view is tapped. ([#3875](https://github.com/mapbox/mapbox-gl-native/pull/3875))
+- Polygons and polylines now default to using the map view's tint color. ([#4028](https://github.com/mapbox/mapbox-gl-native/pull/4028))
+- The Improve This Map tool now uses the same zoom level that is currently being shown in the map view. ([#4068](https://github.com/mapbox/mapbox-gl-native/pull/4068))
+
## iOS 3.1.0
- The SDK is now distributed as a dynamic framework instead of a static library, resulting in a simpler installation workflow and significantly reduced download size. The framework contains both simulator and device content. If you install the dynamic framework manually, you’ll need to strip out the simulator content before submitting your application to the App Store due to [an Xcode bug](http://www.openradar.me/radar?id=6409498411401216); see the installation instructions included with the framework for details. ([#3183](https://github.com/mapbox/mapbox-gl-native/pull/3183))
diff --git a/Makefile b/Makefile
index c66e2b007a..6e8eda4377 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,8 @@
export BUILDTYPE ?= Release
export BUILD_TEST ?= 1
export BUILD_RENDER ?= 1
+export BUILD_OFFLINE ?= 1
+export ENABLE_COVERAGE ?= 0
# Determine build platform
ifeq ($(shell uname -s), Darwin)
@@ -116,11 +118,15 @@ ifeq ($(BUILD),osx)
xtest: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/test
endif
-.PHONY: render xrender
+.PHONY: check
+check: ; $(RUN) BUILDTYPE=Debug ENABLE_COVERAGE=1 check
+coveralls: ; $(RUN) BUILDTYPE=Debug ENABLE_COVERAGE=1 coveralls
+
+.PHONY: render
render: ; $(RUN) Makefile/mbgl-render
-ifeq ($(BUILD),osx)
-xrender: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/mbgl-render
-endif
+
+.PHONY: offline
+offline: ; $(RUN) Makefile/mbgl-offline
##### Maintenace operations ####################################################
@@ -151,15 +157,10 @@ endif
clean: clear_sqlite_cache clear_xcode_cache
-find ./deps/gyp -name "*.pyc" -exec rm {} \;
- -rm -rf ./build/
+ -find ./build -type f -not -path '*/*.xcodeproj/*' -exec rm {} \;
-rm -rf ./gyp/build/
- -rm -rf ./macosx/build
- -rm -rf ./linux/build
- -rm -rf ./ios/build
- -rm -rf ./test/build
-rm -rf ./config/*.gypi
- -rm -rf ./platform/android/build \
- ./platform/android/MapboxGLAndroidSDK/build \
+ -rm -rf ./platform/android/MapboxGLAndroidSDK/build \
./platform/android/MapboxGLAndroidSDKTestApp/build \
./platform/android/MapboxGLAndroidSDK/src/main/jniLibs \
./platform/android/MapboxGLAndroidSDK/src/main/obj.target \
diff --git a/README.md b/README.md
index a70aba07ec..115f805891 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ This repository hosts the cross-platform Mapbox GL Native library, plus convenie
SDK | Languages | Build status
----|-----------|-------------
-[Mapbox GL Native](INSTALL.md) | C++14 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds)
+[Mapbox GL Native](INSTALL.md) | C++14 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![Coverage Status](https://coveralls.io/repos/github/mapbox/mapbox-gl-native/badge.svg?branch=master)](https://coveralls.io/github/mapbox/mapbox-gl-native?branch=master)
[Mapbox Android SDK](platform/android/) | Java | [![Bitrise](https://www.bitrise.io/app/79cdcbdc42de4303.svg?token=_InPF8bII6W7J6kFr-L8QQ&branch=master)](https://www.bitrise.io/app/79cdcbdc42de4303)
[Mapbox iOS SDK](platform/ios/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/7514e4cf3da2cc57.svg?token=OwqZE5rSBR9MVWNr_lf4sA&branch=master)](https://www.bitrise.io/app/7514e4cf3da2cc57)
[Mapbox OS X SDK](platform/osx/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd)
diff --git a/bin/offline.cpp b/bin/offline.cpp
new file mode 100644
index 0000000000..a0adb6c2aa
--- /dev/null
+++ b/bin/offline.cpp
@@ -0,0 +1,76 @@
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/io.hpp>
+
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace std::literals::chrono_literals;
+
+int main(int, char * []) {
+ using namespace mbgl;
+
+ unlink("offline.db");
+
+ util::RunLoop loop;
+ DefaultFileSource fileSource("offline.db", ".");
+
+ fileSource.setAccessToken(getenv("MAPBOX_ACCESS_TOKEN"));
+
+ LatLngBounds bayArea = LatLngBounds::hull(LatLng(37.2, -122.8), LatLng(38.1, -121.7));
+ OfflineTilePyramidRegionDefinition definition("mapbox://styles/mapbox/streets-v8", bayArea, 0, 15, 1.0);
+ OfflineRegionMetadata metadata;
+
+ class Observer : public OfflineRegionObserver {
+ public:
+ Observer(util::RunLoop& loop_)
+ : loop(loop_),
+ start(SystemClock::now()) {
+ }
+
+ void statusChanged(OfflineRegionStatus status) override {
+ std::string bytesPerSecond = "-";
+
+ auto elapsedSeconds = (SystemClock::now() - start) / 1s;
+ if (elapsedSeconds != 0) {
+ bytesPerSecond = util::toString(status.completedResourceSize / elapsedSeconds);
+ }
+
+ std::cout << status.completedResourceCount << " / " << status.requiredResourceCount
+ << " resources"
+ << (status.requiredResourceCountIsIndeterminate ? " (indeterminate); " : "; ")
+ << status.completedResourceSize << " bytes downloaded"
+ << " (" << bytesPerSecond << " bytes/sec)"
+ << std::endl;
+
+ if (status.complete()) {
+ std::cout << "Finished" << std::endl;
+ loop.stop();
+ }
+ }
+
+ void responseError(Response::Error error) override {
+ std::cerr << error.reason << " downloading resource: " << error.message << std::endl;
+ }
+
+ util::RunLoop& loop;
+ SystemTimePoint start;
+ };
+
+ fileSource.createOfflineRegion(definition, metadata, [&] (std::exception_ptr error, optional<OfflineRegion> region) {
+ if (error) {
+ std::cerr << "Error creating region: " << util::toString(error) << std::endl;
+ loop.stop();
+ exit(1);
+ } else {
+ assert(region);
+ fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(loop));
+ fileSource.setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Active);
+ }
+ });
+
+ loop.run();
+ return 0;
+}
diff --git a/bin/offline.gypi b/bin/offline.gypi
new file mode 100644
index 0000000000..b5980ae76d
--- /dev/null
+++ b/bin/offline.gypi
@@ -0,0 +1,44 @@
+{
+ 'includes': [
+ '../gyp/common.gypi',
+ ],
+ 'targets': [
+ { 'target_name': 'mbgl-offline',
+ 'product_name': 'mbgl-offline',
+ 'type': 'executable',
+
+ 'dependencies': [
+ 'mbgl.gyp:core',
+ 'mbgl.gyp:platform-<(platform_lib)',
+ 'mbgl.gyp:headless-<(headless_lib)',
+ 'mbgl.gyp:http-<(http_lib)',
+ 'mbgl.gyp:asset-<(asset_lib)',
+ 'mbgl.gyp:copy_certificate_bundle',
+ ],
+
+ 'include_dirs': [
+ '../src',
+ ],
+
+ 'sources': [
+ './offline.cpp',
+ ],
+
+ 'variables' : {
+ 'cflags_cc': [
+ '<@(boost_cflags)',
+ ],
+ },
+
+ 'conditions': [
+ ['OS == "mac"', {
+ 'xcode_settings': {
+ 'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
+ }
+ }, {
+ 'cflags_cc': [ '<@(cflags_cc)' ],
+ }]
+ ],
+ },
+ ],
+}
diff --git a/gyp/common.gypi b/gyp/common.gypi
index c5eb30b3ab..d54a31b640 100644
--- a/gyp/common.gypi
+++ b/gyp/common.gypi
@@ -20,7 +20,6 @@
'-Wno-variadic-macros',
'-frtti',
'-fexceptions',
- '<@(variant_cflags)',
'${CFLAGS}',
],
'GCC_WARN_PEDANTIC': 'YES',
@@ -38,7 +37,6 @@
'-Wno-error=unused-parameter',
'-frtti',
'-fexceptions',
- '<@(variant_cflags)',
'${CFLAGS}',
],
}],
@@ -88,25 +86,56 @@
],
'configurations': {
'Debug': {
- 'cflags_cc': [ '-g', '-O0', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
+ 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
+ 'DEAD_CODE_STRIPPING': 'NO',
+ 'OTHER_CPLUSPLUSFLAGS': [ '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ],
+ 'conditions': [
+ ['coverage', {
+ 'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': 'YES',
+ 'GCC_GENERATE_TEST_COVERAGE_FILES': 'YES',
+ 'OTHER_CPLUSPLUSFLAGS': [ '--coverage' ],
+ }],
+ ],
+ },
+ }, {
+ 'cflags_cc': [ '-g', '-O0', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ],
+ 'conditions': [
+ ['coverage', { 'cflags_cc': [ '--coverage' ] }],
+ ],
+ }],
+ ],
'defines': [ 'DEBUG' ],
- 'xcode_settings': {
- 'GCC_OPTIMIZATION_LEVEL': '0',
- 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
- 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
- 'DEAD_CODE_STRIPPING': 'NO',
- 'OTHER_CPLUSPLUSFLAGS': [ '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common']
- }
+ 'target_conditions': [
+ ['_type == "executable"', {
+ 'conditions': [
+ ['OS=="mac" and coverage', {
+ 'xcode_settings': { 'OTHER_LDFLAGS': [ '--coverage' ] },
+ }, {
+ 'ldflags': [ '--coverage' ],
+ }],
+ ],
+ }],
+ ],
},
'Release': {
- 'cflags_cc': [ '-g', '-O3' ],
'defines': [ 'NDEBUG' ],
- 'xcode_settings': {
- 'GCC_OPTIMIZATION_LEVEL': '3',
- 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
- 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
- 'DEAD_CODE_STRIPPING': 'NO',
- }
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '3',
+ 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
+ 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
+ 'DEAD_CODE_STRIPPING': 'NO',
+ },
+ }, {
+ 'cflags_cc': [ '-g', '-O3' ],
+ }],
+ ],
},
},
}
diff --git a/gyp/core.gypi b/gyp/core.gypi
index acec3f15be..06497710d3 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -32,6 +32,7 @@
'<@(boost_cflags)',
'<@(geojsonvt_cflags)',
'<@(rapidjson_cflags)',
+ '<@(variant_cflags)',
],
'cflags': [
'<@(opengl_cflags)',
diff --git a/gyp/http-nsurl.gypi b/gyp/http-nsurl.gypi
index af15520c56..9c212ee7c0 100644
--- a/gyp/http-nsurl.gypi
+++ b/gyp/http-nsurl.gypi
@@ -7,7 +7,7 @@
'hard_dependency': 1,
'sources': [
- '../platform/darwin/http_request_nsurl.mm',
+ '../platform/darwin/src/http_request_nsurl.mm',
],
'include_dirs': [
diff --git a/gyp/ios.gyp b/gyp/ios.gyp
index e015318c45..6798384ef4 100644
--- a/gyp/ios.gyp
+++ b/gyp/ios.gyp
@@ -1,7 +1,7 @@
{
'includes': [
- '../ios/app/mapboxgl-app.gypi',
- '../ios/framework/framework-ios.gypi',
- '../ios/benchmark/benchmark-ios.gypi',
+ '../platform/ios/app/mapboxgl-app.gypi',
+ '../platform/ios/framework/framework-ios.gypi',
+ '../platform/ios/benchmark/benchmark-ios.gypi',
],
}
diff --git a/gyp/linux.gyp b/gyp/linux.gyp
index 51d304bc65..2815f4fc58 100644
--- a/gyp/linux.gyp
+++ b/gyp/linux.gyp
@@ -5,6 +5,7 @@
'conditions': [
['test', { 'includes': [ '../test/test.gypi' ] } ],
+ ['offline', { 'includes': [ '../bin/offline.gypi' ] } ],
['render', { 'includes': [ '../bin/render.gypi' ] } ],
],
}
diff --git a/gyp/osx.gyp b/gyp/osx.gyp
index 7501dd8ba0..18d5fe1524 100644
--- a/gyp/osx.gyp
+++ b/gyp/osx.gyp
@@ -4,7 +4,11 @@
'../platform/osx/sdk/framework-osx.gypi',
'../platform/osx/test/osxtest.gypi',
'../platform/linux/mapboxgl-app.gypi',
- '../test/test.gypi',
- '../bin/render.gypi',
+ ],
+
+ 'conditions': [
+ ['test', { 'includes': [ '../test/test.gypi' ] } ],
+ ['offline', { 'includes': [ '../bin/offline.gypi' ] } ],
+ ['render', { 'includes': [ '../bin/render.gypi' ] } ],
],
}
diff --git a/gyp/platform-android.gypi b/gyp/platform-android.gypi
index 8bb046a588..e31a9c9bec 100644
--- a/gyp/platform-android.gypi
+++ b/gyp/platform-android.gypi
@@ -21,7 +21,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
- '../platform/default/sqlite_cache.cpp',
+ '../platform/default/mbgl/storage/offline.hpp',
+ '../platform/default/mbgl/storage/offline.cpp',
+ '../platform/default/mbgl/storage/offline_database.hpp',
+ '../platform/default/mbgl/storage/offline_database.cpp',
+ '../platform/default/mbgl/storage/offline_download.hpp',
+ '../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
],
@@ -34,6 +39,8 @@
'<@(nunicode_cflags)',
'<@(boost_cflags)',
'<@(sqlite_cflags)',
+ '<@(rapidjson_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(libpng_ldflags)',
@@ -56,6 +63,7 @@
'include_dirs': [
'../include',
'../src',
+ '../platform/default',
],
'conditions': [
diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi
index f6d94b0e1c..dc52db7acd 100644
--- a/gyp/platform-ios.gypi
+++ b/gyp/platform-ios.gypi
@@ -16,29 +16,34 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
- '../platform/default/sqlite_cache.cpp',
+ '../platform/default/mbgl/storage/offline.hpp',
+ '../platform/default/mbgl/storage/offline.cpp',
+ '../platform/default/mbgl/storage/offline_database.hpp',
+ '../platform/default/mbgl/storage/offline_database.cpp',
+ '../platform/default/mbgl/storage/offline_download.hpp',
+ '../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
- '../platform/darwin/log_nslog.mm',
- '../platform/darwin/string_nsstring.mm',
- '../platform/darwin/application_root.mm',
- '../platform/darwin/image.mm',
- '../platform/darwin/nsthread.mm',
- '../platform/darwin/reachability.m',
- '../platform/darwin/NSException+MGLAdditions.h',
- '../platform/darwin/NSString+MGLAdditions.h',
- '../platform/darwin/NSString+MGLAdditions.m',
- '../platform/darwin/MGLTypes.m',
- '../platform/darwin/MGLStyle.mm',
- '../platform/darwin/MGLGeometry_Private.h',
- '../platform/darwin/MGLGeometry.mm',
- '../platform/darwin/MGLShape.m',
- '../platform/darwin/MGLMultiPoint_Private.h',
- '../platform/darwin/MGLMultiPoint.mm',
- '../platform/darwin/MGLPointAnnotation.m',
- '../platform/darwin/MGLPolyline.mm',
- '../platform/darwin/MGLPolygon.mm',
- '../platform/darwin/MGLMapCamera.mm',
+ '../platform/darwin/src/log_nslog.mm',
+ '../platform/darwin/src/string_nsstring.mm',
+ '../platform/darwin/src/application_root.mm',
+ '../platform/darwin/src/image.mm',
+ '../platform/darwin/src/nsthread.mm',
+ '../platform/darwin/src/reachability.m',
+ '../platform/darwin/src/NSException+MGLAdditions.h',
+ '../platform/darwin/src/NSString+MGLAdditions.h',
+ '../platform/darwin/src/NSString+MGLAdditions.m',
+ '../platform/darwin/src/MGLTypes.m',
+ '../platform/darwin/src/MGLStyle.mm',
+ '../platform/darwin/src/MGLGeometry_Private.h',
+ '../platform/darwin/src/MGLGeometry.mm',
+ '../platform/darwin/src/MGLShape.m',
+ '../platform/darwin/src/MGLMultiPoint_Private.h',
+ '../platform/darwin/src/MGLMultiPoint.mm',
+ '../platform/darwin/src/MGLPointAnnotation.m',
+ '../platform/darwin/src/MGLPolyline.mm',
+ '../platform/darwin/src/MGLPolygon.mm',
+ '../platform/darwin/src/MGLMapCamera.mm',
'../platform/ios/src/MGLMapboxEvents.h',
'../platform/ios/src/MGLMapboxEvents.m',
'../platform/ios/src/MGLMapView.mm',
@@ -50,7 +55,7 @@
'../platform/ios/src/MGLUserLocationAnnotationView.m',
'../platform/ios/src/MGLAnnotationImage_Private.h',
'../platform/ios/src/MGLAnnotationImage.m',
- '../include/mbgl/ios/MGLCalloutView.h',
+ '../platform/ios/include/MGLCalloutView.h',
'../platform/ios/src/MGLCompactCalloutView.h',
'../platform/ios/src/MGLCompactCalloutView.m',
'../platform/ios/src/NSBundle+MGLAdditions.h',
@@ -71,6 +76,8 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(zlib_cflags)',
+ '<@(rapidjson_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(sqlite_ldflags)',
@@ -94,10 +101,11 @@
},
'include_dirs': [
- '../include/mbgl/ios',
- '../include/mbgl/darwin',
+ '../platform/ios/include',
+ '../platform/darwin/include',
'../include',
'../src',
+ '../platform/default',
],
'xcode_settings': {
@@ -115,12 +123,13 @@
'direct_dependent_settings': {
'include_dirs': [
- '../include/mbgl/ios',
- '../include/mbgl/darwin',
+ '../platform/ios/include',
+ '../platform/darwin/include',
'../include',
],
'mac_bundle_resources': [
'<!@(find ../platform/ios/resources -type f \! -name "README" \! -name \'.*\')',
+ '<!@(find ../platform/default/resources -type f \! -name "README" \! -name \'.der\')',
],
},
},
diff --git a/gyp/platform-linux.gypi b/gyp/platform-linux.gypi
index 1513828821..8865f68e1e 100644
--- a/gyp/platform-linux.gypi
+++ b/gyp/platform-linux.gypi
@@ -23,7 +23,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
- '../platform/default/sqlite_cache.cpp',
+ '../platform/default/mbgl/storage/offline.hpp',
+ '../platform/default/mbgl/storage/offline.cpp',
+ '../platform/default/mbgl/storage/offline_database.hpp',
+ '../platform/default/mbgl/storage/offline_database.cpp',
+ '../platform/default/mbgl/storage/offline_download.hpp',
+ '../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
],
@@ -37,6 +42,8 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(webp_cflags)',
+ '<@(rapidjson_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(libpng_ldflags)',
@@ -61,6 +68,7 @@
'include_dirs': [
'../include',
'../src',
+ '../platform/default',
],
'conditions': [
diff --git a/gyp/platform-osx.gypi b/gyp/platform-osx.gypi
index 2aedce8538..581937ac66 100644
--- a/gyp/platform-osx.gypi
+++ b/gyp/platform-osx.gypi
@@ -15,29 +15,34 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
- '../platform/default/sqlite_cache.cpp',
+ '../platform/default/mbgl/storage/offline.hpp',
+ '../platform/default/mbgl/storage/offline.cpp',
+ '../platform/default/mbgl/storage/offline_database.hpp',
+ '../platform/default/mbgl/storage/offline_database.cpp',
+ '../platform/default/mbgl/storage/offline_download.hpp',
+ '../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
- '../platform/darwin/log_nslog.mm',
- '../platform/darwin/string_nsstring.mm',
- '../platform/darwin/application_root.mm',
- '../platform/darwin/image.mm',
- '../platform/darwin/nsthread.mm',
- '../platform/darwin/reachability.m',
- '../platform/darwin/NSException+MGLAdditions.h',
- '../platform/darwin/NSString+MGLAdditions.h',
- '../platform/darwin/NSString+MGLAdditions.m',
- '../platform/darwin/MGLTypes.m',
- '../platform/darwin/MGLStyle.mm',
- '../platform/darwin/MGLGeometry_Private.h',
- '../platform/darwin/MGLGeometry.mm',
- '../platform/darwin/MGLShape.m',
- '../platform/darwin/MGLMultiPoint_Private.h',
- '../platform/darwin/MGLMultiPoint.mm',
- '../platform/darwin/MGLPointAnnotation.m',
- '../platform/darwin/MGLPolyline.mm',
- '../platform/darwin/MGLPolygon.mm',
- '../platform/darwin/MGLMapCamera.mm',
+ '../platform/darwin/src/log_nslog.mm',
+ '../platform/darwin/src/string_nsstring.mm',
+ '../platform/darwin/src/application_root.mm',
+ '../platform/darwin/src/image.mm',
+ '../platform/darwin/src/nsthread.mm',
+ '../platform/darwin/src/reachability.m',
+ '../platform/darwin/src/NSException+MGLAdditions.h',
+ '../platform/darwin/src/NSString+MGLAdditions.h',
+ '../platform/darwin/src/NSString+MGLAdditions.m',
+ '../platform/darwin/src/MGLTypes.m',
+ '../platform/darwin/src/MGLStyle.mm',
+ '../platform/darwin/src/MGLGeometry_Private.h',
+ '../platform/darwin/src/MGLGeometry.mm',
+ '../platform/darwin/src/MGLShape.m',
+ '../platform/darwin/src/MGLMultiPoint_Private.h',
+ '../platform/darwin/src/MGLMultiPoint.mm',
+ '../platform/darwin/src/MGLPointAnnotation.m',
+ '../platform/darwin/src/MGLPolyline.mm',
+ '../platform/darwin/src/MGLPolygon.mm',
+ '../platform/darwin/src/MGLMapCamera.mm',
'../platform/osx/src/MGLAccountManager_Private.h',
'../platform/osx/src/MGLAccountManager.m',
'../platform/osx/src/MGLMapView_Private.h',
@@ -62,6 +67,8 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(zlib_cflags)',
+ '<@(rapidjson_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(zlib_ldflags)',
@@ -79,10 +86,11 @@
},
'include_dirs': [
- '../include/mbgl/osx',
- '../include/mbgl/darwin',
+ '../platform/osx/include',
+ '../platform/darwin/include',
'../include',
'../src',
+ '../platform/default',
],
'xcode_settings': {
@@ -100,8 +108,8 @@
'direct_dependent_settings': {
'include_dirs': [
- '../include/mbgl/osx',
- '../include/mbgl/darwin',
+ '../platform/osx/include',
+ '../platform/darwin/include',
'../include',
],
'mac_bundle_resources': [
diff --git a/include/mbgl/platform/gl.hpp b/include/mbgl/gl/gl.hpp
index 1e98ea7f3b..2d9b3f7a71 100644
--- a/include/mbgl/platform/gl.hpp
+++ b/include/mbgl/gl/gl.hpp
@@ -1,5 +1,5 @@
-#ifndef MBGL_RENDERER_GL
-#define MBGL_RENDERER_GL
+#ifndef MBGL_GL_GL
+#define MBGL_GL_GL
//#define GL_TRACK
@@ -110,6 +110,32 @@ public:
using glProc = void (*)();
void InitializeExtensions(glProc (*getProcAddress)(const char *));
+static gl::ExtensionFunction<
+ void (GLuint array)>
+ BindVertexArray({
+ {"GL_ARB_vertex_array_object", "glBindVertexArray"},
+ {"GL_OES_vertex_array_object", "glBindVertexArrayOES"},
+ {"GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE"}
+ });
+
+static gl::ExtensionFunction<
+ void (GLsizei n,
+ const GLuint* arrays)>
+ DeleteVertexArrays({
+ {"GL_ARB_vertex_array_object", "glDeleteVertexArrays"},
+ {"GL_OES_vertex_array_object", "glDeleteVertexArraysOES"},
+ {"GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE"}
+ });
+
+static gl::ExtensionFunction<
+ void (GLsizei n,
+ GLuint* arrays)>
+ GenVertexArrays({
+ {"GL_ARB_vertex_array_object", "glGenVertexArrays"},
+ {"GL_OES_vertex_array_object", "glGenVertexArraysOES"},
+ {"GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE"}
+ });
+
} // namespace gl
} // namespace mbgl
diff --git a/include/mbgl/gl/gl_helper.hpp b/include/mbgl/gl/gl_helper.hpp
new file mode 100644
index 0000000000..4f3990a434
--- /dev/null
+++ b/include/mbgl/gl/gl_helper.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_GL_GL_HELPER
+#define MBGL_GL_GL_HELPER
+
+namespace mbgl {
+namespace gl {
+
+template <typename T>
+class Preserve {
+public:
+ inline Preserve() : data(T::Get()) {
+ }
+ inline ~Preserve() {
+ T::Set(data);
+ }
+
+private:
+ const typename T::Type data;
+};
+
+} // namespace gl
+} // namespace mbgl
+
+#endif
diff --git a/src/mbgl/renderer/gl_config.hpp b/include/mbgl/gl/gl_values.hpp
index 2f21b35fe3..a5d413f5af 100644
--- a/src/mbgl/renderer/gl_config.hpp
+++ b/include/mbgl/gl/gl_values.hpp
@@ -1,41 +1,15 @@
-#ifndef MBGL_RENDERER_GL_CONFIG
-#define MBGL_RENDERER_GL_CONFIG
+#ifndef MBGL_GL_GL_VALUES
+#define MBGL_GL_GL_VALUES
#include <cstdint>
#include <tuple>
#include <array>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
namespace mbgl {
namespace gl {
-template <typename T>
-class Value {
-public:
- inline void operator=(const typename T::Type& value) {
- if (dirty || current != value) {
- dirty = false;
- current = value;
- T::Set(current);
- }
- }
-
- inline void reset() {
- dirty = true;
- current = T::Default;
- T::Set(current);
- }
-
- inline void setDirty() {
- dirty = true;
- }
-
-private:
- typename T::Type current = T::Default;
- bool dirty = false;
-};
-
struct ClearDepth {
using Type = GLfloat;
static const Type Default;
@@ -266,64 +240,37 @@ struct LineWidth {
}
};
-class Config {
-public:
- void reset() {
- stencilFunc.reset();
- stencilMask.reset();
- stencilTest.reset();
- stencilOp.reset();
- depthRange.reset();
- depthMask.reset();
- depthTest.reset();
- depthFunc.reset();
- blend.reset();
- blendFunc.reset();
- colorMask.reset();
- clearDepth.reset();
- clearColor.reset();
- clearStencil.reset();
- program.reset();
- lineWidth.reset();
- }
+#ifndef GL_ES_VERSION_2_0
- void setDirty() {
- stencilFunc.setDirty();
- stencilMask.setDirty();
- stencilTest.setDirty();
- stencilOp.setDirty();
- depthRange.setDirty();
- depthMask.setDirty();
- depthTest.setDirty();
- depthFunc.setDirty();
- blend.setDirty();
- blendFunc.setDirty();
- colorMask.setDirty();
- clearDepth.setDirty();
- clearColor.setDirty();
- clearStencil.setDirty();
- program.setDirty();
- lineWidth.setDirty();
+struct PixelZoom {
+ struct Type { GLfloat xfactor; GLfloat yfactor; };
+ static const Type Default;
+ inline static void Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPixelZoom(value.xfactor, value.yfactor));
+ }
+ inline static Type Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_X, &value.xfactor));
+ MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_Y, &value.yfactor));
+ return value;
}
+};
- Value<StencilFunc> stencilFunc;
- Value<StencilMask> stencilMask;
- Value<StencilTest> stencilTest;
- Value<StencilOp> stencilOp;
- Value<DepthRange> depthRange;
- Value<DepthMask> depthMask;
- Value<DepthTest> depthTest;
- Value<DepthFunc> depthFunc;
- Value<Blend> blend;
- Value<BlendFunc> blendFunc;
- Value<ColorMask> colorMask;
- Value<ClearDepth> clearDepth;
- Value<ClearColor> clearColor;
- Value<ClearStencil> clearStencil;
- Value<Program> program;
- Value<LineWidth> lineWidth;
+struct RasterPos {
+ using Type = std::array<GLdouble, 4>;
+ static const Type Default;
+ inline static void Set(const Type& value) {
+ MBGL_CHECK_ERROR(glRasterPos4d(value[0], value[1], value[2], value[3]));
+ }
+ inline static Type Get() {
+ Type pos;
+ MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos.data()));
+ return pos;
+ }
};
+#endif
+
} // namespace gl
} // namespace mbgl
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index 1afe7e86f6..688565fecb 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -165,6 +165,8 @@ public:
AnnotationID addShapeAnnotation(const ShapeAnnotation&);
AnnotationIDs addShapeAnnotations(const std::vector<ShapeAnnotation>&);
+ void updatePointAnnotation(AnnotationID, const PointAnnotation&);
+
void removeAnnotation(AnnotationID);
void removeAnnotations(const AnnotationIDs&);
diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp
index 0e46f7d87e..ae5bf340d5 100644
--- a/include/mbgl/platform/default/glfw_view.hpp
+++ b/include/mbgl/platform/default/glfw_view.hpp
@@ -6,6 +6,7 @@
#ifdef MBGL_USE_GLES2
#define GLFW_INCLUDE_ES2
#endif
+#define GL_GLEXT_PROTOTYPES
#include <GLFW/glfw3.h>
#include <atomic>
@@ -51,6 +52,9 @@ private:
makeSpriteImage(int width, int height, float pixelRatio);
void nextOrientation();
+ void toggleClipMasks();
+
+ void renderClipMasks();
void addRandomPointAnnotations(int count);
void addRandomShapeAnnotations(int count);
@@ -80,6 +84,8 @@ private:
int fbHeight;
float pixelRatio;
+ bool showClipMasks = false;
+
double lastX = 0, lastY = 0;
double lastClick = -1;
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp
index 68f32ed1ca..8f8d11b297 100644
--- a/include/mbgl/platform/default/headless_view.hpp
+++ b/include/mbgl/platform/default/headless_view.hpp
@@ -14,7 +14,7 @@ typedef XID GLXPbuffer;
#endif
#include <mbgl/mbgl.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <memory>
#include <thread>
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index bedea25bef..d55e12b778 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -2,25 +2,100 @@
#define MBGL_STORAGE_DEFAULT_FILE_SOURCE
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/util/constants.hpp>
+
+#include <vector>
namespace mbgl {
+namespace util {
+template <typename T> class Thread;
+} // namespace util
+
class DefaultFileSource : public FileSource {
public:
- DefaultFileSource(const std::string& cachePath, const std::string& assetRoot);
+ DefaultFileSource(const std::string& cachePath,
+ const std::string& assetRoot,
+ uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
~DefaultFileSource() override;
void setAccessToken(const std::string&);
std::string getAccessToken() const;
- void setMaximumCacheSize(uint64_t size);
- void setMaximumCacheEntrySize(uint64_t size);
-
std::unique_ptr<FileRequest> request(const Resource&, Callback) override;
-private:
+ /*
+ * Retrieve all regions in the offline database.
+ *
+ * The query will be executed asynchronously and the results passed to the given
+ * callback, which 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.
+ */
+ void listOfflineRegions(std::function<void (std::exception_ptr,
+ optional<std::vector<OfflineRegion>>)>);
+
+ /*
+ * Create an offline region in the database.
+ *
+ * When the initial database queries have completed, the provided 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.
+ *
+ * Note that the resulting region will be in an inactive download state; to begin
+ * downloading resources, call `setOfflineRegionDownloadState(OfflineRegionDownloadState::Active)`,
+ * optionally registering an `OfflineRegionObserver` beforehand.
+ */
+ void createOfflineRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr,
+ optional<OfflineRegion>)>);
+
+ /*
+ * Register an observer to be notified when the state of the region changes.
+ */
+ void setOfflineRegionObserver(OfflineRegion&, std::unique_ptr<OfflineRegionObserver>);
+
+ /*
+ * Pause or resume downloading of regional resources.
+ */
+ void setOfflineRegionDownloadState(OfflineRegion&, OfflineRegionDownloadState);
+
+ /*
+ * Retrieve the current status of the region. The query will be executed
+ * asynchronously and the results passed to the given callback, which 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.
+ */
+ void getOfflineRegionStatus(OfflineRegion&, std::function<void (std::exception_ptr,
+ optional<OfflineRegionStatus>)>) const;
+
+ /*
+ * Remove an offline region from the database and perform any resources evictions
+ * necessary as a result.
+ *
+ * Eviction works by removing the least-recently requested resources not also required
+ * by other regions, until the database shrinks below a certain size.
+ *
+ * Note that this method takes ownership of the input, reflecting the fact that once
+ * region deletion is initiated, it is not legal to perform further actions with the
+ * region.
+ *
+ * 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.
+ */
+ void deleteOfflineRegion(OfflineRegion&&, std::function<void (std::exception_ptr)>);
+
+ // For testing only.
+ void put(const Resource&, const Response&);
+ void goOffline();
+
class Impl;
- const std::unique_ptr<Impl> impl;
+
+private:
+ const std::unique_ptr<util::Thread<Impl>> thread;
+ const std::unique_ptr<FileSource> assetFileSource;
};
} // namespace mbgl
diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp
new file mode 100644
index 0000000000..dd63cf968f
--- /dev/null
+++ b/include/mbgl/storage/offline.hpp
@@ -0,0 +1,181 @@
+#pragma once
+
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/storage/response.hpp>
+
+#include <string>
+#include <vector>
+#include <functional>
+
+namespace mbgl {
+
+class TileID;
+class SourceInfo;
+
+/*
+ * An offline region defined by a style URL, geographic bounding box, zoom range, and
+ * device pixel ratio.
+ *
+ * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
+ *
+ * maxZoom may be ∞, in which case for each tile source, the region will include
+ * tiles from minZoom up to the maximum zoom level provided by that source.
+ *
+ * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
+ */
+class OfflineTilePyramidRegionDefinition {
+public:
+ OfflineTilePyramidRegionDefinition(const std::string&, const LatLngBounds&, double, double, float);
+
+ /* Private */
+ std::vector<TileID> tileCover(SourceType, uint16_t tileSize, const SourceInfo&) const;
+
+ const std::string styleURL;
+ const LatLngBounds bounds;
+ const double minZoom;
+ const double maxZoom;
+ const float pixelRatio;
+};
+
+/*
+ * For the present, a tile pyramid is the only type of offline region. In the future,
+ * other definition types will be available and this will be a variant type.
+ */
+using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition;
+
+/*
+ * The encoded format is private.
+ */
+std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition&);
+OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string&);
+
+/*
+ * Arbitrary binary region metadata. The contents are opaque to the mbgl implementation;
+ * it just stores and retrieves a BLOB. SDK bindings should leave the interpretation of
+ * this data up to the application; they _should not_ enforce a higher-level data format.
+ * In the future we want offline database to be portable across target platforms, and a
+ * platform-specific metadata format would prevent that.
+ */
+using OfflineRegionMetadata = std::vector<uint8_t>;
+
+/*
+ * A region is either inactive (not downloading, but previously-downloaded
+ * resources are available for use), or active (resources are being downloaded
+ * or will be downloaded, if necessary, when network access is available).
+ *
+ * This state is independent of whether or not the complete set of resources
+ * is currently available for offline use. To check if that is the case, use
+ * `OfflineRegionStatus::complete()`.
+ */
+enum class OfflineRegionDownloadState {
+ Inactive,
+ Active
+};
+
+/*
+ * A region's status includes its active/inactive state as well as counts
+ * of the number of resources that have completed downloading, their total
+ * size in bytes, and the total number of resources that are required.
+ *
+ * Note that the total required size in bytes is not currently available. A
+ * future API release may provide an estimate of this number.
+ */
+class OfflineRegionStatus {
+public:
+ OfflineRegionDownloadState downloadState = OfflineRegionDownloadState::Inactive;
+
+ /**
+ * The number of resources that have been fully downloaded and are ready for
+ * offline access.
+ */
+ uint64_t completedResourceCount = 0;
+
+ /**
+ * The cumulative size, in bytes, of all resources that have been fully downloaded.
+ */
+ uint64_t completedResourceSize = 0;
+
+ /**
+ * The number of resources that are known to be required for this region. See the
+ * documentation for `requiredResourceCountIsIndeterminate` for an important caveat
+ * about this number.
+ */
+ uint64_t requiredResourceCount = 0;
+
+ /**
+ * This property is true during early phases of an offline download, when the total
+ * required resource count is unknown and requiredResourceCount is merely a lower
+ * bound.
+ *
+ * Specifically, it is true before until the style and tile sources have been
+ * downloaded, and false thereafter.
+ */
+ bool requiredResourceCountIsIndeterminate = true;
+
+ bool complete() const {
+ return completedResourceCount == requiredResourceCount;
+ }
+};
+
+/*
+ * A region can have a single observer, which gets notified whenever a change
+ * to the region's status occurs.
+ */
+class OfflineRegionObserver {
+public:
+ virtual ~OfflineRegionObserver() = default;
+
+ /*
+ * Implement this method to be notified of a change in the status of an
+ * offline region. Status changes include any change in state of the members
+ * of OfflineRegionStatus.
+ *
+ * Note that this method will be executed on the database thread; it is the
+ * responsibility of the SDK bindings to wrap this object in an interface that
+ * re-executes the user-provided implementation on the main thread.
+ */
+ virtual void statusChanged(OfflineRegionStatus) {}
+
+ /*
+ * Implement this method to be notified of errors encountered while downloading
+ * regional resources. Such errors may be recoverable; for example the implementation
+ * will attempt to re-request failed resources based on an exponential backoff
+ * algorithm, or when it detects that network access has been restored.
+ *
+ * Note that this method will be executed on the database thread; it is the
+ * responsibility of the SDK bindings to wrap this object in an interface that
+ * re-executes the user-provided implementation on the main thread.
+ */
+ virtual void responseError(Response::Error) {}
+};
+
+class OfflineRegion {
+public:
+ // Move-only; not publicly constructible.
+ OfflineRegion(OfflineRegion&&);
+ OfflineRegion& operator=(OfflineRegion&&);
+ ~OfflineRegion();
+
+ OfflineRegion() = delete;
+ OfflineRegion(const OfflineRegion&) = delete;
+ OfflineRegion& operator=(const OfflineRegion&) = delete;
+
+ int64_t getID() const;
+ const OfflineRegionDefinition& getDefinition() const;
+ const OfflineRegionMetadata& getMetadata() const;
+
+private:
+ friend class OfflineDatabase;
+
+ OfflineRegion(int64_t id,
+ const OfflineRegionDefinition&,
+ const OfflineRegionMetadata&);
+
+ const int64_t id;
+ const OfflineRegionDefinition definition;
+ const OfflineRegionMetadata metadata;
+};
+
+} // namespace mbgl
diff --git a/include/mbgl/storage/online_file_source.hpp b/include/mbgl/storage/online_file_source.hpp
index bdf14c7b34..aceb141fb4 100644
--- a/include/mbgl/storage/online_file_source.hpp
+++ b/include/mbgl/storage/online_file_source.hpp
@@ -5,15 +5,13 @@
namespace mbgl {
-class SQLiteCache;
-
namespace util {
template <typename T> class Thread;
} // namespace util
class OnlineFileSource : public FileSource {
public:
- OnlineFileSource(SQLiteCache*);
+ OnlineFileSource();
~OnlineFileSource() override;
void setAccessToken(const std::string& t) { accessToken = t; }
@@ -22,11 +20,8 @@ public:
std::unique_ptr<FileRequest> request(const Resource&, Callback) override;
private:
- friend class OnlineFileRequest;
friend class OnlineFileRequestImpl;
- void cancel(FileRequest*);
-
class Impl;
const std::unique_ptr<util::Thread<Impl>> thread;
std::string accessToken;
diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp
index c97384e6a7..edd9f58c72 100644
--- a/include/mbgl/storage/resource.hpp
+++ b/include/mbgl/storage/resource.hpp
@@ -31,7 +31,7 @@ public:
Resource(Kind kind_, const std::string& url_, optional<TileData> tileData_ = {})
: kind(kind_),
url(url_),
- tileData(tileData_) {
+ tileData(std::move(tileData_)) {
}
static Resource style(const std::string& url);
@@ -47,8 +47,8 @@ public:
static Resource spriteImage(const std::string& base, float pixelRatio);
static Resource spriteJSON(const std::string& base, float pixelRatio);
- const Kind kind;
- const std::string url;
+ Kind kind;
+ std::string url;
// Includes auxiliary data if this is a tile request.
optional<TileData> tileData;
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
index a44902e1f9..bec1efe6b1 100644
--- a/include/mbgl/storage/response.hpp
+++ b/include/mbgl/storage/response.hpp
@@ -20,10 +20,14 @@ public:
// When this object is empty, the response was successful.
std::unique_ptr<const Error> error;
+ // This is set to true for 204 Not Modified responses, and, for backward compatibility,
+ // for 404 Not Found responses for tiles.
+ bool noContent = false;
+
// This is set to true for 304 Not Modified responses.
bool notModified = false;
- // The actual data of the response. This is null if notModified is true.
+ // The actual data of the response. Present only for non-error, non-notModified responses.
std::shared_ptr<const std::string> data;
optional<SystemTimePoint> modified;
@@ -49,6 +53,8 @@ public:
Error(Reason, const std::string& = "");
};
+std::ostream& operator<<(std::ostream&, Response::Error::Reason);
+
} // namespace mbgl
#endif
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index 24f4b5ee72..9ddbcb2568 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -21,6 +21,8 @@ extern const double PITCH_MAX;
extern const double MIN_ZOOM;
extern const double MAX_ZOOM;
+extern const uint64_t DEFAULT_MAX_CACHE_SIZE;
+
} // namespace util
namespace debug {
diff --git a/include/mbgl/util/gl_helper.hpp b/include/mbgl/util/gl_helper.hpp
deleted file mode 100644
index 7d104fb80e..0000000000
--- a/include/mbgl/util/gl_helper.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef MBGL_UTIL_GL_HELPER
-#define MBGL_UTIL_GL_HELPER
-
-#include <mbgl/platform/gl.hpp>
-
-#include <array>
-
-namespace {
-
-template <typename T, T (*Create)(), void (*Destroy)(const T&)>
-class Preserve {
-public:
- Preserve() : data(Create()) {}
- ~Preserve() { Destroy(data); }
-
-private:
- const T data;
-};
-
-inline bool getBlend() {
- return glIsEnabled(GL_BLEND);
-}
-
-inline void setBlend(const bool& enabled) {
- enabled ? MBGL_CHECK_ERROR(glEnable(GL_BLEND)) : MBGL_CHECK_ERROR(glDisable(GL_BLEND));
-}
-
-inline std::array<float, 4> getClearColor() {
- std::array<float, 4> color;
- MBGL_CHECK_ERROR(glGetFloatv(GL_COLOR_CLEAR_VALUE, color.data()));
- return color;
-}
-
-inline void setClearColor(const std::array<float, 4>& color) {
- MBGL_CHECK_ERROR(glClearColor(color[0], color[1], color[2], color[3]));
-}
-
-
-inline std::array<GLenum, 2> getBlendFunc() {
- GLint func[2];
- glGetIntegerv(GL_BLEND_SRC_ALPHA, &func[0]);
- glGetIntegerv(GL_BLEND_DST_ALPHA, &func[1]);
- return {{ static_cast<GLenum>(func[0]), static_cast<GLenum>(func[1]) }};
-}
-
-inline void setBlendFunc(const std::array<GLenum, 2>& func) {
- MBGL_CHECK_ERROR(glBlendFunc(func[0], func[1]));
-}
-
-#ifndef GL_ES_VERSION_2_0
-inline std::array<double, 2> getPixelZoom() {
- std::array<double, 2> zoom;
- glGetDoublev(GL_ZOOM_X, &zoom[0]);
- glGetDoublev(GL_ZOOM_Y, &zoom[1]);
- return zoom;
-}
-
-inline void setPixelZoom(const std::array<double, 2>& func) {
- MBGL_CHECK_ERROR(glPixelZoom(func[0], func[1]));
-}
-
-
-inline std::array<double, 4> getRasterPos() {
- std::array<double, 4> pos;
- MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos.data()));
- return pos;
-}
-
-inline void setRasterPos(const std::array<double, 4>& pos) {
- MBGL_CHECK_ERROR(glRasterPos4d(pos[0], pos[1], pos[2], pos[3]));
-}
-#endif
-} // end anonymous namespace
-
-namespace mbgl {
-namespace gl {
-
-using PreserveBlend = Preserve<bool, getBlend, setBlend>;
-using PreserveClearColor = Preserve<std::array<float, 4>, getClearColor, setClearColor>;
-using PreserveBlendFunc = Preserve<std::array<GLenum, 2>, getBlendFunc, setBlendFunc>;
-
-#ifndef GL_ES_VERSION_2_0
-using PreservePixelZoom = Preserve<std::array<double, 2>, getPixelZoom, setPixelZoom>;
-using PreserveRasterPos = Preserve<std::array<double, 4>, getRasterPos, setRasterPos>;
-#endif
-
-} // namespace gl
-} // namespace mbgl
-
-#endif
diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp
index 9be0568e12..08625ffc0c 100644
--- a/include/mbgl/util/math.hpp
+++ b/include/mbgl/util/math.hpp
@@ -88,6 +88,11 @@ inline T dist(const S1& a, const S2& b) {
}
template <typename T>
+inline T round(const T& a) {
+ return T(::round(a.x), ::round(a.y));
+}
+
+template <typename T>
inline T length(T a, T b) {
return std::sqrt(a * a + b * b);
}
diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp
index 6075d76c8c..fbc4794940 100644
--- a/include/mbgl/util/run_loop.hpp
+++ b/include/mbgl/util/run_loop.hpp
@@ -41,9 +41,6 @@ public:
void runOnce();
void stop();
- void ref();
- void unref();
-
// So far only needed by the libcurl backend.
void addWatch(int fd, Event, std::function<void(int, Event)>&& callback);
void removeWatch(int fd);
diff --git a/ios/README.md b/ios/README.md
deleted file mode 100644
index a5ee2d37e5..0000000000
--- a/ios/README.md
+++ /dev/null
@@ -1 +0,0 @@
-The Mapbox iOS SDK is [located here](../platform/ios/).
diff --git a/ios/benchmark/MBXBenchAppDelegate.m b/ios/benchmark/MBXBenchAppDelegate.m
deleted file mode 100644
index e8fbd88d28..0000000000
--- a/ios/benchmark/MBXBenchAppDelegate.m
+++ /dev/null
@@ -1,15 +0,0 @@
-#import "MBXBenchAppDelegate.h"
-#import "MBXBenchViewController.h"
-
-@implementation MBXBenchAppDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.window.rootViewController = [MBXBenchViewController new];
- [self.window makeKeyAndVisible];
-
- return YES;
-}
-
-@end
diff --git a/package.json b/package.json
index d97d3f56e7..57452a060b 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
],
"devDependencies": {
"aws-sdk": "^2.2.21",
- "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#2b4ed672dc7e7e60f98115e3eb2dc55125b96e66",
+ "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#8859b504ef241bca49d4c2f9a79ff4d0bfdf81a1",
"node-gyp": "^3.2.1",
"request": "^2.67.0",
"tape": "^4.2.2"
diff --git a/platform/android/INSTALL_LINUX.md b/platform/android/INSTALL_LINUX.md
index 219bb7d0e9..353d0269d0 100644
--- a/platform/android/INSTALL_LINUX.md
+++ b/platform/android/INSTALL_LINUX.md
@@ -21,7 +21,7 @@ In the Android SDK Manager also select and install "Android Support Repository"
_The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._
-gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environ variable and save it to `"MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from.
+gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environ variable and save it to `"MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise, you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`.
## Building
diff --git a/platform/android/INSTALL_OSX.md b/platform/android/INSTALL_OSX.md
index f82bb80da0..00096ebc60 100644
--- a/platform/android/INSTALL_OSX.md
+++ b/platform/android/INSTALL_OSX.md
@@ -22,7 +22,7 @@ By default, the Android SDK will be installed to `/Users/<user>/Library/Android/
_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/)._
If you start Android Studio from your terminal, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise,
-you can edit `developer-config.xml` and add the value manually.
+you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`.
## Developing In Android Studio
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 8b44873a27..b9e294966e 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -25,7 +25,7 @@ dependencies {
compile "com.android.support:support-annotations:${supportLibVersion}"
compile "com.android.support:support-v4:${supportLibVersion}"
compile "com.android.support:design:${supportLibVersion}"
- compile 'com.squareup.okhttp3:okhttp:3.0.1'
+ compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.mapzen.android:lost:1.0.1'
}
@@ -66,6 +66,9 @@ android {
consumerProguardFiles 'proguard-rules.pro'
}
}
+
+// resourcePrefix 'mapbox_'
+
}
configurations {
diff --git a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
index 85754a75a5..98647f5518 100644
--- a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
@@ -15,8 +15,11 @@
# Package: http
-keep class com.mapbox.mapboxsdk.http.** { *; }
-# Package views
--keep class com.mapbox.mapboxsdk.views.** { *; }
+# Package maps
+-keep class com.mapbox.mapboxsdk.maps.** { *; }
+
+# Package telemetry
+-keep class com.mapbox.mapboxsdk.telemetry.** { *; }
# Package layers
-keep class com.mapbox.mapboxsdk.layers.** { *; }
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
index 1b8b54c86f..0307d462c8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
@@ -5,5 +5,6 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
</manifest>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
new file mode 100644
index 0000000000..5b1eebdb1b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
@@ -0,0 +1,38 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+public abstract class BaseMarkerOptions<U extends Marker, T extends BaseMarkerOptions<U, T>> implements Parcelable {
+
+ protected LatLng position;
+ protected String snippet;
+ protected String title;
+ protected Icon icon;
+
+ public T position(LatLng position) {
+ this.position = position;
+ return getThis();
+ }
+
+ public T snippet(String snippet) {
+ this.snippet = snippet;
+ return getThis();
+ }
+
+ public T title(String title) {
+ this.title = title;
+ return getThis();
+ }
+
+ public T icon(Icon icon) {
+ this.icon = icon;
+ return getThis();
+ }
+
+ public abstract T getThis();
+
+ public abstract U getMarker();
+
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
index bee4ec47c5..d7d41b98be 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
@@ -150,4 +150,8 @@ public final class IconFactory {
}
return fromInputStream(is);
}
+
+ public static Icon recreate(@NonNull String iconId, @NonNull Bitmap bitmap) {
+ return new Icon(iconId, bitmap);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
index 9c79ffcbd9..d8763e321d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
@@ -53,22 +53,35 @@ public class InfoWindow {
mIsVisible = false;
mView = new WeakReference<>(view);
- // default behavior: close it when clicking on the tooltip:
- view.setOnTouchListener(new View.OnTouchListener() {
+ view.setOnClickListener(new View.OnClickListener() {
@Override
- public boolean onTouch(View v, MotionEvent e) {
- if (e.getAction() == MotionEvent.ACTION_UP) {
+ public void onClick(View v) {
+ MapboxMap mapboxMap = mMapboxMap.get();
+ if (mapboxMap != null) {
+ MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener = mapboxMap.getOnInfoWindowClickListener();
boolean handledDefaultClick = false;
- MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener =
- mMapboxMap.get().getOnInfoWindowClickListener();
if (onInfoWindowClickListener != null) {
- handledDefaultClick = onInfoWindowClickListener.onMarkerClick(getBoundMarker());
+ handledDefaultClick = onInfoWindowClickListener.onInfoWindowClick(getBoundMarker());
}
if (!handledDefaultClick) {
+ // default behavior: close it when clicking on the tooltip:
close();
}
}
+ }
+ });
+
+ view.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ MapboxMap mapboxMap = mMapboxMap.get();
+ if (mapboxMap != null) {
+ MapboxMap.OnInfoWindowLongClickListener listener = mapboxMap.getOnInfoWindowLongClickListener();
+ if (listener != null) {
+ listener.onInfoWindowLongClick(getBoundMarker());
+ }
+ }
return true;
}
});
@@ -179,11 +192,10 @@ public class InfoWindow {
if (mIsVisible) {
mIsVisible = false;
View view = mView.get();
- if (view != null) {
+ if (view != null && view.getParent() != null) {
((ViewGroup) view.getParent()).removeView(view);
- setBoundMarker(null);
- onClose();
}
+ onClose();
}
return this;
}
@@ -210,7 +222,12 @@ public class InfoWindow {
private void onClose() {
MapboxMap mapboxMap = mMapboxMap.get();
if (mapboxMap != null) {
+ MapboxMap.OnInfoWindowCloseListener listener = mapboxMap.getOnInfoWindowCloseListener();
+ if (listener != null) {
+ listener.onInfoWindowClose(getBoundMarker());
+ }
mapboxMap.deselectMarker(getBoundMarker());
+ setBoundMarker(null);
}
}
@@ -237,4 +254,8 @@ public class InfoWindow {
}
}
+ boolean isVisible() {
+ return mIsVisible;
+ }
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
index 27c9c03697..c2683cbb56 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
@@ -15,7 +15,7 @@ import com.mapbox.mapboxsdk.maps.MapView;
* An {@link InfoWindow} can be shown when a Marker is pressed
* <p/>
*/
-public final class Marker extends Annotation {
+public class Marker extends Annotation {
private LatLng position;
private String snippet;
@@ -32,6 +32,13 @@ public final class Marker extends Annotation {
super();
}
+ public Marker(BaseMarkerOptions baseMarkerOptions) {
+ position = baseMarkerOptions.position;
+ snippet = baseMarkerOptions.snippet;
+ icon = baseMarkerOptions.icon;
+ title = baseMarkerOptions.title;
+ }
+
public LatLng getPosition() {
return position;
}
@@ -61,8 +68,17 @@ public final class Marker extends Annotation {
return infoWindowShown;
}
- void setPosition(LatLng position) {
+ /**
+ * Sets the position.
+ *
+ * @param position new position
+ */
+ public void setPosition(LatLng position) {
this.position = position;
+ MapboxMap map = getMapboxMap();
+ if (map != null) {
+ map.updateMarker(this);
+ }
}
void setSnippet(String snippet) {
@@ -70,10 +86,16 @@ public final class Marker extends Annotation {
}
/**
- * Do not use this method. Used internally by the SDK.
+ * Sets the icon.
+ *
+ * @param icon The icon to be used as Marker image
*/
public void setIcon(@Nullable Icon icon) {
this.icon = icon;
+ MapboxMap map = getMapboxMap();
+ if (map != null) {
+ map.updateMarker(this);
+ }
}
public Icon getIcon() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
index a83a6991b2..5cc54cd1ca 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
@@ -12,9 +12,9 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
* <p>
* Builder for composing {@link com.mapbox.mapboxsdk.annotations.Marker} objects.
* </p>
- *
+ * <p/>
* <h3>Example</h3>
- *
+ * <p/>
* <pre>
* mMapView.addMarker(new MarkerOptions()
* .title("Intersection")
@@ -22,7 +22,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
* .position(new LatLng(38.9002073, -77.03364419)));
* </pre>
*/
-public final class MarkerOptions implements Parcelable {
+public final class MarkerOptions extends BaseMarkerOptions<Marker, MarkerOptions> implements Parcelable {
public static final Parcelable.Creator<MarkerOptions> CREATOR
= new Parcelable.Creator<MarkerOptions>() {
@@ -47,6 +47,11 @@ public final class MarkerOptions implements Parcelable {
}
@Override
+ public MarkerOptions getThis() {
+ return this;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
@@ -72,43 +77,27 @@ public final class MarkerOptions implements Parcelable {
* @return Marker The build marker
*/
public Marker getMarker() {
+ marker.setPosition(position);
+ marker.setSnippet(snippet);
+ marker.setTitle(title);
+ marker.setIcon(icon);
return marker;
}
public LatLng getPosition() {
- return marker.getPosition();
+ return position;
}
public String getSnippet() {
- return marker.getSnippet();
+ return snippet;
}
public String getTitle() {
- return marker.getTitle();
+ return title;
}
public Icon getIcon() {
- return marker.getIcon();
- }
-
- public MarkerOptions position(LatLng position) {
- marker.setPosition(position);
- return this;
- }
-
- public MarkerOptions snippet(String snippet) {
- marker.setSnippet(snippet);
- return this;
- }
-
- public MarkerOptions icon(@Nullable Icon icon) {
- marker.setIcon(icon);
- return this;
- }
-
- public MarkerOptions title(String title) {
- marker.setTitle(title);
- return this;
+ return icon;
}
@Override
@@ -125,7 +114,6 @@ public final class MarkerOptions implements Parcelable {
if (getIcon() != null ? !getIcon().equals(marker.getIcon()) : marker.getIcon() != null)
return false;
return !(getTitle() != null ? !getTitle().equals(marker.getTitle()) : marker.getTitle() != null);
-
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index 004e7f5f84..ec2f0eb316 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -9,7 +9,6 @@ import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MathConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
import com.mapbox.mapboxsdk.utils.MathUtils;
public final class CameraPosition implements Parcelable {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdate.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java
index 0f3e710134..c6852624ef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdate.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.camera;
import android.support.annotation.NonNull;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index cad5152316..df156961a0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.camera;
import android.graphics.Point;
import android.graphics.PointF;
@@ -6,15 +6,17 @@ import android.graphics.RectF;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
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 com.mapbox.mapboxsdk.utils.MathUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-public class CameraUpdateFactory {
+public final class CameraUpdateFactory {
/**
* Returns a CameraUpdate that moves the camera to a specified CameraPosition.
@@ -144,7 +146,7 @@ public class CameraUpdateFactory {
// CameraUpdate types
//
- public static class CameraPositionUpdate implements CameraUpdate {
+ static final class CameraPositionUpdate implements CameraUpdate {
private final float bearing;
private final LatLng target;
@@ -189,7 +191,7 @@ public class CameraUpdateFactory {
}
}
- public static class CameraBoundsUpdate implements CameraUpdate {
+ static final class CameraBoundsUpdate implements CameraUpdate {
private LatLngBounds bounds;
private RectF padding;
@@ -217,39 +219,40 @@ public class CameraUpdateFactory {
@Override
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
- MapView mapView = mapboxMap.getMapView();
+ // Get required objects
+ Projection projection = mapboxMap.getProjection();
+ UiSettings uiSettings = mapboxMap.getUiSettings();
RectF padding = getPadding();
- // Calculate the bounds of the possibly rotated shape with respect to the viewport.
+ // Calculate the bounds of the possibly rotated shape with respect to the viewport
PointF nePixel = new PointF(-10000, -10000);
- PointF swPixel = new PointF(1000, 10000);
- float viewportHeight = mapView.getHeight();
+ PointF swPixel = new PointF(10000, 10000);
+ float viewportHeight = uiSettings.getHeight();
for (LatLng latLng : getBounds().toLatLngs()) {
- PointF pixel = mapView.toScreenLocation(latLng);
+ PointF pixel = projection.toScreenLocation(latLng);
swPixel.x = Math.min(swPixel.x, pixel.x);
nePixel.x = Math.max(nePixel.x, pixel.x);
swPixel.y = Math.min(swPixel.y, viewportHeight - pixel.y);
nePixel.y = Math.max(nePixel.y, viewportHeight - pixel.y);
}
+ // Calculate wid=th/height
float width = nePixel.x - swPixel.x;
float height = nePixel.y - swPixel.y;
- // Calculate the zoom level.
- float scaleX = (mapView.getWidth() - padding.left - padding.right) / width;
- float scaleY = (mapView.getHeight() - padding.top - padding.bottom) / height;
+ // Calculate the zoom level
+ float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width;
+ float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height;
float minScale = scaleX < scaleY ? scaleX : scaleY;
- double zoom = Math.log(mapView.getScale() * minScale) / Math.log(2);
- zoom = MathUtils.clamp(zoom, (float) mapView.getMinZoom(), (float) mapView.getMaxZoom());
+ double zoom = projection.calculateZoom(minScale);
+ zoom = MathUtils.clamp(zoom, (float) uiSettings.getMinZoom(), (float) uiSettings.getMaxZoom());
- // Calculate the center point of a virtual bounds that is extended in all directions by padding.
+ // Calculate the center point
PointF paddedNEPixel = new PointF(nePixel.x + padding.right / minScale, nePixel.y + padding.top / minScale);
PointF paddedSWPixel = new PointF(swPixel.x - padding.left / minScale, swPixel.y - padding.bottom / minScale);
PointF centerPixel = new PointF((paddedNEPixel.x + paddedSWPixel.x) / 2, (paddedNEPixel.y + paddedSWPixel.y) / 2);
-
centerPixel.y = viewportHeight - centerPixel.y;
-
- LatLng center = mapboxMap.getProjection().fromScreenLocation(centerPixel);
+ LatLng center = projection.fromScreenLocation(centerPixel);
return new CameraPosition.Builder()
.target(center)
@@ -260,7 +263,7 @@ public class CameraUpdateFactory {
}
}
- public static class CameraMoveUpdate implements CameraUpdate {
+ static final class CameraMoveUpdate implements CameraUpdate {
private float x;
private float y;
@@ -272,15 +275,16 @@ public class CameraUpdateFactory {
@Override
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
- MapView mapView = mapboxMap.getMapView();
+ UiSettings uiSettings = mapboxMap.getUiSettings();
+ Projection projection = mapboxMap.getProjection();
// Calculate the new center point
- float viewPortWidth = mapView.getWidth();
- float viewPortHeight = mapView.getHeight();
+ float viewPortWidth = uiSettings.getWidth();
+ float viewPortHeight = uiSettings.getHeight();
PointF targetPoint = new PointF(viewPortWidth / 2 + x, viewPortHeight / 2 + y);
// Convert point to LatLng
- LatLng latLng = mapView.fromScreenLocation(targetPoint);
+ LatLng latLng = projection.fromScreenLocation(targetPoint);
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
return new CameraPosition.Builder()
@@ -292,7 +296,7 @@ public class CameraUpdateFactory {
}
}
- public static class ZoomUpdate implements CameraUpdate {
+ static final class ZoomUpdate implements CameraUpdate {
@IntDef({ZOOM_IN, ZOOM_OUT, ZOOM_BY, ZOOM_TO, ZOOM_TO_POINT})
@Retention(RetentionPolicy.SOURCE)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
index 33ebfca2fa..f04087818b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
@@ -18,6 +18,16 @@ public class MapboxConstants {
public static final String KEY_META_DATA_MANIFEST = "com.mapbox.AccessToken";
/**
+ * Key used to store staging data server url in AndroidManifest.xml
+ */
+ public static final String KEY_META_DATA_STAGING_SERVER = "com.mapbox.TestEventsServer";
+
+ /**
+ * Key used to store staging data server access token in AndroidManifest.xml
+ */
+ public static final String KEY_META_DATA_STAGING_ACCESS_TOKEN = "com.mapbox.TestEventsAccessToken";
+
+ /**
* Default animation time
*/
public static final int ANIMATION_DURATION = 300;
@@ -58,6 +68,7 @@ public class MapboxConstants {
public static final String FRAG_ARG_MAPBOXMAPOPTIONS = "MapboxMapOptions";
// Save instance state keys
+ public static final String STATE_HAS_SAVED_STATE = "savedState";
public static final String STATE_CAMERA_POSITION = "cameraPosition";
public static final String STATE_ZOOM_ENABLED = "zoomEnabled";
public static final String STATE_SCROLL_ENABLED = "scrollEnabled";
@@ -91,4 +102,8 @@ public class MapboxConstants {
public static final String STATE_ATTRIBUTION_ENABLED = "atrrEnabled";
public static final String TAG = "MapboxMap";
+
+ public static final String MAPBOX_SHARED_PREFERENCES_FILE = "MapboxSharedPreferences";
+ public static final String MAPBOX_SHARED_PREFERENCE_KEY_VENDORID = "mapboxVendorId";
+ public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED = "mapboxTelemetryEnabled";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
index 2374a98fc1..383a85417c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
@@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
index a8008d3742..9b0ae7285e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
@@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java
new file mode 100644
index 0000000000..54908aa58b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java
@@ -0,0 +1,18 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+import android.os.Bundle;
+import com.mapbox.mapboxsdk.maps.MapView;
+
+/**
+ * A {@code TelemetryServiceNotConfiguredException} is thrown by {@link MapView} when it checks and finds that
+ * TelemetryService has not been configured in the app's AndroidManifest.xml {@link MapView#onCreate(Bundle)}
+ *
+ * @see MapView#onCreate(Bundle)
+ */
+public class TelemetryServiceNotConfiguredException extends RuntimeException {
+
+ public TelemetryServiceNotConfiguredException() {
+ super("Using Mapbox Android SDK requires configuring TelemetryService. See the INSTALL.md");
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
index 349120d1f3..de562c3632 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
@@ -67,6 +67,7 @@ public class VisibleRegion implements Parcelable {
* 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.
*/
@@ -89,7 +90,15 @@ public class VisibleRegion implements Parcelable {
@Override
public String toString() {
- return "[farLeft [" + farLeft + "], farRight [" + farRight + "], nearLeft [" + nearLeft + "], nearRight [" + nearRight + "], latLngBounds ["+latLngBounds+"]]";
+ return "[farLeft [" + farLeft + "], farRight [" + farRight + "], nearLeft [" + nearLeft + "], nearRight [" + nearRight + "], latLngBounds [" + latLngBounds + "]]";
+ }
+
+ @Override
+ public int hashCode() {
+ return ((farLeft.hashCode() + 90)
+ + ((farRight.hashCode() + 90) * 1000)
+ + ((nearLeft.hashCode() + 180) * 1000000)
+ + ((nearRight.hashCode() + 180) * 1000000000));
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java
index c385820423..f787085d2f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java
@@ -2,12 +2,15 @@ package com.mapbox.mapboxsdk.location;
import android.location.Location;
+/**
+ * Callback interface for when a location change occurs.
+ */
public interface LocationListener {
/**
- * Callback method for receiving location updates from LocationServices.
+ * Callback method for receiving location updates from LocationService.
* @param location The new Location data
*/
- public void onLocationChanged(Location location);
+ void onLocationChanged(Location location);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationService.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationService.java
new file mode 100644
index 0000000000..f459b5ad53
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationService.java
@@ -0,0 +1,166 @@
+package com.mapbox.mapboxsdk.location;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.location.LocationManager;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver;
+import com.mapzen.android.lost.api.LocationRequest;
+import com.mapzen.android.lost.api.LostApiClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LocationService implements com.mapzen.android.lost.api.LocationListener {
+
+ private static final String TAG = "LocationService";
+
+ private static LocationService instance;
+
+ private Context context;
+ private LostApiClient locationClient;
+ private Location lastLocation;
+
+ private List<LocationListener> locationListeners;
+
+ private boolean isGPSEnabled;
+
+ /**
+ * Private constructor for singleton LocationService
+ */
+ private LocationService(Context context) {
+ super();
+ this.context = context;
+ // Setup location services
+ locationClient = new LostApiClient.Builder(context).build();
+ locationListeners = new ArrayList<>();
+ }
+
+ /**
+ * Primary (singleton) access method for LocationService
+ *
+ * @param context Context
+ * @return LocationService
+ */
+ public static LocationService getInstance(@NonNull final Context context) {
+ if (instance == null) {
+ instance = new LocationService(context.getApplicationContext());
+ }
+ return instance;
+ }
+
+ /**
+ * Enabled / Disable GPS focused location tracking
+ *
+ * @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled
+ */
+ public void toggleGPS(boolean enableGPS) {
+ if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) &&
+ (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ Log.w(TAG, "Location Permissions Not Granted Yet. Try again after requesting.");
+ return;
+ }
+
+ // Disconnect
+ if (locationClient.isConnected()) {
+ // Disconnect first to ensure that the new requests are GPS
+ com.mapzen.android.lost.api.LocationServices.FusedLocationApi.removeLocationUpdates(this);
+ locationClient.disconnect();
+ }
+
+ // Setup Fresh
+ locationClient.connect();
+ Location lastLocation = com.mapzen.android.lost.api.LocationServices.FusedLocationApi.getLastLocation();
+ if (lastLocation != null) {
+ this.lastLocation = lastLocation;
+ }
+
+ LocationRequest locationRequest;
+
+ if (enableGPS) {
+ // LocationRequest Tuned for GPS
+ locationRequest = LocationRequest.create()
+ .setFastestInterval(1000)
+ .setSmallestDisplacement(3.0f)
+ .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
+
+ com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this);
+ } else {
+ // LocationRequest Tuned for PASSIVE
+ locationRequest = LocationRequest.create()
+ .setFastestInterval(1000)
+ .setSmallestDisplacement(3.0f)
+ .setPriority(LocationRequest.PRIORITY_NO_POWER);
+
+ com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this);
+ }
+
+ isGPSEnabled = enableGPS;
+ }
+
+ /**
+ * Returns if the GPS sensor is currently enabled
+ *
+ * @return active state of the GPS
+ */
+ public boolean isGPSEnabled() {
+ return isGPSEnabled;
+ }
+
+ /**
+ * Called when the location has changed.
+ *
+ * @param location The updated location
+ */
+ @Override
+ public void onLocationChanged(Location location) {
+ Log.i(TAG, "onLocationChanged()..." + location);
+ this.lastLocation = location;
+
+ // Update Listeners
+ for (LocationListener listener : this.locationListeners) {
+ listener.onLocationChanged(location);
+ }
+
+ // Update the Telemetry Receiver
+ Intent locIntent = new Intent(TelemetryLocationReceiver.INTENT_STRING);
+ locIntent.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
+ context.sendBroadcast(locIntent);
+ }
+
+ /**
+ * Last known location
+ *
+ * @return Last known location data
+ */
+ public Location getLastLocation() {
+ return lastLocation;
+ }
+
+ /**
+ * Registers a LocationListener to receive location updates
+ *
+ * @param locationListener LocationListener
+ */
+ public void addLocationListener(@NonNull LocationListener locationListener) {
+ if (!this.locationListeners.contains(locationListener)) {
+ this.locationListeners.add(locationListener);
+ }
+ }
+
+ /**
+ * Unregister a LocationListener to stop receiving location updates
+ *
+ * @param locationListener LocationListener to remove
+ * @return True if LocationListener was found and removed, False if it was not
+ */
+ public boolean removeLocationListener(@NonNull LocationListener locationListener) {
+ return this.locationListeners.remove(locationListener);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
deleted file mode 100644
index ac2ab64076..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.mapbox.mapboxsdk.location;
-
-import android.content.Context;
-import android.location.Location;
-import android.support.annotation.NonNull;
-import com.mapzen.android.lost.api.LocationRequest;
-import com.mapzen.android.lost.api.LostApiClient;
-import java.util.ArrayList;
-import java.util.List;
-
-public class LocationServices implements com.mapzen.android.lost.api.LocationListener {
-
- private static LocationServices instance = null;
-
- private LostApiClient mLocationClient;
- private LocationRequest mLocationRequest;
-
- private Location lastLocation = null;
-
- private List<LocationListener> locationListeners = null;
-
- private boolean isGPSEnabled = false;
-
- /**
- * Private constructor for singleton LocationServices
- */
- private LocationServices(Context context) {
- super();
- // Setup location services
- mLocationClient = new LostApiClient.Builder(context).build();
- locationListeners = new ArrayList<>();
- }
-
- /**
- * Primary (singleton) access method for LocationServices
- * @param context Context
- * @return LocationServices
- */
- public static LocationServices getLocationServices(@NonNull final Context context) {
- if (instance == null) {
- if (context == null) {
- throw new NullPointerException("Context required for accessing LocationServices");
- }
- instance = new LocationServices(context.getApplicationContext());
- }
- return instance;
- }
-
- /**
- * Enabled / Disable GPS focused location tracking
- *
- * @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled
- */
- public void toggleGPS(boolean enableGPS) {
-
- if (enableGPS) {
-
- if (mLocationClient.isConnected()) {
- // Disconnect first to ensure that the new requests are GPS
- com.mapzen.android.lost.api.LocationServices.FusedLocationApi.removeLocationUpdates(this);
- mLocationClient.disconnect();
- }
-
- // Setup Fresh
- mLocationClient.connect();
- Location lastLocation = com.mapzen.android.lost.api.LocationServices.FusedLocationApi.getLastLocation();
- if (lastLocation != null) {
- this.lastLocation = lastLocation;
- }
-
- // LocationRequest Tuned for GPS
- mLocationRequest = LocationRequest.create()
- .setFastestInterval(1000)
- .setSmallestDisplacement(3.0f)
- .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
-
- com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, this);
-
- } else {
-
- // Disconnect
- if (mLocationClient.isConnected()) {
- // Disconnect first to ensure that the new requests are GPS
- com.mapzen.android.lost.api.LocationServices.FusedLocationApi.removeLocationUpdates(this);
- mLocationClient.disconnect();
- }
-
- }
-
- isGPSEnabled = enableGPS;
- }
-
- public boolean isGPSEnabled() {
- return isGPSEnabled;
- }
-
- @Override
- public void onLocationChanged(Location location) {
- this.lastLocation = location;
-
- // Update Listeners
- for (LocationListener listener : this.locationListeners) {
- listener.onLocationChanged(location);
- }
- }
-
- /**
- * Last known location
- * @return Last known location data
- */
- public Location getLastLocation() {
- return lastLocation;
- }
-
- /**
- * Registers a LocationListener to receive location updates
- * @param locationListener LocationListener
- */
- public void addLocationListener(@NonNull LocationListener locationListener) {
- if(!this.locationListeners.contains(locationListener)){
- this.locationListeners.add(locationListener);
- }
- }
-
- /**
- * Unregister a LocationListener to stop receiving location updates
- * @param locationListener LocationListener to remove
- * @return True if LocationListener was found and removed, False if it was not
- */
- public boolean removeLocationListener(@NonNull LocationListener locationListener) {
- return this.locationListeners.remove(locationListener);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
index 2789e85ed8..4b5aa0cbaf 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.maps;
import android.app.Fragment;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
@@ -29,18 +30,10 @@ public class MapFragment extends Fragment {
private MapView mMap;
- public static MapFragment newInstance(){
+ public static MapFragment newInstance() {
return new MapFragment();
}
- public static MapFragment newInstance(MapboxMapOptions mapboxMapOptions) {
- final MapFragment mapFragment = new MapFragment();
- Bundle bundle = new Bundle();
- bundle.putParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS, mapboxMapOptions);
- mapFragment.setArguments(bundle);
- return mapFragment;
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
@@ -94,7 +87,12 @@ public class MapFragment extends Fragment {
}
@NonNull
- public void getMapAsync(@NonNull OnMapReadyCallback onMapReadyCallback){
- mMap.getMapAsync(onMapReadyCallback);
+ public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ mMap.getMapAsync(onMapReadyCallback);
+ }
+ });
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index bd0a010900..cb9459d5f2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -10,7 +10,9 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -27,8 +29,8 @@ import android.support.annotation.FloatRange;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.RequiresPermission;
import android.support.annotation.UiThread;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ScaleGestureDetectorCompat;
import android.support.v7.app.AlertDialog;
@@ -47,44 +49,50 @@ import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewConfiguration;
+import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.ListView;
import android.widget.ZoomButtonsController;
-
import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
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.annotations.IconFactory;
import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.exceptions.TelemetryServiceNotConfiguredException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.layers.CustomLayer;
+import com.mapbox.mapboxsdk.maps.widgets.CompassView;
+import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
+import com.mapbox.mapboxsdk.telemetry.MapboxEvent;
+import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
import com.mapbox.mapboxsdk.utils.ApiAccess;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* <p>
@@ -111,7 +119,6 @@ public class MapView extends FrameLayout {
private static final float DIMENSION_SEVENTYSIX_DP = 76f;
private MapboxMap mMapboxMap;
- private List<Annotation> mAnnotations;
private List<Icon> mIcons;
private NativeMapView mNativeMapView;
@@ -120,7 +127,7 @@ public class MapView extends FrameLayout {
private ImageView mAttributionsView;
private UserLocationView mUserLocationView;
- private List<OnMapChangedListener> mOnMapChangedListener;
+ private CopyOnWriteArrayList<OnMapChangedListener> mOnMapChangedListener;
private ZoomButtonsController mZoomButtonsController;
private ConnectivityReceiver mConnectivityReceiver;
private float mScreenDensity = 1.0f;
@@ -133,13 +140,12 @@ public class MapView extends FrameLayout {
private boolean mTwoTap = false;
private boolean mZoomStarted = false;
private boolean mQuickZoom = false;
+ private boolean mScrollInProgress = false;
- /*
private int mContentPaddingLeft;
private int mContentPaddingTop;
private int mContentPaddingRight;
private int mContentPaddingBottom;
-*/
@UiThread
public MapView(@NonNull Context context) {
@@ -160,11 +166,9 @@ public class MapView extends FrameLayout {
}
private void initialize(@NonNull Context context, @Nullable AttributeSet attrs) {
- mOnMapChangedListener = new ArrayList<>();
+ mOnMapChangedListener = new CopyOnWriteArrayList<>();
mMapboxMap = new MapboxMap(this);
- mAnnotations = new ArrayList<>();
mIcons = new ArrayList<>();
-
View view = LayoutInflater.from(context).inflate(R.layout.mapview_internal, this);
if (!isInEditMode()) {
@@ -200,7 +204,7 @@ public class MapView extends FrameLayout {
// Shows the zoom controls
if (!context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) {
- mMapboxMap.setZoomControlsEnabled(true);
+ mMapboxMap.getUiSettings().setZoomControlsEnabled(true);
}
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION);
@@ -210,9 +214,9 @@ public class MapView extends FrameLayout {
onConnectivityChanged(isConnected());
mUserLocationView = (UserLocationView) view.findViewById(R.id.userLocationView);
- mUserLocationView.setMapView(this);
+ mUserLocationView.setMapboxMap(mMapboxMap);
mCompassView = (CompassView) view.findViewById(R.id.compassView);
- mCompassView.setOnClickListener(new CompassView.CompassClickListener(this));
+ mCompassView.setOnClickListener(new CompassView.CompassClickListener(mMapboxMap));
mLogoView = (ImageView) view.findViewById(R.id.logoView);
// Setup Attributions control
@@ -232,13 +236,15 @@ public class MapView extends FrameLayout {
mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
// Access token
- if (typedArray.getString(R.styleable.MapView_access_token) != null) {
+ String accessToken = typedArray.getString(R.styleable.MapView_access_token);
+ if (accessToken != null) {
setAccessToken(typedArray.getString(R.styleable.MapView_access_token));
}
// Style url
- if (typedArray.getString(R.styleable.MapView_style_url) != null) {
- mMapboxMap.setStyleUrl(typedArray.getString(R.styleable.MapView_style_url));
+ String styleUrl = typedArray.getString(R.styleable.MapView_style_url);
+ if (styleUrl != null) {
+ mMapboxMap.setStyleUrl(styleUrl);
}
// Enable gestures
@@ -249,6 +255,10 @@ public class MapView extends FrameLayout {
uiSettings.setTiltGesturesEnabled(typedArray.getBoolean(R.styleable.MapView_tilt_enabled, true));
uiSettings.setZoomControlsEnabled(typedArray.getBoolean(R.styleable.MapView_zoom_controls_enabled, false));
+ // Zoom
+ uiSettings.setMaxZoom(typedArray.getFloat(R.styleable.MapView_zoom_max, (float) MapboxConstants.MAXIMUM_ZOOM));
+ uiSettings.setMinZoom(typedArray.getFloat(R.styleable.MapView_zoom_min, (float) MapboxConstants.MINIMUM_ZOOM));
+
// Compass
uiSettings.setCompassEnabled(typedArray.getBoolean(R.styleable.MapView_compass_enabled, true));
uiSettings.setCompassGravity(typedArray.getInt(R.styleable.MapView_compass_gravity, Gravity.TOP | Gravity.END));
@@ -274,13 +284,7 @@ public class MapView extends FrameLayout {
, (int) (typedArray.getDimension(R.styleable.MapView_attribution_margin_bottom, DIMENSION_SEVEN_DP) * mScreenDensity));
// User location
- try {
- //noinspection ResourceType
- mMapboxMap.setMyLocationEnabled(typedArray.getBoolean(R.styleable.MapView_my_location_enabled, false));
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
-
+ mMapboxMap.setMyLocationEnabled(typedArray.getBoolean(R.styleable.MapView_my_location_enabled, false));
} finally {
typedArray.recycle();
}
@@ -303,7 +307,7 @@ public class MapView extends FrameLayout {
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
- if (savedInstanceState != null) {
+ if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
// Get previous camera position
CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION);
@@ -357,10 +361,17 @@ public class MapView extends FrameLayout {
// User did not accept location permissions
}
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
//noinspection ResourceType
- mMapboxMap.setMyLocationTrackingMode(savedInstanceState.getInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE));
+ trackingSettings.setMyLocationTrackingMode(savedInstanceState.getInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE));
//noinspection ResourceType
- mMapboxMap.setMyBearingTrackingMode(savedInstanceState.getInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE));
+ trackingSettings.setMyBearingTrackingMode(savedInstanceState.getInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE));
+ } else {
+ // Force a check for Telemetry
+ validateTelemetryServiceConfigured();
+
+ // Start Telemetry (authorization determined in initial MapboxEventManager constructor)
+ MapboxEventManager.getMapboxEventManager(getContext()).isTelemetryEnabled();
}
// Force a check for an access token
@@ -381,6 +392,16 @@ public class MapView extends FrameLayout {
}
}
});
+
+ // Fire MapLoad
+ if (savedInstanceState == null) {
+ Hashtable<String, Object> evt = new Hashtable<>();
+ evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_LOAD);
+ evt.put(MapboxEvent.KEY_LATITUDE, mMapboxMap.getCameraPosition().target.getLatitude());
+ evt.put(MapboxEvent.KEY_LONGITUDE, mMapboxMap.getCameraPosition().target.getLongitude());
+ evt.put(MapboxEvent.KEY_ZOOM, mMapboxMap.getCameraPosition().zoom);
+ MapboxEventManager.getMapboxEventManager(getContext()).pushEvent(evt);
+ }
}
/**
@@ -392,14 +413,19 @@ public class MapView extends FrameLayout {
@UiThread
public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, mMapboxMap.getCameraPosition());
outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, mMapboxMap.isDebugActive());
outState.putString(MapboxConstants.STATE_STYLE_URL, mMapboxMap.getStyleUrl());
outState.putString(MapboxConstants.STATE_ACCESS_TOKEN, mMapboxMap.getAccessToken());
outState.putLong(MapboxConstants.STATE_DEFAULT_TRANSITION_DURATION, mNativeMapView.getDefaultTransitionDuration());
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, mMapboxMap.isMyLocationEnabled());
- outState.putInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, mMapboxMap.getMyLocationTrackingMode());
- outState.putInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, mMapboxMap.getMyBearingTrackingMode());
+
+
+ // TrackingSettings
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+ outState.putInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, trackingSettings.getMyLocationTrackingMode());
+ outState.putInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, trackingSettings.getMyBearingTrackingMode());
// UiSettings
UiSettings uiSettings = mMapboxMap.getUiSettings();
@@ -554,13 +580,13 @@ public class MapView extends FrameLayout {
}
//
- // Rotation
+ // Direction
//
/**
- * Returns the current heading of the map relative to true north.
+ * Returns the current direction of the map relative to true north.
*
- * @return The current heading measured in degrees.
+ * @return The current direction measured in degrees.
*/
@UiThread
@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION)
@@ -633,6 +659,46 @@ public class MapView extends FrameLayout {
}
//
+ // Content padding
+ //
+
+ /**
+ * Return The current content padding left of the map view viewport.
+ *
+ * @return The current content padding left
+ */
+ int getContentPaddingLeft() {
+ return mContentPaddingLeft;
+ }
+
+ /**
+ * Return The current content padding left of the map view viewport.
+ *
+ * @return The current content padding left
+ */
+ int getContentPaddingTop() {
+ return mContentPaddingTop;
+ }
+
+ /**
+ * Return The current content padding left of the map view viewport.
+ *
+ * @return The current content padding right
+ */
+ int getContentPaddingRight() {
+ return mContentPaddingRight;
+ }
+
+ /**
+ * Return The current content padding left of the map view viewport.
+ *
+ * @return The current content padding bottom
+ */
+ int getContentPaddingBottom() {
+ return mContentPaddingBottom;
+ }
+
+ //
// Zoom
//
@@ -647,51 +713,6 @@ public class MapView extends FrameLayout {
return mNativeMapView.getZoom();
}
-// /**
-// * Return The current content padding left of the map view viewport.
-// *
-// * @return The current content padding left
-// */
-///*
-// public int getContentPaddingLeft() {
-// return mContentPaddingLeft;
-// }
-//*/
-//
-// /**
-// * Return The current content padding left of the map view viewport.
-// *
-// * @return The current content padding left
-// */
-///*
-// public int getContentPaddingTop() {
-// return mContentPaddingTop;
-// }
-//*/
-//
-// /**
-// * Return The current content padding left of the map view viewport.
-// *
-// * @return The current content padding left
-// */
-///*
-// public int getContentPaddingRight() {
-// return mContentPaddingRight;
-// }
-//*/
-//
-// /**
-// * Return The current content padding left of the map view viewport.
-// *
-// * @param zoomLevel The new zoom level.
-// * @param animated If true, animates the change. If false, immediately changes the map.
-// * @see MapboxMap#MAXIMUM_ZOOM
-// */
-///*
-// public int getContentPaddingBottom() {
-// return mContentPaddingBottom;
-//*/
-
/**
* <p>
* Sets the minimum zoom level the map can be displayed at.
@@ -712,7 +733,7 @@ public class MapView extends FrameLayout {
* @return The minimum zoom level.
*/
@UiThread
- public double getMinZoom() {
+ double getMinZoom() {
return mNativeMapView.getMinZoom();
}
@@ -724,7 +745,7 @@ public class MapView extends FrameLayout {
* @param maxZoom The new maximum zoom level.
*/
@UiThread
- public void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
+ void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
mNativeMapView.setMaxZoom(maxZoom);
}
@@ -736,7 +757,7 @@ public class MapView extends FrameLayout {
* @return The maximum zoom level.
*/
@UiThread
- public double getMaxZoom() {
+ double getMaxZoom() {
return mNativeMapView.getMaxZoom();
}
@@ -866,6 +887,28 @@ public class MapView extends FrameLayout {
}
}
+ // Checks that TelemetryService has been configured by developer
+ private void validateTelemetryServiceConfigured() {
+
+ try {
+ // Check Implementing app's AndroidManifest.xml
+ PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), PackageManager.GET_SERVICES);
+
+ if (packageInfo.services != null) {
+
+ for (ServiceInfo service : packageInfo.services) {
+ if (TextUtils.equals("com.mapbox.mapboxsdk.telemetry.TelemetryService", service.name)) {
+ return;
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ Log.w(TAG, "Error checking for Telemetry Service Config: " + e);
+ }
+ throw new TelemetryServiceNotConfiguredException();
+ }
+
/**
* <p>
* Sets the current Mapbox access token used to load map styles and tiles.
@@ -942,7 +985,25 @@ public class MapView extends FrameLayout {
// Annotations
//
- private void loadIcon(Icon icon) {
+ Icon loadIconForMarker(Marker marker) {
+ Icon icon = marker.getIcon();
+ if (icon == null) {
+ icon = IconFactory.getInstance(getContext()).defaultMarker();
+ marker.setIcon(icon);
+ }
+ if (!mIcons.contains(icon)) {
+ mIcons.add(icon);
+ loadIcon(icon);
+ } else {
+ Icon oldIcon = mIcons.get(mIcons.indexOf(icon));
+ if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
+ throw new IconBitmapChangedException();
+ }
+ }
+ return icon;
+ }
+
+ void loadIcon(Icon icon) {
Bitmap bitmap = icon.getBitmap();
String id = icon.getId();
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
@@ -964,7 +1025,7 @@ public class MapView extends FrameLayout {
scale, buffer.array());
}
- private void reloadIcons() {
+ void reloadIcons() {
int count = mIcons.size();
for (int i = 0; i < count; i++) {
Icon icon = mIcons.get(i);
@@ -972,8 +1033,35 @@ public class MapView extends FrameLayout {
}
}
+ /**
+ * <p>
+ * Updates a marker on this map. Does nothing if the marker is already added.
+ * </p>
+ *
+ * @param updatedMarker An updated marker object.
+ */
+ @UiThread
+ void updateMarker(@NonNull Marker updatedMarker) {
+ if (updatedMarker == null) {
+ Log.w(TAG, "marker was null, doing nothing");
+ return;
+ }
+
+ if (updatedMarker.getId() == -1) {
+ Log.w(TAG, "marker has an id of -1, possibly was not added yet, doing nothing");
+ }
+
+ ensureIconLoaded(updatedMarker);
+ mNativeMapView.updateMarker(updatedMarker);
+ }
+
private Marker prepareMarker(MarkerOptions markerOptions) {
Marker marker = markerOptions.getMarker();
+ ensureIconLoaded(marker);
+ return marker;
+ }
+
+ private void ensureIconLoaded(Marker marker) {
Icon icon = marker.getIcon();
if (icon == null) {
icon = IconFactory.getInstance(getContext()).defaultMarker();
@@ -988,270 +1076,48 @@ public class MapView extends FrameLayout {
throw new IconBitmapChangedException();
}
}
- marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
- return marker;
- }
- /**
- * <p>
- * Adds a marker to this map.
- * </p>
- * 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.
- */
- @UiThread
- @NonNull
- Marker addMarker(@NonNull MarkerOptions markerOptions) {
- if (markerOptions == null) {
- Log.w(TAG, "markerOptions was null, so just returning null");
- return null;
+ // 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) mMapboxMap.getAnnotation(marker.getId()) : null;
+ if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
+ marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
-
- Marker marker = prepareMarker(markerOptions);
- long id = mNativeMapView.addMarker(marker);
- marker.setId(id); // the annotation needs to know its id
- marker.setMapboxMap(mMapboxMap); // the annotation needs to know which map view it is in
- mAnnotations.add(marker);
- return marker;
}
- /**
- * <p>
- * Adds multiple markers to this map.
- * </p>
- * 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.
- */
- @UiThread
- @NonNull
- List<Marker> addMarkers(@NonNull List<MarkerOptions> markerOptionsList) {
- if (markerOptionsList == null) {
- Log.w(TAG, "markerOptionsList was null, so just returning null");
- return null;
- }
-
- int count = markerOptionsList.size();
- List<Marker> markers = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- MarkerOptions markerOptions = markerOptionsList.get(i);
- Marker marker = prepareMarker(markerOptions);
- markers.add(marker);
- }
-
- long[] ids = mNativeMapView.addMarkers(markers);
- Marker m;
- for (int i = 0; i < count; i++) {
- m = markers.get(i);
- m.setId(ids[i]);
- m.setMapboxMap(mMapboxMap);
- mAnnotations.add(m);
+ long addMarker(@NonNull Marker marker) {
+ if (mNativeMapView == null) {
+ return 0l;
}
-
- return new ArrayList<>(markers);
+ return mNativeMapView.addMarker(marker);
}
- /**
- * 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.
- */
- @UiThread
- @NonNull
- Polyline addPolyline(@NonNull PolylineOptions polylineOptions) {
- if (polylineOptions == null) {
- Log.w(TAG, "polylineOptions was null, so just returning null");
- return null;
- }
-
- Polyline polyline = polylineOptions.getPolyline();
- long id = mNativeMapView.addPolyline(polyline);
- polyline.setId(id);
- polyline.setMapboxMap(mMapboxMap);
- mAnnotations.add(polyline);
- return polyline;
+ long[] addMarkers(@NonNull List<Marker> markerList) {
+ return mNativeMapView.addMarkers(markerList);
}
- /**
- * 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.
- */
- @UiThread
- @NonNull
- List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList) {
- if (polylineOptionsList == null) {
- Log.w(TAG, "polylineOptionsList was null, so just returning null");
- return null;
- }
-
- int count = polylineOptionsList.size();
- List<Polyline> polylines = new ArrayList<>(count);
- for (PolylineOptions options : polylineOptionsList) {
- polylines.add(options.getPolyline());
- }
-
- long[] ids = mNativeMapView.addPolylines(polylines);
-
- Polyline p;
- for (int i = 0; i < count; i++) {
- p = polylines.get(i);
- p.setId(ids[i]);
- p.setMapboxMap(mMapboxMap);
- mAnnotations.add(p);
- }
-
- return new ArrayList<>(polylines);
+ long addPolyline(@NonNull Polyline polyline) {
+ return mNativeMapView.addPolyline(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.
- */
- @UiThread
- @NonNull
- Polygon addPolygon(@NonNull PolygonOptions polygonOptions) {
- if (polygonOptions == null) {
- Log.w(TAG, "polygonOptions was null, so just returning null");
- return null;
- }
-
- Polygon polygon = polygonOptions.getPolygon();
- long id = mNativeMapView.addPolygon(polygon);
- polygon.setId(id);
- polygon.setMapboxMap(mMapboxMap);
- mAnnotations.add(polygon);
- return polygon;
+ long[] addPolylines(@NonNull List<Polyline> polylines) {
+ return mNativeMapView.addPolylines(polylines);
}
-
- /**
- * 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.
- */
- @UiThread
- @NonNull
- List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList) {
- if (polygonOptionsList == null) {
- Log.w(TAG, "polygonOptionsList was null, so just returning null");
- return null;
- }
-
- int count = polygonOptionsList.size();
- List<Polygon> polygons = new ArrayList<>(count);
- for (PolygonOptions polygonOptions : polygonOptionsList) {
- polygons.add(polygonOptions.getPolygon());
- }
-
- long[] ids = mNativeMapView.addPolygons(polygons);
-
- Polygon p;
- for (int i = 0; i < count; i++) {
- p = polygons.get(i);
- p.setId(ids[i]);
- p.setMapboxMap(mMapboxMap);
- mAnnotations.add(p);
- }
-
- return new ArrayList<>(polygons);
+ long addPolygon(@NonNull Polygon polygon) {
+ return mNativeMapView.addPolygon(polygon);
}
-
- /**
- * <p>
- * Convenience method for removing a Marker from the map.
- * </p>
- * Calls removeAnnotation() internally
- *
- * @param marker Marker to remove
- */
- @UiThread
- void removeMarker(@NonNull Marker marker) {
- removeAnnotation(marker);
+ long[] addPolygons(@NonNull List<Polygon> polygons) {
+ return mNativeMapView.addPolygons(polygons);
}
- /**
- * Removes an annotation from the map.
- *
- * @param annotation The annotation object to remove.
- */
- @UiThread
- void removeAnnotation(@NonNull Annotation annotation) {
- if (annotation == null) {
- Log.w(TAG, "annotation was null, so just returning");
- return;
- }
-
- if (annotation instanceof Marker) {
- ((Marker) annotation).hideInfoWindow();
- }
- long id = annotation.getId();
+ void removeAnnotation(long id) {
mNativeMapView.removeAnnotation(id);
- mAnnotations.remove(annotation);
- }
-
- /**
- * Removes multiple annotations from the map.
- *
- * @param annotationList A list of annotation objects to remove.
- */
- @UiThread
- void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
- if (annotationList == null) {
- Log.w(TAG, "annotationList was null, so just returning");
- return;
- }
-
- int count = annotationList.size();
- long[] ids = new long[count];
- for (int i = 0; i < count; i++) {
- ids[i] = annotationList.get(i).getId();
- }
- mNativeMapView.removeAnnotations(ids);
}
- /**
- * Removes all annotations from the map.
- */
- @UiThread
- void removeAllAnnotations() {
- int count = mAnnotations.size();
- long[] ids = new long[mAnnotations.size()];
-
- for (int i = 0; i < count; i++) {
- Annotation annotation = mAnnotations.get(i);
- long id = annotation.getId();
- ids[i] = id;
- if (annotation instanceof Marker) {
- ((Marker) annotation).hideInfoWindow();
- }
- }
-
+ void removeAnnotations(@NonNull long[] ids) {
mNativeMapView.removeAnnotations(ids);
- mAnnotations.clear();
- }
-
- /**
- * 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.
- */
- @NonNull
- List<Annotation> getAllAnnotations() {
- return new ArrayList<>(mAnnotations);
}
private List<Marker> getMarkersInBounds(@NonNull LatLngBounds bbox) {
@@ -1269,9 +1135,10 @@ public class MapView extends FrameLayout {
}
List<Marker> annotations = new ArrayList<>(ids.length);
- int count = mAnnotations.size();
+ List<Annotation> annotationList = mMapboxMap.getAnnotations();
+ int count = annotationList.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = mAnnotations.get(i);
+ Annotation annotation = annotationList.get(i);
if (annotation instanceof Marker && idsList.contains(annotation.getId())) {
annotations.add((Marker) annotation);
}
@@ -1280,7 +1147,7 @@ public class MapView extends FrameLayout {
return new ArrayList<>(annotations);
}
- private int getTopOffsetPixelsForIcon(Icon icon) {
+ int getTopOffsetPixelsForIcon(Icon icon) {
// This method will dead lock if map paused. Causes a freeze if you add a marker in an
// activity's onCreate()
if (mNativeMapView.isPaused()) {
@@ -1292,6 +1159,35 @@ public class MapView extends FrameLayout {
}
/**
+ * Sets the distance from the edges of the map view’s frame to the edges of the map
+ * view’s logical viewport.
+ * <p/>
+ * 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 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.
+ */
+ @UiThread
+ void setContentPadding(int left, int top, int right, int bottom) {
+ if (left == mContentPaddingLeft && top == mContentPaddingTop && right == mContentPaddingRight && bottom == mContentPaddingBottom) {
+ return;
+ }
+
+ mContentPaddingLeft = left;
+ mContentPaddingTop = top;
+ mContentPaddingRight = right;
+ mContentPaddingBottom = bottom;
+
+ mNativeMapView.setContentPadding(top / mScreenDensity, left / mScreenDensity, bottom / mScreenDensity, right / mScreenDensity);
+ }
+
+ /**
* <p>
* Returns the distance spanned by one pixel at the specified latitude and current zoom level.
* </p>
@@ -1400,9 +1296,10 @@ public class MapView extends FrameLayout {
}
private void adjustTopOffsetPixels() {
- int count = mAnnotations.size();
+ List<Annotation> annotations = mMapboxMap.getAnnotations();
+ int count = annotations.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = mAnnotations.get(i);
+ Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
@@ -1419,9 +1316,10 @@ public class MapView extends FrameLayout {
}
private void reloadMarkers() {
- int count = mAnnotations.size();
+ List<Annotation> annotations = mMapboxMap.getAnnotations();
+ int count = annotations.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = mAnnotations.get(i);
+ Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
mNativeMapView.removeAnnotation(annotation.getId());
@@ -1572,6 +1470,26 @@ public class MapView extends FrameLayout {
// Touch events
//
+ /**
+ * Helper method for tracking gesture events
+ * @param gestureId Type of Gesture See {@see MapboxEvent#GESTURE_SINGLETAP MapboxEvent#GESTURE_DOUBLETAP MapboxEvent#GESTURE_TWO_FINGER_SINGLETAP MapboxEvent#GESTURE_QUICK_ZOOM MapboxEvent#GESTURE_PAN_START MapboxEvent#GESTURE_PINCH_START MapboxEvent#GESTURE_ROTATION_START MapboxEvent#GESTURE_PITCH_START}
+ * @param xCoordinate Original x screen coordinate at start of gesture
+ * @param yCoordinate Original y screen cooridnate at start of gesture
+ */
+ private void trackGestureEvent(@NonNull String gestureId, @NonNull float xCoordinate, float yCoordinate) {
+
+ LatLng tapLatLng = fromScreenLocation(new PointF(xCoordinate, yCoordinate));
+
+ Hashtable<String, Object> evt = new Hashtable<>();
+ evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK);
+ evt.put(MapboxEvent.KEY_GESTURE_ID, gestureId);
+ evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude());
+ evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude());
+ evt.put(MapboxEvent.KEY_ZOOM, mMapboxMap.getCameraPosition().zoom);
+
+ MapboxEventManager.getMapboxEventManager(getContext()).pushEvent(evt);
+ }
+
// Called when user touches the screen, all positions are absolute
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
@@ -1596,6 +1514,10 @@ public class MapView extends FrameLayout {
case MotionEvent.ACTION_POINTER_DOWN:
// Second pointer down
mTwoTap = event.getPointerCount() == 2;
+ if (mTwoTap) {
+ // Confirmed 2nd Finger Down
+ trackGestureEvent(MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY());
+ }
break;
case MotionEvent.ACTION_POINTER_UP:
@@ -1617,6 +1539,12 @@ public class MapView extends FrameLayout {
return true;
}
+ // Scroll / Pan Has Stopped
+ if (mScrollInProgress) {
+ trackGestureEvent(MapboxEvent.TYPE_MAP_DRAGEND, event.getX(), event.getY());
+ mScrollInProgress = false;
+ }
+
mTwoTap = false;
mNativeMapView.setGestureInProgress(false);
break;
@@ -1632,8 +1560,7 @@ public class MapView extends FrameLayout {
}
// This class handles one finger gestures
- private class GestureListener extends
- GestureDetector.SimpleOnGestureListener {
+ private class GestureListener extends GestureDetector.SimpleOnGestureListener {
// Must always return true otherwise all events are ignored
@Override
@@ -1665,16 +1592,20 @@ public class MapView extends FrameLayout {
}
// Single finger double tap
- if (mUserLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE) {
+ if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) {
// Zoom in on gesture
zoom(true, e.getX(), e.getY());
+ trackGestureEvent(MapboxEvent.GESTURE_QUICK_ZOOM, e.getX(), e.getY());
} else {
- // Zoom in on center map
- zoom(true, getWidth() / 2, getHeight() / 2);
+ // Zoom in on user location view
+ PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
+ zoom(true, centerPoint.x, centerPoint.y);
}
break;
}
+ trackGestureEvent(MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY());
+
return true;
}
@@ -1725,9 +1656,10 @@ public class MapView extends FrameLayout {
}
if (newSelectedMarkerId >= 0) {
- int count = mAnnotations.size();
+ List<Annotation> annotations = mMapboxMap.getAnnotations();
+ int count = annotations.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = mAnnotations.get(i);
+ Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
if (selectedMarkers.isEmpty() || !selectedMarkers.contains(annotation)) {
@@ -1749,6 +1681,8 @@ public class MapView extends FrameLayout {
}
}
+ trackGestureEvent(MapboxEvent.GESTURE_SINGLETAP, e.getX(), e.getY());
+
return true;
}
@@ -1771,7 +1705,9 @@ public class MapView extends FrameLayout {
}
// reset tracking modes if gesture occurs
- resetTrackingModes();
+ if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
+ resetTrackingModes();
+ }
// Fling the map
float ease = 0.25f;
@@ -1793,18 +1729,25 @@ public class MapView extends FrameLayout {
listener.onFling();
}
+ trackGestureEvent(MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY());
return true;
}
// Called for drags
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ Log.i(TAG, "onScroll() started");
+ if (!mScrollInProgress) {
+ mScrollInProgress = true;
+ }
if (!mMapboxMap.getUiSettings().isScrollGesturesEnabled()) {
return false;
}
- // reset tracking modes if gesture occurs
- resetTrackingModes();
+ if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
+ // reset tracking modes if gesture occurs
+ resetTrackingModes();
+ }
// Cancel any animation
mNativeMapView.cancelTransitions();
@@ -1817,6 +1760,7 @@ public class MapView extends FrameLayout {
listener.onScroll();
}
+ Log.i(TAG, "onScroll() done");
return true;
}
}
@@ -1834,10 +1778,13 @@ public class MapView extends FrameLayout {
return false;
}
- // reset tracking modes if gesture occurs
- resetTrackingModes();
+ if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
+ // reset tracking modes if gesture occurs
+ resetTrackingModes();
+ }
mBeginTime = detector.getEventTime();
+ trackGestureEvent(MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY());
return true;
}
@@ -1853,7 +1800,8 @@ public class MapView extends FrameLayout {
// Called for pinch zooms and quickzooms/quickscales
@Override
public boolean onScale(ScaleGestureDetector detector) {
- if (!mMapboxMap.getUiSettings().isZoomGesturesEnabled()) {
+ UiSettings uiSettings = mMapboxMap.getUiSettings();
+ if (!uiSettings.isZoomGesturesEnabled()) {
return false;
}
@@ -1881,13 +1829,21 @@ public class MapView extends FrameLayout {
// Gesture is a quickzoom if there aren't two fingers
mQuickZoom = !mTwoTap;
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+
// Scale the map
- if (mMapboxMap.getUiSettings().isScrollGesturesEnabled() && !mQuickZoom && mUserLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE) {
+ if (uiSettings.isScrollGesturesEnabled() && !mQuickZoom && trackingSettings.isLocationTrackingDisabled()) {
// around gesture
mNativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity);
} else {
- // around center map
- mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity);
+ if(trackingSettings.isLocationTrackingDisabled()) {
+ // around center map
+ mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity);
+ }else {
+ // around user location view
+ PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
+ mNativeMapView.scaleBy(detector.getScaleFactor(), centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity);
+ }
}
return true;
}
@@ -1907,10 +1863,13 @@ public class MapView extends FrameLayout {
return false;
}
- // reset tracking modes if gesture occurs
- resetTrackingModes();
+ if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
+ // reset tracking modes if gesture occurs
+ resetTrackingModes();
+ }
mBeginTime = detector.getEventTime();
+ trackGestureEvent(MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY());
return true;
}
@@ -1957,16 +1916,15 @@ public class MapView extends FrameLayout {
bearing += detector.getRotationDegreesDelta();
// Rotate the map
- if (mUserLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE) {
+ if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) {
// around gesture
mNativeMapView.setBearing(bearing,
detector.getFocusX() / mScreenDensity,
detector.getFocusY() / mScreenDensity);
} else {
- // around center map
- mNativeMapView.setBearing(bearing,
- (getWidth() / 2) / mScreenDensity,
- (getHeight() / 2) / mScreenDensity);
+ // around center userlocation
+ PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
+ mNativeMapView.setBearing(bearing, centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity);
}
return true;
}
@@ -1986,10 +1944,13 @@ public class MapView extends FrameLayout {
return false;
}
- // reset tracking modes if gesture occurs
- resetTrackingModes();
+ if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
+ // reset tracking modes if gesture occurs
+ resetTrackingModes();
+ }
mBeginTime = detector.getEventTime();
+ trackGestureEvent(MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY());
return true;
}
@@ -2056,8 +2017,6 @@ public class MapView extends FrameLayout {
if (!mMapboxMap.getUiSettings().isZoomGesturesEnabled()) {
return;
}
-
- // Zoom in or out
zoom(zoomIn);
}
}
@@ -2408,9 +2367,11 @@ public class MapView extends FrameLayout {
// Forward to any listeners
protected void onMapChanged(int mapChange) {
if (mOnMapChangedListener != null) {
- int count = mOnMapChangedListener.size();
- for (int i = 0; i < count; i++) {
- mOnMapChangedListener.get(i).onMapChanged(mapChange);
+ OnMapChangedListener listener;
+ final Iterator<OnMapChangedListener> iterator = mOnMapChangedListener.iterator();
+ while (iterator.hasNext()) {
+ listener = iterator.next();
+ listener.onMapChanged(mapChange);
}
}
}
@@ -2419,6 +2380,11 @@ public class MapView extends FrameLayout {
// User location
//
+ boolean isPermissionsAccepted() {
+ return (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) ||
+ ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
* <p>
* Enables or disables the my-location layer.
@@ -2433,9 +2399,6 @@ public class MapView extends FrameLayout {
* @throws SecurityException if no suitable permission is present
*/
@UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
void setMyLocationEnabled(boolean enabled) {
mUserLocationView.setEnabled(enabled);
}
@@ -2473,19 +2436,13 @@ public class MapView extends FrameLayout {
* See {@link MyLocationTracking} for different values.
*
* @param myLocationTrackingMode The location tracking mode to be used.
- * @throws SecurityException if no suitable permission is present
* @see MyLocationTracking
*/
@UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && !mMapboxMap.isMyLocationEnabled()) {
- //noinspection ResourceType
mMapboxMap.setMyLocationEnabled(true);
}
-
mUserLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
MapboxMap.OnMyLocationTrackingModeChangeListener listener = mMapboxMap.getOnMyLocationTrackingModeChangeListener();
if (listener != null) {
@@ -2494,19 +2451,6 @@ public class MapView extends FrameLayout {
}
/**
- * Returns the current user location tracking mode.
- *
- * @return The current user location tracking mode.
- * One of the values from {@link MyLocationTracking.Mode}.
- * @see MyLocationTracking.Mode
- */
- @UiThread
- @MyLocationTracking.Mode
- int getMyLocationTrackingMode() {
- return mUserLocationView.getMyLocationTrackingMode();
- }
-
- /**
* <p>
* Set the current my bearing tracking mode.
* </p>
@@ -2518,16 +2462,11 @@ public class MapView extends FrameLayout {
* See {@link MyBearingTracking} for different values.
*
* @param myBearingTrackingMode The bearing tracking mode to be used.
- * @throws SecurityException if no suitable permission is present
* @see MyBearingTracking
*/
@UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
if (myBearingTrackingMode != MyBearingTracking.NONE && !mMapboxMap.isMyLocationEnabled()) {
- //noinspection ResourceType
mMapboxMap.setMyLocationEnabled(true);
}
mUserLocationView.setMyBearingTrackingMode(myBearingTrackingMode);
@@ -2537,26 +2476,11 @@ public class MapView extends FrameLayout {
}
}
- /**
- * Returns the current user bearing tracking mode.
- * See {@link MyBearingTracking} for possible return values.
- *
- * @return the current user bearing tracking mode.
- * @see MyBearingTracking
- */
- @UiThread
- @MyLocationTracking.Mode
- int getMyBearingTrackingMode() {
- //noinspection ResourceType
- return mUserLocationView.getMyBearingTrackingMode();
- }
-
private void resetTrackingModes() {
try {
- //noinspection ResourceType
- setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
- //noinspection ResourceType
- setMyBearingTrackingMode(MyBearingTracking.NONE);
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
} catch (SecurityException ignore) {
// User did not accept location permissions
}
@@ -2806,6 +2730,10 @@ public class MapView extends FrameLayout {
private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) {
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
+ left += mContentPaddingLeft;
+ top += mContentPaddingTop;
+ right += mContentPaddingRight;
+ bottom += mContentPaddingBottom;
layoutParams.setMargins(left, top, right, bottom);
view.setLayoutParams(layoutParams);
}
@@ -2813,9 +2741,11 @@ public class MapView extends FrameLayout {
private static class AttributionOnClickListener implements View.OnClickListener, DialogInterface.OnClickListener {
private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2;
+ private static final int ATTRIBUTION_INDEX_TELEMETRY_SETTINGS = 3;
private MapView mMapView;
public AttributionOnClickListener(MapView mapView) {
+ super();
mMapView = mapView;
}
@@ -2825,7 +2755,7 @@ public class MapView extends FrameLayout {
Context context = v.getContext();
String[] items = context.getResources().getStringArray(R.array.attribution_names);
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AttributionAlertDialogStyle);
- builder.setTitle(R.string.attributionsDialogTitle);
+ builder.setTitle(R.string.mapbox_attributionsDialogTitle);
builder.setAdapter(new ArrayAdapter<>(context, R.layout.attribution_list_item, items), this);
builder.show();
}
@@ -2833,7 +2763,49 @@ public class MapView extends FrameLayout {
// Called when someone selects an attribution, 'Improve this map' adds location data to the url
@Override
public void onClick(DialogInterface dialog, int which) {
- Context context = ((Dialog) dialog).getContext();
+ final Context context = ((Dialog) dialog).getContext();
+ if (which == ATTRIBUTION_INDEX_TELEMETRY_SETTINGS) {
+
+ int array = R.array.attribution_telemetry_options;
+ if (MapboxEventManager.getMapboxEventManager(context).isTelemetryEnabled()) {
+ array = R.array.attribution_telemetry_options_already_participating;
+ }
+ String[] items = context.getResources().getStringArray(array);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AttributionAlertDialogStyle);
+ builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
+ LayoutInflater factory = LayoutInflater.from(context);
+ View content = factory.inflate(R.layout.attribution_telemetry_view, null);
+
+ ListView lv = (ListView) content.findViewById(R.id.telemetryOptionsList);
+ lv.setAdapter(new ArrayAdapter<String>(context, R.layout.attribution_list_item, items));
+ lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+
+ builder.setView(content);
+ final AlertDialog telemDialog = builder.show();
+ lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ switch (position) {
+ case 0:
+ String url = context.getResources().getStringArray(R.array.attribution_links)[3];
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ context.startActivity(intent);
+ telemDialog.cancel();
+ return;
+ case 1:
+ MapboxEventManager.getMapboxEventManager(context).setTelemetryEnabled(false);
+ telemDialog.cancel();
+ return;
+ case 2:
+ MapboxEventManager.getMapboxEventManager(context).setTelemetryEnabled(true);
+ telemDialog.cancel();
+ return;
+ }
+ }
+ });
+ return;
+ }
String url = context.getResources().getStringArray(R.array.attribution_links)[which];
if (which == ATTRIBUTION_INDEX_IMPROVE_THIS_MAP) {
LatLng latLng = mMapView.getMapboxMap().getCameraPosition().target;
@@ -3044,4 +3016,5 @@ public class MapView extends FrameLayout {
void onMapChanged(@MapChange int change);
}
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index 757a9bc3d9..40b75d3ce1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -1,20 +1,21 @@
package com.mapbox.mapboxsdk.maps;
-import android.Manifest;
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
-import android.support.annotation.FloatRange;
+import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.RequiresPermission;
import android.support.annotation.UiThread;
+import android.support.v4.util.LongSparseArray;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
@@ -23,6 +24,8 @@ 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.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
@@ -39,10 +42,12 @@ public class MapboxMap {
private MapView mMapView;
private UiSettings mUiSettings;
+ private TrackingSettings mTrackingSettings;
private Projection mProjection;
private CameraPosition mCameraPosition;
private boolean mInvalidCameraPosition;
private String mStyleUrl;
+ private LongSparseArray<Annotation> mAnnotations;
private List<Marker> mSelectedMarkers;
private List<InfoWindow> mInfoWindows;
private MapboxMap.InfoWindowAdapter mInfoWindowAdapter;
@@ -54,17 +59,22 @@ public class MapboxMap {
private MapboxMap.OnMapLongClickListener mOnMapLongClickListener;
private MapboxMap.OnMarkerClickListener mOnMarkerClickListener;
private MapboxMap.OnInfoWindowClickListener mOnInfoWindowClickListener;
+ private MapboxMap.OnInfoWindowLongClickListener mOnInfoWindowLongClickListener;
+ private MapboxMap.OnInfoWindowCloseListener mOnInfoWindowCloseListener;
private MapboxMap.OnFlingListener mOnFlingListener;
private MapboxMap.OnScrollListener mOnScrollListener;
private MapboxMap.OnMyLocationTrackingModeChangeListener mOnMyLocationTrackingModeChangeListener;
private MapboxMap.OnMyBearingTrackingModeChangeListener mOnMyBearingTrackingModeChangeListener;
private MapboxMap.OnFpsChangedListener mOnFpsChangedListener;
+ private MapboxMap.OnCameraChangeListener mOnCameraChangeListener;
MapboxMap(@NonNull MapView mapView) {
mMapView = mapView;
mMapView.addOnMapChangedListener(new MapChangeCameraPositionListener());
mUiSettings = new UiSettings(mapView);
+ mTrackingSettings = new TrackingSettings(mMapView, mUiSettings);
mProjection = new Projection(mapView);
+ mAnnotations = new LongSparseArray<>();
mSelectedMarkers = new ArrayList<>();
mInfoWindows = new ArrayList<>();
}
@@ -83,6 +93,19 @@ public class MapboxMap {
}
//
+ // TrackingSettings
+ //
+
+ /**
+ * Gets the tracking interface settings for the map.
+ *
+ * @return
+ */
+ public TrackingSettings getTrackingSettings() {
+ return mTrackingSettings;
+ }
+
+ //
// Projection
//
@@ -105,14 +128,7 @@ public class MapboxMap {
*/
public final CameraPosition getCameraPosition() {
if (mInvalidCameraPosition) {
- // Camera position has changed, need to regenerate position
- mCameraPosition = new CameraPosition.Builder(true)
- .bearing((float) mMapView.getBearing())
- .target(mMapView.getLatLng())
- .tilt((float) mMapView.getTilt())
- .zoom((float) mMapView.getZoom())
- .build();
- mInvalidCameraPosition = false;
+ invalidateCameraPosition();
}
return mCameraPosition;
}
@@ -137,8 +153,26 @@ public class MapboxMap {
*/
@UiThread
public final void moveCamera(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.
+ */
+ @UiThread
+ public final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
mCameraPosition = update.getCameraPosition(this);
mMapView.jumpTo(mCameraPosition.bearing, mCameraPosition.target, mCameraPosition.tilt, mCameraPosition.zoom);
+ if (mOnCameraChangeListener != null) {
+ mOnCameraChangeListener.onCameraChange(mCameraPosition);
+ }
+ if (callback != null) {
+ callback.onFinish();
+ }
}
/**
@@ -175,7 +209,25 @@ public class MapboxMap {
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
mCameraPosition = update.getCameraPosition(this);
- mMapView.easeTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, callback);
+ mMapView.easeTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, new CancelableCallback() {
+ @Override
+ public void onCancel() {
+ if (callback != null) {
+ callback.onCancel();
+ }
+ }
+
+ @Override
+ public void onFinish() {
+ if (mOnCameraChangeListener != null) {
+ mOnCameraChangeListener.onCameraChange(mCameraPosition);
+ }
+
+ if (callback != null) {
+ callback.onFinish();
+ }
+ }
+ });
}
/**
@@ -227,7 +279,25 @@ public class MapboxMap {
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
mCameraPosition = update.getCameraPosition(this);
- mMapView.flyTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, callback);
+ mMapView.flyTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, new CancelableCallback() {
+ @Override
+ public void onCancel() {
+ if (callback != null) {
+ callback.onCancel();
+ }
+ }
+
+ @Override
+ public void onFinish() {
+ if (mOnCameraChangeListener != null) {
+ mOnCameraChangeListener.onCameraChange(mCameraPosition);
+ }
+
+ if (callback != null) {
+ callback.onFinish();
+ }
+ }
+ });
}
// internal time layer conversion
@@ -235,75 +305,34 @@ public class MapboxMap {
return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0;
}
- //
- // ZOOM
- //
-
- /**
- * <p>
- * Sets the minimum zoom level the map can be displayed at.
- * </p>
- *
- * @param minZoom The new minimum zoom level.
- */
- @UiThread
- public void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
- if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) {
- Log.e(MapboxConstants.TAG, "Not setting minZoom, value is in unsupported range: " + minZoom);
- return;
+ private void invalidateCameraPosition() {
+ mInvalidCameraPosition = false;
+ mCameraPosition = new CameraPosition.Builder(true)
+ .bearing((float) mMapView.getBearing())
+ .target(mMapView.getLatLng())
+ .tilt((float) mMapView.getTilt())
+ .zoom((float) mMapView.getZoom())
+ .build();
+ if (mOnCameraChangeListener != null) {
+ mOnCameraChangeListener.onCameraChange(mCameraPosition);
}
- mMapView.setMinZoom(minZoom);
}
- /**
- * <p>
- * Gets the maximum zoom level the map can be displayed at.
- * </p>
- *
- * @return The minimum zoom level.
- */
- @UiThread
- public double getMinZoom() {
- return mMapView.getMinZoom();
- }
-
- /**
- * <p>
- * Sets the maximum zoom level the map can be displayed at.
- * </p>
- *
- * @param maxZoom The new maximum zoom level.
- */
- @UiThread
- public void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
- if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) {
- Log.e(MapboxConstants.TAG, "Not setting maxZoom, value is in unsupported range: " + maxZoom);
- return;
- }
- mMapView.setMaxZoom(maxZoom);
- }
+ //
+ // Reset North
+ //
/**
- * <p>
- * Gets the maximum zoom level the map can be displayed at.
- * </p>
*
- * @return The maximum zoom level.
*/
- @UiThread
- public double getMaxZoom() {
- return mMapView.getMaxZoom();
+ public void resetNorth() {
+ mMapView.resetNorth();
}
//
// Manual zoom controls
//
- // used by UiSettings
- void setZoomControlsEnabled(boolean enabled) {
- mMapView.setZoomControlsEnabled(enabled);
- }
-
//
// Debug
//
@@ -468,7 +497,17 @@ public class MapboxMap {
@UiThread
@NonNull
public Marker addMarker(@NonNull MarkerOptions markerOptions) {
- return mMapView.addMarker(markerOptions);
+ return addMarker((BaseMarkerOptions) markerOptions);
+ }
+
+ @UiThread
+ @NonNull
+ public Marker addMarker(@NonNull BaseMarkerOptions markerOptions) {
+ Marker marker = prepareMarker(markerOptions);
+ long id = mMapView.addMarker(marker);
+ marker.setId(id);
+ mAnnotations.put(id, marker);
+ return marker;
}
/**
@@ -484,7 +523,50 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Marker> addMarkers(@NonNull List<MarkerOptions> markerOptionsList) {
- return mMapView.addMarkers(markerOptionsList);
+ int count = markerOptionsList.size();
+ List<Marker> markers = new ArrayList<>(count);
+ MarkerOptions markerOptions;
+ Marker marker;
+ for (int i = 0; i < count; i++) {
+ markerOptions = markerOptionsList.get(i);
+ marker = prepareMarker(markerOptions);
+ markers.add(marker);
+ }
+
+ long[] ids = mMapView.addMarkers(markers);
+ long id = 0;
+ Marker m;
+
+ for (int i = 0; i < markers.size(); i++) {
+ m = markers.get(i);
+ m.setMapboxMap(this);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ //unit test
+ id++;
+ }
+ m.setId(id);
+ mAnnotations.put(id, m);
+ }
+ return markers;
+ }
+
+ /**
+ * <p>
+ * Updates a marker on this map. Does nothing if the marker is already added.
+ * </p>
+ *
+ * @param updatedMarker An updated marker object.
+ */
+ @UiThread
+ public void updateMarker(@NonNull Marker updatedMarker) {
+ mMapView.updateMarker(updatedMarker);
+
+ int index = mAnnotations.indexOfKey(updatedMarker.getId());
+ if (index > -1) {
+ mAnnotations.setValueAt(index, updatedMarker);
+ }
}
/**
@@ -496,7 +578,14 @@ public class MapboxMap {
@UiThread
@NonNull
public Polyline addPolyline(@NonNull PolylineOptions polylineOptions) {
- return mMapView.addPolyline(polylineOptions);
+ Polyline polyline = polylineOptions.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ long id = mMapView.addPolyline(polyline);
+ polyline.setMapboxMap(this);
+ polyline.setId(id);
+ mAnnotations.put(id, polyline);
+ }
+ return polyline;
}
/**
@@ -508,7 +597,33 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList) {
- return mMapView.addPolylines(polylineOptionsList);
+ int count = polylineOptionsList.size();
+ Polyline polyline;
+ List<Polyline> polylines = new ArrayList<>(count);
+ for (PolylineOptions options : polylineOptionsList) {
+ polyline = options.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ polylines.add(polyline);
+ }
+ }
+
+ long[] ids = mMapView.addPolylines(polylines);
+ long id = 0;
+ Polyline p;
+
+ for (int i = 0; i < polylines.size(); i++) {
+ p = polylines.get(i);
+ p.setMapboxMap(this);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ p.setId(id);
+ mAnnotations.put(id, p);
+ }
+ return polylines;
}
/**
@@ -520,7 +635,14 @@ public class MapboxMap {
@UiThread
@NonNull
public Polygon addPolygon(@NonNull PolygonOptions polygonOptions) {
- return mMapView.addPolygon(polygonOptions);
+ Polygon polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ long id = mMapView.addPolygon(polygon);
+ polygon.setId(id);
+ polygon.setMapboxMap(this);
+ mAnnotations.put(id, polygon);
+ }
+ return polygon;
}
/**
@@ -532,7 +654,32 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList) {
- return mMapView.addPolygons(polygonOptionsList);
+ int count = polygonOptionsList.size();
+
+ Polygon polygon;
+ List<Polygon> polygons = new ArrayList<>(count);
+ for (PolygonOptions polygonOptions : polygonOptionsList) {
+ polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ polygons.add(polygon);
+ }
+ }
+
+ long[] ids = mMapView.addPolygons(polygons);
+ long id = 0;
+ for (int i = 0; i < polygons.size(); i++) {
+ polygon = polygons.get(i);
+ polygon.setMapboxMap(this);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ polygon.setId(id);
+ mAnnotations.put(id, polygon);
+ }
+ return polygons;
}
/**
@@ -549,13 +696,55 @@ public class MapboxMap {
}
/**
+ * <p>
+ * Convenience method for removing a Polyline from the map.
+ * </p>
+ * Calls removeAnnotation() internally
+ *
+ * @param polyline Polyline to remove
+ */
+ @UiThread
+ public void removePolyline(@NonNull Polyline polyline) {
+ removeAnnotation(polyline);
+ }
+
+ /**
+ * <p>
+ * Convenience method for removing a Polygon from the map.
+ * </p>
+ * Calls removeAnnotation() internally
+ *
+ * @param polygon Polygon to remove
+ */
+ @UiThread
+ public void removePolygon(@NonNull Polygon polygon) {
+ removeAnnotation(polygon);
+ }
+
+ /**
* Removes an annotation from the map.
*
* @param annotation The annotation object to remove.
*/
@UiThread
public void removeAnnotation(@NonNull Annotation annotation) {
- mMapView.removeAnnotation(annotation);
+ if (annotation instanceof Marker) {
+ ((Marker) annotation).hideInfoWindow();
+ }
+ long id = annotation.getId();
+ mMapView.removeAnnotation(id);
+ mAnnotations.remove(id);
+ }
+
+ /**
+ * Removes an annotation from the map
+ *
+ * @param id The identifier associated to the annotation to be removed
+ */
+ @UiThread
+ public void removeAnnotation(long id) {
+ mMapView.removeAnnotation(id);
+ mAnnotations.remove(id);
}
/**
@@ -565,15 +754,49 @@ public class MapboxMap {
*/
@UiThread
public void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
- mMapView.removeAnnotations(annotationList);
+ int count = annotationList.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof Marker) {
+ ((Marker) annotation).hideInfoWindow();
+ }
+ ids[i] = annotationList.get(i).getId();
+ }
+ mMapView.removeAnnotations(ids);
+ for (long id : ids) {
+ mAnnotations.remove(id);
+ }
}
/**
* Removes all annotations from the map.
*/
@UiThread
- public void removeAllAnnotations() {
- mMapView.removeAllAnnotations();
+ public void removeAnnotations() {
+ Annotation annotation;
+ int count = mAnnotations.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ ids[i] = mAnnotations.keyAt(i);
+ annotation = mAnnotations.get(ids[i]);
+ if (annotation instanceof Marker) {
+ ((Marker) annotation).hideInfoWindow();
+ }
+ }
+ mMapView.removeAnnotations(ids);
+ mAnnotations.clear();
+ }
+
+ /**
+ * Return a annotation based on its id.
+ *
+ * @return An annotation with a matched id, null is returned if no match was found.
+ */
+ @UiThread
+ @Nullable
+ public Annotation getAnnotation(long id) {
+ return mAnnotations.get(id);
}
/**
@@ -583,8 +806,69 @@ public class MapboxMap {
* list will not update the map.
*/
@NonNull
- public List<Annotation> getAllAnnotations() {
- return mMapView.getAllAnnotations();
+ public List<Annotation> getAnnotations() {
+ List<Annotation> annotations = new ArrayList<>();
+ for (int i = 0; i < mAnnotations.size(); i++) {
+ annotations.add(mAnnotations.get(mAnnotations.keyAt(i)));
+ }
+ return annotations;
+ }
+
+ /**
+ * 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.
+ */
+ @NonNull
+ public List<Marker> getMarkers() {
+ List<Marker> markers = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < mAnnotations.size(); i++) {
+ annotation = mAnnotations.get(mAnnotations.keyAt(i));
+ if (annotation instanceof Marker) {
+ markers.add((Marker) annotation);
+ }
+ }
+ return markers;
+ }
+
+ /**
+ * 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.
+ */
+ @NonNull
+ public List<Polygon> getPolygons() {
+ List<Polygon> polygons = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < mAnnotations.size(); i++) {
+ annotation = mAnnotations.get(mAnnotations.keyAt(i));
+ if (annotation instanceof Polygon) {
+ polygons.add((Polygon) annotation);
+ }
+ }
+ return polygons;
+ }
+
+ /**
+ * 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.
+ */
+ @NonNull
+ public List<Polyline> getPolylines() {
+ List<Polyline> polylines = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < mAnnotations.size(); i++) {
+ annotation = mAnnotations.get(mAnnotations.keyAt(i));
+ if (annotation instanceof Polyline) {
+ polylines.add((Polyline) annotation);
+ }
+ }
+ return polylines;
}
/**
@@ -670,11 +954,17 @@ public class MapboxMap {
* @return The currently selected marker.
*/
@UiThread
- @Nullable
public List<Marker> getSelectedMarkers() {
return mSelectedMarkers;
}
+ private Marker prepareMarker(BaseMarkerOptions markerOptions) {
+ Marker marker = markerOptions.getMarker();
+ Icon icon = mMapView.loadIconForMarker(marker);
+ marker.setTopOffsetPixels(mMapView.getTopOffsetPixelsForIcon(icon));
+ return marker;
+ }
+
//
// InfoWindow
//
@@ -735,10 +1025,58 @@ public class MapboxMap {
}
//
+ // Padding
+ //
+
+ /**
+ * Sets the distance from the edges of the map view’s frame to the edges of the map
+ * view’s logical viewport.
+ * <p/>
+ * 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 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.
+ */
+ public void setPadding(int left, int top, int right, int bottom) {
+ mMapView.setContentPadding(left, top, right, bottom);
+ mUiSettings.invalidate();
+
+ moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(mCameraPosition).build()));
+ }
+
+ /**
+ *
+ * @return
+ */
+ public int[] getPadding() {
+ return new int[]{mMapView.getContentPaddingLeft(),
+ mMapView.getContentPaddingTop(),
+ mMapView.getContentPaddingRight(),
+ mMapView.getContentPaddingBottom()};
+ }
+
+ //
// Map events
//
/**
+ * Sets a callback that's invoked on every change in camera position.
+ *
+ * @param listener The callback that's invoked on every camera change position.
+ * To unset the callback, use null.
+ */
+ @UiThread
+ public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
+ mOnCameraChangeListener = 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.
@@ -845,10 +1183,44 @@ public class MapboxMap {
*
* @return Current active InfoWindow Click Listener
*/
+ @UiThread
public OnInfoWindowClickListener getOnInfoWindowClickListener() {
return mOnInfoWindowClickListener;
}
+ /**
+ * 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.
+ */
+ @UiThread
+ public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) {
+ mOnInfoWindowLongClickListener = listener;
+ }
+
+ /**
+ * Return the InfoWindow long click listener
+ *
+ * @return Current active InfoWindow long Click Listener
+ */
+ public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() {
+ return mOnInfoWindowLongClickListener;
+ }
+
+ public void setOnInfoWindowCloseListener(@Nullable OnInfoWindowCloseListener listener) {
+ mOnInfoWindowCloseListener = listener;
+ }
+
+ /**
+ * Return the InfoWindow close listener
+ *
+ * @return Current active InfoWindow Close Listener
+ */
+ @UiThread
+ public OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
+ return mOnInfoWindowCloseListener;
+ }
+
//
// User location
//
@@ -874,13 +1246,14 @@ public class MapboxMap {
* or @link android.Manifest.permission#ACCESS_FINE_LOCATION.
*
* @param enabled True to enable; false to disable.
- * @throws SecurityException if no suitable permission is present
*/
@UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
public void setMyLocationEnabled(boolean enabled) {
+ if (!mMapView.isPermissionsAccepted()) {
+ Log.e(MapboxConstants.TAG, "Could not activate user location tracking: " +
+ "user did not accept the permission or permissions were not requested.");
+ return;
+ }
mMyLocationEnabled = enabled;
mMapView.setMyLocationEnabled(enabled);
}
@@ -909,40 +1282,6 @@ public class MapboxMap {
}
/**
- * <p>
- * Set the current my location tracking mode.
- * </p>
- * <p>
- * Will enable my location if not active.
- * </p>
- * See {@link MyLocationTracking} for different values.
- *
- * @param myLocationTrackingMode The location tracking mode to be used.
- * @throws SecurityException if no suitable permission is present
- * @see MyLocationTracking
- */
- @UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
- public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
- mMapView.setMyLocationTrackingMode(myLocationTrackingMode);
- }
-
- /**
- * Returns the current user location tracking mode.
- *
- * @return The current user location tracking mode.
- * One of the values from {@link MyLocationTracking.Mode}.
- * @see MyLocationTracking.Mode
- */
- @UiThread
- @MyLocationTracking.Mode
- public int getMyLocationTrackingMode() {
- return mMapView.getMyLocationTrackingMode();
- }
-
- /**
* Sets a callback that's invoked when the location tracking mode changes.
*
* @param listener The callback that's invoked when the location tracking mode changes.
@@ -959,42 +1298,6 @@ public class MapboxMap {
}
/**
- * <p>
- * Set the current my bearing tracking mode.
- * </p>
- * Shows the direction the user is heading.
- * <p>
- * When location tracking is disabled the direction of {@link UserLocationView} is rotated
- * When location tracking is enabled the {@link MapView} is rotated based on bearing value.
- * </p>
- * See {@link MyBearingTracking} for different values.
- *
- * @param myBearingTrackingMode The bearing tracking mode to be used.
- * @throws SecurityException if no suitable permission is present
- * @see MyBearingTracking
- */
- @UiThread
- @RequiresPermission(anyOf = {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION})
- public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
- mMapView.setMyBearingTrackingMode(myBearingTrackingMode);
- }
-
- /**
- * Returns the current user bearing tracking mode.
- * See {@link MyBearingTracking} for possible return values.
- *
- * @return the current user bearing tracking mode.
- * @see MyBearingTracking
- */
- @UiThread
- @MyLocationTracking.Mode
- public int getMyBearingTrackingMode() {
- return mMapView.getMyBearingTrackingMode();
- }
-
- /**
* Sets a callback that's invoked when the bearing tracking mode changes.
*
* @param listener The callback that's invoked when the bearing tracking mode changes.
@@ -1033,9 +1336,17 @@ public class MapboxMap {
return mMapView;
}
-//
-// Interfaces
-//
+ //
+ // Invalidate
+ //
+
+ public void invalidate(){
+ mMapView.update();
+ }
+
+ //
+ // Interfaces
+ //
/**
* Interface definition for a callback to be invoked when the map is flinged.
@@ -1062,6 +1373,20 @@ public class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked for when the camera changes position.
+ */
+ public interface OnCameraChangeListener {
+ /**
+ * Called after the camera position has changed. During an animation,
+ * this listener may not be notified of intermediate camera positions.
+ * It is always called for the final position in the animation.
+ *
+ * @param position The CameraPosition at the end of the last camera change.
+ */
+ void onCameraChange(CameraPosition position);
+ }
+
+ /**
* Interface definition for a callback to be invoked on every frame rendered to the map view.
*
* @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener)
@@ -1130,7 +1455,37 @@ public class MapboxMap {
* @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 onMarkerClick(@NonNull Marker marker);
+ boolean onInfoWindowClick(@NonNull Marker marker);
+ }
+
+ /**
+ * Callback interface for 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(Marker marker);
+ }
+
+ /**
+ * Callback interface for close events on a marker's info window.
+ *
+ * @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(Marker marker);
}
/**
@@ -1169,7 +1524,7 @@ public class MapboxMap {
/**
* Interface definition for a callback to be invoked when the the My Location tracking mode changes.
*
- * @see MapboxMap#setMyLocationTrackingMode(int)
+ * @see MapView#setMyLocationTrackingMode(int)
*/
public interface OnMyLocationTrackingModeChangeListener {
@@ -1184,7 +1539,7 @@ public class MapboxMap {
/**
* Interface definition for a callback to be invoked when the the My Location tracking mode changes.
*
- * @see MapboxMap#setMyLocationTrackingMode(int)
+ * @see MapView#setMyLocationTrackingMode(int)
*/
public interface OnMyBearingTrackingModeChangeListener {
@@ -1212,13 +1567,20 @@ public class MapboxMap {
}
private class MapChangeCameraPositionListener implements MapView.OnMapChangedListener {
+
+ private static final long UPDATE_RATE_MS = 400;
+ private long mPreviousUpdateTimestamp = 0;
+
@Override
public void onMapChanged(@MapView.MapChange int change) {
- if (!mInvalidCameraPosition && (change == MapView.REGION_DID_CHANGE
- || change == MapView.REGION_DID_CHANGE_ANIMATED
- || change == MapView.REGION_WILL_CHANGE
- || change == MapView.REGION_WILL_CHANGE_ANIMATED)) {
+ if (change >= MapView.REGION_WILL_CHANGE && change <= MapView.REGION_DID_CHANGE_ANIMATED) {
mInvalidCameraPosition = true;
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime < mPreviousUpdateTimestamp) {
+ return;
+ }
+ invalidateCameraPosition();
+ mPreviousUpdateTimestamp = currentTime + UPDATE_RATE_MS;
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
deleted file mode 100644
index cb6407986e..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.mapbox.mapboxsdk.maps;
-
-import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-
-/**
- * Builder for composing {@link MapboxMap} objects. 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).
- */
-public class MapboxMapOptions implements Parcelable {
-
- private MapboxMap mMapboxMap;
- private UiSettings mUiSettings;
-
- public MapboxMapOptions(MapboxMap mapboxMap) {
- mMapboxMap = mapboxMap;
- mUiSettings = mapboxMap.getUiSettings();
- }
-
- public MapboxMapOptions(Parcel in) {
- throw new UnsupportedOperationException();
- }
-
- public MapboxMapOptions camera(CameraPosition camera) {
- mMapboxMap.setCameraPosition(camera);
- return this;
- }
-
- public CameraPosition getCamera() {
- return mMapboxMap.getCameraPosition();
- }
-
- public MapboxMapOptions compassEnabled(boolean enabled) {
- mUiSettings.setCompassEnabled(enabled);
- return this;
- }
-
- public boolean getCompassEnabled() {
- return mUiSettings.isCompassEnabled();
- }
-
- public MapboxMapOptions rotateEnabled(boolean rotateEnabled) {
- mUiSettings.setRotateGesturesEnabled(rotateEnabled);
- return this;
- }
-
- public MapboxMapOptions rotateGesturesEnabled(boolean enabled) {
- mUiSettings.setRotateGesturesEnabled(enabled);
- return this;
- }
-
- public boolean getRotateGesturesEnabled() {
- return mUiSettings.isRotateGesturesEnabled();
- }
-
- public MapboxMapOptions scrollGesturesEnabled(boolean enabled) {
- mUiSettings.setScrollGesturesEnabled(enabled);
- return this;
- }
-
- public boolean getScrollGesturesEnabled() {
- return mUiSettings.isScrollGesturesEnabled();
- }
-
- public MapboxMapOptions tiltGesturesEnabled(boolean enabled) {
- mUiSettings.setTiltGesturesEnabled(enabled);
- return this;
- }
-
- public boolean getTiltGesturesEnabled() {
- return mUiSettings.isTiltGesturesEnabled();
- }
-
- public MapboxMapOptions zoomControlsEnabled(boolean enabled) {
- mUiSettings.setZoomControlsEnabled(enabled);
- return this;
- }
-
- public boolean getZoomControlsEnabled() {
- return mUiSettings.isZoomControlsEnabled();
- }
-
- public boolean getZoomGesturesEnabled() {
- return mUiSettings.isZoomGesturesEnabled();
- }
-
- public MapboxMapOptions createFromAttributes(Context context, AttributeSet attrs) {
- throw new UnsupportedOperationException();
- }
-
- public static final Parcelable.Creator<MapboxMapOptions> CREATOR = new Parcelable.Creator<MapboxMapOptions>() {
- public MapboxMapOptions createFromParcel(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(Parcel out, int flags) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index 6c388d9d8a..b7f583e943 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -395,6 +395,10 @@ final class NativeMapView {
return nativeAddPolygons(mNativeMapViewPtr, polygon);
}
+ public void updateMarker(Marker marker) {
+ nativeUpdateMarker(mNativeMapViewPtr, marker);
+ }
+
public void removeAnnotation(long id) {
nativeRemoveAnnotation(mNativeMapViewPtr, id);
}
@@ -619,6 +623,8 @@ final class NativeMapView {
private native long nativeAddMarker(long nativeMapViewPtr, Marker marker);
+ private native void nativeUpdateMarker(long nativeMapViewPtr, Marker marker);
+
private native long[] nativeAddMarkers(long nativeMapViewPtr, List<Marker> markers);
private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index e53d430b69..0d5745d4c9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
+import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -21,6 +22,20 @@ public class Projection {
}
/**
+ * <p>
+ * Returns the distance spanned by one pixel at the specified latitude and current zoom level.
+ * </p>
+ * 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 = -180, to = 180) double latitude) {
+ return mMapView.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).
@@ -55,7 +70,7 @@ public class Projection {
.include(bottomRight)
.include(bottomLeft);
- return new VisibleRegion(topLeft,topRight,bottomLeft,bottomRight,builder.build());
+ return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, builder.build());
}
/**
@@ -69,4 +84,14 @@ public class Projection {
public PointF toScreenLocation(LatLng location) {
return mMapView.toScreenLocation(location);
}
+
+ /**
+ * 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 Math.log(mMapView.getScale() * minScale) / Math.log(2);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
index 147cd31b5a..8783712e10 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.maps;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
@@ -29,18 +30,10 @@ public class SupportMapFragment extends Fragment {
private MapView mMap;
- public static SupportMapFragment newInstance(){
+ public static SupportMapFragment newInstance() {
return new SupportMapFragment();
}
- public static SupportMapFragment newInstance(MapboxMapOptions mapboxMapOptions) {
- final SupportMapFragment mapFragment = new SupportMapFragment();
- Bundle bundle = new Bundle();
- bundle.putParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS, mapboxMapOptions);
- mapFragment.setArguments(bundle);
- return mapFragment;
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
@@ -94,7 +87,12 @@ public class SupportMapFragment extends Fragment {
}
@NonNull
- public void getMapAsync(@NonNull OnMapReadyCallback onMapReadyCallback){
- mMap.getMapAsync(onMapReadyCallback);
+ public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ mMap.getMapAsync(onMapReadyCallback);
+ }
+ });
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
new file mode 100644
index 0000000000..543ff19e56
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -0,0 +1,121 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.constants.MyBearingTracking;
+import com.mapbox.mapboxsdk.constants.MyLocationTracking;
+
+public class TrackingSettings {
+
+ private MapView mapView;
+ private UiSettings uiSettings;
+ private boolean dismissTrackingOnGesture = true;
+
+ @MyLocationTracking.Mode
+ private int mMyLocationTrackingMode;
+
+ @MyBearingTracking.Mode
+ private int mMyBearingTrackingMode;
+
+ TrackingSettings(@NonNull MapView mapView, UiSettings uiSettings) {
+ this.mapView = mapView;
+ this.uiSettings = uiSettings;
+ }
+
+ /**
+ * <p>
+ * Set the current my location tracking mode.
+ * </p>
+ * <p>
+ * Will enable my location if not active.
+ * </p>
+ * See {@link MyLocationTracking} for different values.
+ *
+ * @param myLocationTrackingMode The location tracking mode to be used.
+ * @throws SecurityException if no suitable permission is present
+ * @see MyLocationTracking
+ */
+ @UiThread
+ public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
+ mMyLocationTrackingMode = myLocationTrackingMode;
+ mapView.setMyLocationTrackingMode(myLocationTrackingMode);
+ validateGesturesForTrackingModes();
+ }
+
+ /**
+ * Returns the current user location tracking mode.
+ *
+ * @return The current user location tracking mode.
+ * One of the values from {@link MyLocationTracking.Mode}.
+ * @see MyLocationTracking.Mode
+ */
+ @UiThread
+ @MyLocationTracking.Mode
+ public int getMyLocationTrackingMode() {
+ return mMyLocationTrackingMode;
+ }
+
+ /**
+ * <p>
+ * Set the current my bearing tracking mode.
+ * </p>
+ * Shows the direction the user is heading.
+ * <p>
+ * When location tracking is disabled the direction of {@link UserLocationView} is rotated
+ * When location tracking is enabled the {@link MapView} is rotated based on bearing value.
+ * </p>
+ * See {@link MyBearingTracking} for different values.
+ *
+ * @param myBearingTrackingMode The bearing tracking mode to be used.
+ * @throws SecurityException if no suitable permission is present
+ * @see MyBearingTracking
+ */
+ @UiThread
+ public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
+ mMyBearingTrackingMode = myBearingTrackingMode;
+ mapView.setMyBearingTrackingMode(myBearingTrackingMode);
+ }
+
+ /**
+ * Returns the current user bearing tracking mode.
+ * See {@link MyBearingTracking} for possible return values.
+ *
+ * @return the current user bearing tracking mode.
+ * @see MyBearingTracking
+ */
+ @UiThread
+ @MyLocationTracking.Mode
+ public int getMyBearingTrackingMode() {
+ return mMyBearingTrackingMode;
+ }
+
+ public boolean isDismissTrackingOnGesture() {
+ return dismissTrackingOnGesture;
+ }
+
+ public void setDismissTrackingOnGesture(boolean dismissTrackingOnGesture) {
+ this.dismissTrackingOnGesture = dismissTrackingOnGesture;
+ validateGesturesForTrackingModes();
+ }
+
+ private void validateGesturesForTrackingModes() {
+ if (!dismissTrackingOnGesture) {
+ int myLocationTrackingMode = getMyLocationTrackingMode();
+ int myBearingTrackingMode = getMyBearingTrackingMode();
+
+ // Enable/disable gestures based on tracking mode
+ if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
+ uiSettings.setScrollGesturesEnabled(true);
+ uiSettings.setRotateGesturesEnabled(true);
+ } else {
+ uiSettings.setScrollGesturesEnabled(false);
+ uiSettings.setRotateGesturesEnabled((myBearingTrackingMode == MyBearingTracking.NONE));
+ }
+ }
+ }
+
+ public boolean isLocationTrackingDisabled(){
+ return mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index d6cb106054..1538f49d60 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -1,9 +1,14 @@
package com.mapbox.mapboxsdk.maps;
+import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
+import android.util.Log;
import android.view.Gravity;
import android.view.View;
+import android.widget.VideoView;
+
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
/**
* Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings().
@@ -12,17 +17,9 @@ public class UiSettings {
private MapView mapView;
- private boolean compassEnabled;
- private int compassGravity;
- private int[] compassMargins;
-
- private boolean logoEnabled;
- private int logoGravity;
- private int[] logoMargins;
-
- private boolean attributionEnabled;
- private int attributionGravity;
- private int[] attributionMargins;
+ private ViewSettings compassSettings;
+ private ViewSettings logoSettings;
+ private ViewSettings attributionSettings;
private boolean rotateGesturesEnabled;
private boolean tiltGesturesEnabled;
@@ -30,11 +27,78 @@ public class UiSettings {
private boolean zoomControlsEnabled;
private boolean scrollGesturesEnabled;
+ private double maxZoomLevel = -1;
+ private double minZoomLevel = -1;
+
UiSettings(@NonNull MapView mapView) {
this.mapView = mapView;
- this.compassMargins = new int[4];
- this.attributionMargins = new int[4];
- this.logoMargins = new int[4];
+ this.compassSettings = new ViewSettings();
+ this.logoSettings = new ViewSettings();
+ this.attributionSettings = new ViewSettings();
+ }
+
+ /**
+ * <p>
+ * Sets the minimum zoom level the map can be displayed at.
+ * </p>
+ *
+ * @param minZoom The new minimum zoom level.
+ */
+ @UiThread
+ public void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
+ if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) {
+ Log.e(MapboxConstants.TAG, "Not setting minZoom, value is in unsupported range: " + minZoom);
+ return;
+ }
+ minZoomLevel = minZoom;
+ mapView.setMinZoom(minZoom);
+ }
+
+ /**
+ * <p>
+ * Gets the maximum zoom level the map can be displayed at.
+ * </p>
+ *
+ * @return The minimum zoom level.
+ */
+ @UiThread
+ public double getMinZoom() {
+ if (minZoomLevel == -1) {
+ return minZoomLevel = mapView.getMinZoom();
+ }
+ return minZoomLevel;
+ }
+
+ /**
+ * <p>
+ * Sets the maximum zoom level the map can be displayed at.
+ * </p>
+ *
+ * @param maxZoom The new maximum zoom level.
+ */
+ @UiThread
+ public void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
+ if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) {
+ Log.e(MapboxConstants.TAG, "Not setting maxZoom, value is in unsupported range: " + maxZoom);
+ return;
+ }
+ maxZoomLevel = maxZoom;
+ mapView.setMaxZoom(maxZoom);
+ }
+
+ /**
+ * <p>
+ * Gets the maximum zoom level the map can be displayed at.
+ * </p>
+ *
+ * @return The maximum zoom level.
+ */
+ @UiThread
+ public double getMaxZoom() {
+ if (maxZoomLevel == -1) {
+ return maxZoomLevel = mapView.getMaxZoom();
+ }
+ return maxZoomLevel;
}
/**
@@ -49,8 +113,8 @@ public class UiSettings {
* @param compassEnabled True to enable the compass; false to disable the compass.
*/
public void setCompassEnabled(boolean compassEnabled) {
- this.compassEnabled = compassEnabled;
- this.mapView.setCompassEnabled(compassEnabled);
+ compassSettings.setEnabled(compassEnabled);
+ mapView.setCompassEnabled(compassEnabled);
}
/**
@@ -59,7 +123,7 @@ public class UiSettings {
* @return True if the compass is enabled; false if the compass is disabled.
*/
public boolean isCompassEnabled() {
- return compassEnabled;
+ return compassSettings.isEnabled();
}
/**
@@ -74,8 +138,8 @@ public class UiSettings {
*/
@UiThread
public void setCompassGravity(int gravity) {
- this.compassGravity = gravity;
- this.mapView.setCompassGravity(gravity);
+ compassSettings.setGravity(gravity);
+ mapView.setCompassGravity(gravity);
}
/**
@@ -84,7 +148,7 @@ public class UiSettings {
* @return The gravity
*/
public int getCompassGravity() {
- return compassGravity;
+ return compassSettings.getGravity();
}
/**
@@ -98,8 +162,8 @@ public class UiSettings {
*/
@UiThread
public void setCompassMargins(int left, int top, int right, int bottom) {
- this.compassMargins = new int[]{left, top, right, bottom};
- this.mapView.setCompassMargins(left, top, right, bottom);
+ compassSettings.setMargins(new int[]{left, top, right, bottom});
+ mapView.setCompassMargins(left, top, right, bottom);
}
/**
@@ -108,7 +172,7 @@ public class UiSettings {
* @return The left margin in pixels
*/
public int getCompassMarginLeft() {
- return compassMargins[0];
+ return compassSettings.getMargins()[0];
}
/**
@@ -117,7 +181,7 @@ public class UiSettings {
* @return The top margin in pixels
*/
public int getCompassMarginTop() {
- return compassMargins[1];
+ return compassSettings.getMargins()[1];
}
/**
@@ -126,7 +190,7 @@ public class UiSettings {
* @return The right margin in pixels
*/
public int getCompassMarginRight() {
- return compassMargins[2];
+ return compassSettings.getMargins()[2];
}
/**
@@ -135,7 +199,7 @@ public class UiSettings {
* @return The bottom margin in pixels
*/
public int getCompassMarginBottom() {
- return compassMargins[3];
+ return compassSettings.getMargins()[3];
}
/**
@@ -147,8 +211,8 @@ public class UiSettings {
* @param enabled True to enable the logo; false to disable the logo.
*/
public void setLogoEnabled(boolean enabled) {
- this.logoEnabled = enabled;
- this.mapView.setLogoVisibility(enabled );
+ logoSettings.setEnabled(enabled);
+ mapView.setLogoVisibility(enabled);
}
/**
@@ -157,7 +221,7 @@ public class UiSettings {
* @return True if the logo is enabled; false if the logo is disabled.
*/
public boolean isLogoEnabled() {
- return logoEnabled;
+ return logoSettings.isEnabled();
}
/**
@@ -171,8 +235,8 @@ public class UiSettings {
* @see Gravity
*/
public void setLogoGravity(int gravity) {
- this.logoGravity = gravity;
- this.mapView.setLogoGravity(gravity);
+ logoSettings.setGravity(gravity);
+ mapView.setLogoGravity(gravity);
}
/**
@@ -181,7 +245,7 @@ public class UiSettings {
* @return The gravity
*/
public int getLogoGravity() {
- return logoGravity;
+ return logoSettings.getGravity();
}
/**
@@ -194,8 +258,8 @@ public class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setLogoMargins(int left, int top, int right, int bottom) {
- this.logoMargins = new int[]{left, top, right, bottom};
- this.mapView.setLogoMargins(left, top, right, bottom);
+ logoSettings.setMargins(new int[]{left, top, right, bottom});
+ mapView.setLogoMargins(left, top, right, bottom);
}
/**
@@ -203,8 +267,8 @@ public class UiSettings {
*
* @return The left margin in pixels
*/
- public int getLogoMarginLeft(){
- return logoMargins[0];
+ public int getLogoMarginLeft() {
+ return logoSettings.getMargins()[0];
}
/**
@@ -212,8 +276,8 @@ public class UiSettings {
*
* @return The top margin in pixels
*/
- public int getLogoMarginTop(){
- return logoMargins[1];
+ public int getLogoMarginTop() {
+ return logoSettings.getMargins()[1];
}
/**
@@ -221,8 +285,8 @@ public class UiSettings {
*
* @return The right margin in pixels
*/
- public int getLogoMarginRight(){
- return logoMargins[2];
+ public int getLogoMarginRight() {
+ return logoSettings.getMargins()[2];
}
/**
@@ -230,8 +294,8 @@ public class UiSettings {
*
* @return The bottom margin in pixels
*/
- public int getLogoMarginBottom(){
- return logoMargins[3];
+ public int getLogoMarginBottom() {
+ return logoSettings.getMargins()[3];
}
/**
@@ -243,8 +307,8 @@ public class UiSettings {
* @param enabled True to enable the logo; false to disable the logo.
*/
public void setAttributionEnabled(boolean enabled) {
- this.attributionEnabled = enabled;
- this.mapView.setAttributionVisibility(enabled ? View.VISIBLE : View.GONE);
+ attributionSettings.setEnabled(enabled);
+ mapView.setAttributionVisibility(enabled ? View.VISIBLE : View.GONE);
}
/**
@@ -253,7 +317,7 @@ public class UiSettings {
* @return True if the logo is enabled; false if the logo is disabled.
*/
public boolean isAttributionEnabled() {
- return attributionEnabled;
+ return attributionSettings.isEnabled();
}
/**
@@ -267,8 +331,8 @@ public class UiSettings {
* @see Gravity
*/
public void setAttributionGravity(int gravity) {
- this.attributionGravity = gravity;
- this.mapView.setAttributionGravity(gravity);
+ attributionSettings.setGravity(gravity);
+ mapView.setAttributionGravity(gravity);
}
/**
@@ -277,7 +341,7 @@ public class UiSettings {
* @return The gravity
*/
public int getAttributionGravity() {
- return attributionGravity;
+ return attributionSettings.getGravity();
}
/**
@@ -290,8 +354,8 @@ public class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setAttributionMargins(int left, int top, int right, int bottom) {
- this.attributionMargins = new int[]{left, top, right, bottom};
- this.mapView.setAttributionMargins(left, top, right, bottom);
+ attributionSettings.setMargins(new int[]{left, top, right, bottom});
+ mapView.setAttributionMargins(left, top, right, bottom);
}
/**
@@ -299,8 +363,8 @@ public class UiSettings {
*
* @return The left margin in pixels
*/
- public int getAttributionMarginLeft(){
- return attributionMargins[0];
+ public int getAttributionMarginLeft() {
+ return attributionSettings.getMargins()[0];
}
/**
@@ -308,8 +372,8 @@ public class UiSettings {
*
* @return The top margin in pixels
*/
- public int getAttributionMarginTop(){
- return attributionMargins[1];
+ public int getAttributionMarginTop() {
+ return attributionSettings.getMargins()[1];
}
/**
@@ -317,8 +381,8 @@ public class UiSettings {
*
* @return The right margin in pixels
*/
- public int getAttributionMarginRight(){
- return attributionMargins[2];
+ public int getAttributionMarginRight() {
+ return attributionSettings.getMargins()[2];
}
/**
@@ -326,8 +390,8 @@ public class UiSettings {
*
* @return The bottom margin in pixels
*/
- public int getAttributionMarginBottom(){
- return attributionMargins[3];
+ public int getAttributionMarginBottom() {
+ return attributionSettings.getMargins()[3];
}
/**
@@ -477,4 +541,31 @@ public class UiSettings {
setTiltGesturesEnabled(enabled);
setZoomGesturesEnabled(enabled);
}
+
+ /**
+ * Returns the measured height of the MapView
+ *
+ * @return height in pixels
+ */
+ public float getHeight() {
+ return mapView.getMeasuredHeight();
+ }
+
+ /**
+ * Returns the measured width of the MapView
+ *
+ * @return widht in pixels
+ */
+ public float getWidth() {
+ return mapView.getMeasuredWidth();
+ }
+
+ /**
+ * Invalidates the ViewSettings instances shown on top of the MapView
+ */
+ public void invalidate() {
+ mapView.setLogoMargins(getLogoMarginLeft(), getLogoMarginTop(), getLogoMarginRight(), getLogoMarginBottom());
+ mapView.setCompassMargins(getCompassMarginLeft(), getCompassMarginTop(), getCompassMarginRight(), getCompassMarginBottom());
+ mapView.setAttributionMargins(getAttributionMarginLeft(), getAttributionMarginTop(), getAttributionMarginRight(), getAttributionMarginBottom());
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java
new file mode 100644
index 0000000000..a192a1b576
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java
@@ -0,0 +1,36 @@
+package com.mapbox.mapboxsdk.maps;
+
+public class ViewSettings {
+
+ private boolean enabled;
+ private int gravity;
+ private int[]margins;
+
+ public ViewSettings() {
+ margins = new int[4];
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public int getGravity() {
+ return gravity;
+ }
+
+ public void setGravity(int gravity) {
+ this.gravity = gravity;
+ }
+
+ public int[] getMargins() {
+ return margins;
+ }
+
+ public void setMargins(int[] margins) {
+ this.margins = margins;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
index 0d84289332..28afb70de3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.maps.widgets;
import android.content.Context;
import android.support.v4.content.ContextCompat;
@@ -11,6 +11,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
import java.lang.ref.WeakReference;
import java.util.Timer;
@@ -21,7 +23,7 @@ import java.util.TimerTask;
* when it isn't true north (0.0). Tapping the compass resets the bearing to true
* north and hides the compass.
*/
-public class CompassView extends ImageView {
+public final class CompassView extends ImageView {
private Timer mNorthTimer;
private double mDirection = 0.0f;
@@ -46,7 +48,7 @@ public class CompassView extends ImageView {
// View configuration
setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.compass));
- setContentDescription(getResources().getString(R.string.compassContentDescription));
+ setContentDescription(getResources().getString(R.string.mapbox_compassContentDescription));
setEnabled(false);
// Layout params
@@ -139,17 +141,17 @@ public class CompassView extends ImageView {
public static class CompassClickListener implements View.OnClickListener {
- private WeakReference<MapView> mMapView;
+ private WeakReference<MapboxMap> mMapboxMap;
- public CompassClickListener(final MapView mapView) {
- mMapView = new WeakReference<>(mapView);
+ public CompassClickListener(final MapboxMap mapboxMap) {
+ mMapboxMap = new WeakReference<>(mapboxMap);
}
@Override
public void onClick(View v) {
- final MapView mapView = mMapView.get();
- if (mapView != null) {
- mapView.resetNorth();
+ final MapboxMap mapboxMap = mMapboxMap.get();
+ if (mapboxMap != null) {
+ mapboxMap.resetNorth();
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UserLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java
index 9f8261a0a7..98d66b9307 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UserLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.maps.widgets;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -27,11 +27,14 @@ import android.view.ViewGroup;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationService;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Projection;
import java.lang.ref.WeakReference;
@@ -42,9 +45,8 @@ import java.lang.ref.WeakReference;
public final class UserLocationView extends View {
- private MapView mMapView;
-
- private float mDensity;
+ private MapboxMap mMapboxMap;
+ private Projection mProjection;
private boolean mShowMarker;
private boolean mShowDirection;
@@ -84,7 +86,6 @@ public final class UserLocationView extends View {
private LatLng mCurrentMapViewCoordinate;
private double mCurrentBearing;
-
private boolean mPaused = false;
private Location mUserLocation;
private UserLocationListener mUserLocationListener;
@@ -99,7 +100,6 @@ public final class UserLocationView extends View {
// Compass data
private MyBearingListener mBearingChangeListener;
- private static final long BEARING_DURATION = 100;
public UserLocationView(Context context) {
super(context);
@@ -132,9 +132,9 @@ public final class UserLocationView extends View {
// Setup the custom paint
Resources resources = context.getResources();
- int accuracyColor = resources.getColor(R.color.my_location_ring);
+ int accuracyColor = ContextCompat.getColor(context,R.color.my_location_ring);
- mDensity = resources.getDisplayMetrics().density;
+ float density = resources.getDisplayMetrics().density;
mMarkerCoordinate = new LatLng(0.0, 0.0);
mMarkerScreenPoint = new PointF();
mMarkerScreenMatrix = new Matrix();
@@ -148,7 +148,7 @@ public final class UserLocationView extends View {
mAccuracyPaintStroke = new Paint();
mAccuracyPaintStroke.setAntiAlias(true);
mAccuracyPaintStroke.setStyle(Paint.Style.STROKE);
- mAccuracyPaintStroke.setStrokeWidth(0.5f * mDensity);
+ mAccuracyPaintStroke.setStrokeWidth(0.5f * density);
mAccuracyPaintStroke.setColor(accuracyColor);
mAccuracyPaintStroke.setAlpha((int) (255 * 0.5f));
@@ -195,8 +195,9 @@ public final class UserLocationView extends View {
mUserLocationStaleDrawable.setBounds(mUserLocationStaleDrawableBounds);
}
- public void setMapView(MapView mapView) {
- mMapView = mapView;
+ public void setMapboxMap(MapboxMap mapboxMap) {
+ mMapboxMap = mapboxMap;
+ mProjection = mapboxMap.getProjection();
}
public void onStart() {
@@ -247,21 +248,15 @@ public final class UserLocationView extends View {
if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && mUserLocation != null) {
// center map directly if we have a location fix
mMarkerCoordinate = new LatLng(mUserLocation.getLatitude(), mUserLocation.getLongitude());
- mMapView.getMapboxMap().moveCamera(CameraUpdateFactory.newLatLng(new LatLng(mUserLocation)));
+ mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(mUserLocation)));
// center view directly
mMarkerScreenMatrix.reset();
- mMarkerScreenMatrix.setTranslate(
- getMeasuredWidth() / 2,
- getMeasuredHeight() / 2);
+ mMarkerScreenPoint = getMarkerScreenPoint();
+ mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y);
}
}
- @MyLocationTracking.Mode
- public int getMyLocationTrackingMode() {
- return mMyLocationTrackingMode;
- }
-
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
@@ -278,7 +273,7 @@ public final class UserLocationView extends View {
// compute new marker position
// TODO add JNI method that takes existing pointf
if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenPoint = mMapView.toScreenLocation(mMarkerCoordinate);
+ mMarkerScreenPoint = getMarkerScreenPoint();
mMarkerScreenMatrix.reset();
mMarkerScreenMatrix.setTranslate(
mMarkerScreenPoint.x,
@@ -289,11 +284,11 @@ public final class UserLocationView extends View {
if (mShowDirection) {
bearing = mMyBearingTrackingMode == MyBearingTracking.COMPASS ? mBearingChangeListener.getCompassBearing() : mUserLocation.getBearing();
} else {
- bearing = (float) mMapView.getBearing();
+ bearing = mMapboxMap.getCameraPosition().bearing;
}
if (mCurrentMapViewCoordinate == null) {
- mCurrentMapViewCoordinate = mMapView.getMapboxMap().getCameraPosition().target;
+ mCurrentMapViewCoordinate = mMapboxMap.getCameraPosition().target;
}
// only update if there is an actual change
@@ -302,11 +297,10 @@ public final class UserLocationView extends View {
.target(mMarkerCoordinate)
.bearing(bearing)
.build();
- mMapView.getMapboxMap().animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 300, null);
+ mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 300, null);
mMarkerScreenMatrix.reset();
- mMarkerScreenMatrix.setTranslate(
- getMeasuredWidth() / 2,
- getMeasuredHeight() / 2);
+ mMarkerScreenPoint = getMarkerScreenPoint();
+ mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y);
// set values for next check for actual change
mCurrentMapViewCoordinate = mMarkerCoordinate;
@@ -317,10 +311,10 @@ public final class UserLocationView extends View {
// rotate so arrow in points to bearing
if (mShowDirection) {
if (mMyBearingTrackingMode == MyBearingTracking.COMPASS && mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenMatrix.preRotate(mCompassMarkerDirection + (float) mMapView.getDirection());
+ mMarkerScreenMatrix.preRotate(mCompassMarkerDirection + mMapboxMap.getCameraPosition().bearing);
} else if (mMyBearingTrackingMode == MyBearingTracking.GPS) {
if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenMatrix.preRotate(mGpsMarkerDirection + (float) mMapView.getDirection());
+ mMarkerScreenMatrix.preRotate(mGpsMarkerDirection + mMapboxMap.getCameraPosition().bearing);
} else {
mMarkerScreenMatrix.preRotate(mGpsMarkerDirection);
}
@@ -331,7 +325,7 @@ public final class UserLocationView extends View {
if (mShowAccuracy && !mStaleMarker) {
mAccuracyPath.reset();
mAccuracyPath.addCircle(0.0f, 0.0f,
- (float) (mMarkerAccuracy / mMapView.getMetersPerPixelAtLatitude(
+ (float) (mMarkerAccuracy / mMapboxMap.getProjection().getMetersPerPixelAtLatitude(
mMarkerCoordinate.getLatitude())),
Path.Direction.CW);
@@ -371,11 +365,11 @@ public final class UserLocationView extends View {
*/
private void toggleGps(boolean enableGps) {
- LocationServices locationServices = LocationServices.getLocationServices(getContext());
+ LocationService locationService = LocationService.getInstance(getContext());
if (enableGps) {
// Set an initial location if one available
- Location lastLocation = locationServices.getLastLocation();
+ Location lastLocation = locationService.getLastLocation();
if (lastLocation != null) {
setLocation(lastLocation);
}
@@ -385,16 +379,16 @@ public final class UserLocationView extends View {
}
// Register for Location Updates
- locationServices.addLocationListener(mUserLocationListener);
+ locationService.addLocationListener(mUserLocationListener);
} else {
// Disable location and user dot
setLocation(null);
// Deregister for Location Updates
- locationServices.removeLocationListener(mUserLocationListener);
+ locationService.removeLocationListener(mUserLocationListener);
}
- locationServices.toggleGPS(enableGps);
+ locationService.toggleGPS(enableGps);
}
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
@@ -415,11 +409,6 @@ public final class UserLocationView extends View {
update();
}
- @MyBearingTracking.Mode
- public int getMyBearingTrackingMode() {
- return mMyBearingTrackingMode;
- }
-
private class MyBearingListener implements SensorEventListener {
private SensorManager mSensorManager;
@@ -483,9 +472,8 @@ public final class UserLocationView extends View {
SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
SensorManager.getOrientation(mR, mOrientation);
float azimuthInRadians = mOrientation[0];
- float azimuthInDegress = (float) (Math.toDegrees(azimuthInRadians) + 360) % 360;
- mCompassBearing = azimuthInDegress;
+ mCompassBearing = (float) (Math.toDegrees(azimuthInRadians) + 360) % 360;
if (mCompassBearing < 0) {
// only allow positive degrees
mCompassBearing += 360;
@@ -515,7 +503,7 @@ public final class UserLocationView extends View {
/**
- * Callback method for receiving location updates from LocationServices.
+ * Callback method for receiving location updates from LocationService.
*
* @param location The new Location data
*/
@@ -670,7 +658,7 @@ public final class UserLocationView extends View {
}
void updateOnNextFrame() {
- mMapView.update();
+ mMapboxMap.invalidate();
}
/**
@@ -770,4 +758,14 @@ public final class UserLocationView extends View {
return mPaused;
}
+ public PointF getMarkerScreenPoint() {
+ if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
+ mMarkerScreenPoint = mProjection.toScreenLocation(mMarkerCoordinate);
+ } else {
+ int[] contentPadding = mMapboxMap.getPadding();
+ mMarkerScreenPoint = new PointF(((getMeasuredWidth() + contentPadding[0] - contentPadding[2]) / 2)
+ , ((getMeasuredHeight() - contentPadding[3] + contentPadding[1]) / 2));
+ }
+ return mMarkerScreenPoint;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
new file mode 100644
index 0000000000..87dfb7ec3c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
@@ -0,0 +1,59 @@
+package com.mapbox.mapboxsdk.telemetry;
+
+import java.io.Serializable;
+
+public class MapboxEvent implements Serializable {
+ public static final int VERSION_NUMBER = 1;
+ public static final String MGLMapboxEventsUserAgent = "MapboxEventsAndroid/1.1";
+ public static final String MAPBOX_EVENTS_BASE_URL = "https://api.mapbox.com";
+
+ // Event Types
+ public static final String TYPE_TURNSTILE = "appUserTurnstile";
+ public static final String TYPE_MAP_LOAD = "map.load";
+ public static final String TYPE_MAP_CLICK = "map.click";
+ public static final String TYPE_MAP_DRAGEND = "map.dragend";
+ public static final String TYPE_LOCATION = "location";
+ public static final String TYPE_VISIT = "visit";
+
+ // Event Keys
+ public static final String KEY_LATITUDE = "lat";
+ public static final String KEY_LONGITUDE = "lng";
+ public static final String KEY_SPEED = "speed";
+ public static final String KEY_COURSE = "course";
+ public static final String KEY_ALTITUDE = "altitude";
+ public static final String KEY_HORIZONTAL_ACCURACY = "horizontalAccuracy";
+ public static final String KEY_ZOOM = "zoom";
+
+ public static final String KEY_PUSH_ENABLED = "enabled.push";
+ public static final String KEY_EMAIL_ENABLED = "enabled.email";
+ public static final String KEY_GESTURE_ID = "gesture";
+ public static final String KEY_ARRIVAL_DATE = "arrivalDate";
+ public static final String KEY_DEPARTURE_DATE = "departureDate";
+
+ public static final String GESTURE_SINGLETAP = "SingleTap";
+ public static final String GESTURE_DOUBLETAP = "DoubleTap";
+ public static final String GESTURE_TWO_FINGER_SINGLETAP = "TwoFingerTap";
+ public static final String GESTURE_QUICK_ZOOM = "QuickZoom";
+ public static final String GESTURE_PAN_START = "Pan";
+ public static final String GESTURE_PINCH_START = "Pinch";
+ public static final String GESTURE_ROTATION_START = "Rotation";
+ public static final String GESTURE_PITCH_START = "Pitch";
+
+ // Event Attributes
+ public static final String ATTRIBUTE_EVENT = "event";
+ public static final String ATTRIBUTE_SESSION_ID = "sessionId";
+ public static final String ATTRIBUTE_VERSION = "version";
+ public static final String ATTRIBUTE_CREATED = "created";
+ public static final String ATTRIBUTE_VENDOR_ID = "vendorId";
+ public static final String ATTRIBUTE_APP_BUNDLE_ID = "appBundleId";
+ public static final String ATTRIBUTE_MODEL = "model";
+ public static final String ATTRIBUTE_OPERATING_SYSTEM= "operatingSystem";
+ public static final String ATTRIBUTE_ORIENTATION = "orientation";
+ public static final String ATTRIBUTE_BATTERY_LEVEL = "batteryLevel";
+ public static final String ATTRIBUTE_APPLICATION_STATE = "applicationState";
+ public static final String ATTRIBUTE_RESOLUTION = "resolution";
+ public static final String ATTRIBUTE_ACCESSIBILITY_FONT_SCALE = "accessibilityFontScale";
+ public static final String ATTRIBUTE_CARRIER = "carrier";
+ public static final String ATTRIBUTE_CELLULAR_NETWORK_TYPE = "cellularNetworkType";
+ public static final String ATTRIBUTE_WIFI = "wifi";
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
new file mode 100644
index 0000000000..a62fdc98c5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
@@ -0,0 +1,532 @@
+package com.mapbox.mapboxsdk.telemetry;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.location.Location;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.os.BatteryManager;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.WindowManager;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.location.LocationService;
+import com.mapbox.mapboxsdk.utils.ApiAccess;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.UUID;
+import java.util.Vector;
+import okhttp3.CertificatePinner;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+public class MapboxEventManager {
+
+ private static final String TAG = "MapboxEventManager";
+
+ private static MapboxEventManager mapboxEventManager = null;
+
+ private boolean telemetryEnabled;
+
+ private final Vector<Hashtable<String, Object>> events = new Vector<>();
+ private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+ private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
+
+ private Context context = null;
+ private String accessToken = null;
+ private String eventsURL = MapboxEvent.MAPBOX_EVENTS_BASE_URL;
+
+ private String userAgent = MapboxEvent.MGLMapboxEventsUserAgent;
+
+ private Intent batteryStatus = null;
+
+ private DisplayMetrics displayMetrics = null;
+
+ private String mapboxVendorId = null;
+
+ private String mapboxSessionId = null;
+ private long mapboxSessionIdLastSet = 0;
+ private static long hourInMillis = 1000 * 60 * 60;
+ private static long flushDelayInitialInMillis = 1000 * 10; // 10 Seconds
+ private static long flushDelayInMillis = 1000 * 60 * 2; // 2 Minutes
+ private static final int SESSION_ID_ROTATION_HOURS = 24;
+
+ private static MessageDigest messageDigest = null;
+
+ private Timer timer = null;
+
+ private MapboxEventManager(@NonNull Context context) {
+ super();
+ this.accessToken = ApiAccess.getToken(context);
+ this.context = context;
+
+ // Setup Message Digest
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ Log.w(TAG, "Error getting Encryption Algorithm: " + e);
+ }
+
+ SharedPreferences prefs = context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE);
+
+ // Determine if Telemetry Should Be Enabled
+ setTelemetryEnabled(prefs.getBoolean(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED, true));
+
+ // Load / Create Vendor Id
+ if (prefs.contains(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID)) {
+ mapboxVendorId = prefs.getString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID, "Default Value");
+ Log.d(TAG, "Found Vendor Id = " + mapboxVendorId);
+ } else {
+ String vendorId = UUID.randomUUID().toString();
+ vendorId = encodeString(vendorId);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID, vendorId);
+ editor.apply();
+ editor.commit();
+ Log.d(TAG, "Set New Vendor Id = " + vendorId);
+ }
+
+ // Create Initial Session Id
+ rotateSessionId();
+
+ // Get DisplayMetrics Setup
+ displayMetrics = new DisplayMetrics();
+ ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
+
+ // Check for Staging Server Information
+ try {
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ String stagingURL = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_SERVER);
+ String stagingAccessToken = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_ACCESS_TOKEN);
+ String appName = context.getPackageManager().getApplicationLabel(appInfo).toString();
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ String versionName = packageInfo.versionName;
+ int versionCode = packageInfo.versionCode;
+
+ if (!TextUtils.isEmpty(stagingURL)) {
+ eventsURL = stagingURL;
+ }
+
+ if (!TextUtils.isEmpty(stagingAccessToken)) {
+ this.accessToken = stagingAccessToken;
+ }
+
+ // Build User Agent
+ if (!TextUtils.isEmpty(appName) && !TextUtils.isEmpty(versionName)) {
+ userAgent = appName + "/" + versionName + "/" + versionCode + " " + userAgent;
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error Trying to load Staging Credentials: " + e.toString());
+ }
+
+ // Register for battery updates
+ IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ batteryStatus = context.registerReceiver(null, iFilter);
+ }
+
+ /**
+ * Primary Access method using Singleton pattern
+ * @param context Application Context
+ * @return MapboxEventManager
+ */
+ public static MapboxEventManager getMapboxEventManager(@NonNull Context context) {
+ if (mapboxEventManager == null) {
+ mapboxEventManager = new MapboxEventManager(context.getApplicationContext());
+ }
+ return mapboxEventManager;
+ }
+
+ public boolean isTelemetryEnabled() {
+ return telemetryEnabled;
+ }
+
+ /**
+ * Enables / Disables Telemetry
+ * @param telemetryEnabled True to start telemetry, false to stop it
+ */
+ public void setTelemetryEnabled(boolean telemetryEnabled) {
+ if (this.telemetryEnabled == telemetryEnabled) {
+ Log.i(TAG, "no need to start / stop telemetry as it's already in that state.");
+ return;
+ }
+
+ if (telemetryEnabled) {
+ Log.i(TAG, "Starting Telemetry Up!");
+ // Start It Up
+ context.startService(new Intent(context, TelemetryService.class));
+
+ // Make sure Ambient Mode is started at a minimum
+ if (LocationService.getInstance(context).isGPSEnabled()) {
+ LocationService.getInstance(context).toggleGPS(false);
+ }
+
+ // Manage Timer Flush
+ timer = new Timer();
+ timer.schedule(new FlushEventsTimerTask(), flushDelayInitialInMillis, flushDelayInMillis);
+ } else {
+ Log.i(TAG, "Shutting Telemetry Down");
+ // Shut It Down
+ events.removeAllElements();
+ context.stopService(new Intent(context, TelemetryService.class));
+
+ if (timer != null) {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+ // Persist
+ this.telemetryEnabled = telemetryEnabled;
+ SharedPreferences prefs = context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED, telemetryEnabled);
+ editor.apply();
+ editor.commit();
+ }
+
+ /**
+ * Adds a Location Event to the system for processing
+ * @param location Location event
+ */
+ public void addLocationEvent(Location location) {
+ // Add Location even to queue
+ Hashtable<String, Object> event = new Hashtable<>();
+ event.put(MapboxEvent.KEY_LATITUDE, location.getLatitude());
+ event.put(MapboxEvent.KEY_LONGITUDE, location.getLongitude());
+ event.put(MapboxEvent.KEY_SPEED, location.getSpeed());
+ event.put(MapboxEvent.KEY_COURSE, location.getBearing());
+ event.put(MapboxEvent.KEY_ALTITUDE, location.getAltitude());
+ event.put(MapboxEvent.KEY_HORIZONTAL_ACCURACY, location.getAccuracy());
+ event.put(MapboxEvent.ATTRIBUTE_CREATED, dateFormat.format(new Date()));
+ event.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_LOCATION);
+
+ events.add(event);
+
+ rotateSessionId();
+ }
+
+ /**
+ * Push Interactive Events to the system for processing
+ * @param eventWithAttributes Event with attributes
+ */
+ public void pushEvent(Hashtable<String, Object> eventWithAttributes) {
+
+ if (eventWithAttributes == null) {
+ return;
+ }
+
+ String eventType = (String)eventWithAttributes.get(MapboxEvent.ATTRIBUTE_EVENT);
+ if (!TextUtils.isEmpty(eventType) && eventType.equalsIgnoreCase(MapboxEvent.TYPE_MAP_LOAD)) {
+ pushTurnstileEvent();
+ }
+
+ events.add(eventWithAttributes);
+ }
+
+ /**
+ * Pushes turnstile event for internal billing purposes
+ */
+ private void pushTurnstileEvent() {
+
+ Hashtable<String, Object> event = new Hashtable<>();
+ event.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_TURNSTILE);
+ event.put(MapboxEvent.ATTRIBUTE_CREATED, dateFormat.format(new Date()));
+/*
+ // Already set by processing
+ event.put(MapboxEvent.ATTRIBUTE_APP_BUNDLE_ID, context.getPackageName());
+ event.put(MapboxEvent.ATTRIBUTE_VERSION, MapboxEvent.VERSION_NUMBER);
+ event.put(MapboxEvent.ATTRIBUTE_VENDOR_ID, mapboxVendorId);
+*/
+
+ events.add(event);
+
+ // Send to Server Immediately
+ new FlushTheEventsTask().execute();
+ Log.d(TAG, "turnstile event pushed.");
+ }
+
+ /**
+ * SHA-1 Encoding for strings
+ * @param string String to encode
+ * @return String encoded if no error, original string if error
+ */
+ private String encodeString(String string) {
+ try {
+ if (messageDigest != null) {
+ messageDigest.reset();
+ messageDigest.update(string.getBytes("UTF-8"));
+ byte[] bytes = messageDigest.digest();
+
+ // Get the Hex version of the digest
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append( String.format("%02X", b) );
+ }
+ String hex = sb.toString();
+ Log.d(TAG, "original = " + string + "; hex = " + hex);
+
+ return hex;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error encoding string, will return in original form." + e);
+ }
+ return string;
+ }
+
+ /**
+ * Changes Session Id based on time boundary
+ */
+ private void rotateSessionId() {
+ long now = System.currentTimeMillis();
+ if (now - mapboxSessionIdLastSet > (SESSION_ID_ROTATION_HOURS * hourInMillis)) {
+ mapboxSessionId = UUID.randomUUID().toString();
+ mapboxSessionIdLastSet = System.currentTimeMillis();
+ }
+ }
+
+ private String getOrientation() {
+ switch (context.getResources().getConfiguration().orientation) {
+ case Configuration.ORIENTATION_LANDSCAPE:
+ return "Landscape";
+ case Configuration.ORIENTATION_PORTRAIT:
+ return "Portrait";
+ default:
+ return "Undefined";
+ }
+ }
+
+ private int getBatteryLevel() {
+ int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+
+ return Math.round((level / (float)scale) * 100);
+ }
+
+ private String getApplicationState() {
+
+ ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
+ if (appProcesses == null) {
+ return "Unknown";
+ }
+ final String packageName = context.getPackageName();
+ for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
+ if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
+ return "Foreground";
+ }
+ }
+ return "Background";
+ }
+
+ private float getAccesibilityFontScaleSize() {
+ // Values
+ // Small = 0.85
+ // Normal = 1.0
+ // Large = 1.15
+ // Huge = 1.3
+
+ return context.getResources().getConfiguration().fontScale;
+ }
+
+ private String getCellularCarrier() {
+ TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+ String carrierName = manager.getNetworkOperatorName();
+ if (TextUtils.isEmpty(carrierName)) {
+ carrierName = "None";
+ }
+ return carrierName;
+ }
+
+ private String getCellularNetworkType () {
+ TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+ switch (manager.getNetworkType()) {
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ return "1xRTT";
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ return "CDMA";
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ return "EDGE";
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ return "EHRPD";
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:
+ return "EVDO_0";
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ return "EVDO_A";
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ return "EVDO_B";
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ return "GPRS";
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ return "HSDPA";
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ return "HSPA";
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ return "HSPAP";
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ return "HSUPA";
+ case TelephonyManager.NETWORK_TYPE_IDEN:
+ return "IDEN";
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ return "LTE";
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ return "UMTS";
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ return "Unknown";
+ default:
+ return "Default Unknown";
+ }
+ }
+
+
+ public String getConnectedToWifi() {
+
+ String status = "No";
+ WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ if (wifiMgr.isWifiEnabled()) {
+ try {
+ WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
+ if( wifiInfo.getNetworkId() != -1 ){
+ status = "Yes";
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error getting Wifi Connection Status: " + e);
+ status = "Unknown";
+ }
+ }
+
+ return status;
+ }
+
+ /**
+ * Task responsible for converting stored events and sending them to the server
+ */
+ private class FlushTheEventsTask extends AsyncTask<Void, Void, Void> {
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+
+ if (events.size() < 1) {
+ Log.i(TAG, "No events in the queue to send so returning.");
+ return null;
+ }
+
+ // Check for NetworkConnectivity
+ ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ if (networkInfo == null || !networkInfo.isConnected()) {
+ Log.w(TAG, "Not connected to network, so returning without attempting to send events");
+ return null;
+ }
+
+ try {
+ // Send data
+ // =========
+ JSONArray jsonArray = new JSONArray();
+
+ for (Hashtable<String, Object> evt : events) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(MapboxEvent.KEY_LATITUDE, evt.get(MapboxEvent.KEY_LATITUDE));
+ jsonObject.put(MapboxEvent.KEY_LONGITUDE, evt.get(MapboxEvent.KEY_LONGITUDE));
+ jsonObject.put(MapboxEvent.KEY_SPEED, evt.get(MapboxEvent.KEY_SPEED));
+ jsonObject.put(MapboxEvent.KEY_COURSE, evt.get(MapboxEvent.KEY_COURSE));
+ jsonObject.put(MapboxEvent.KEY_ALTITUDE, evt.get(MapboxEvent.KEY_ALTITUDE));
+ jsonObject.put(MapboxEvent.KEY_HORIZONTAL_ACCURACY, evt.get(MapboxEvent.KEY_HORIZONTAL_ACCURACY));
+ jsonObject.put(MapboxEvent.KEY_ZOOM, evt.get(MapboxEvent.KEY_ZOOM));
+
+ // Basic Event Meta Data
+ jsonObject.put(MapboxEvent.ATTRIBUTE_EVENT, evt.get(MapboxEvent.ATTRIBUTE_EVENT));
+ jsonObject.put(MapboxEvent.ATTRIBUTE_CREATED, evt.get(MapboxEvent.ATTRIBUTE_CREATED));
+ jsonObject.put(MapboxEvent.ATTRIBUTE_SESSION_ID, encodeString(mapboxSessionId));
+ jsonObject.put(MapboxEvent.ATTRIBUTE_VERSION, MapboxEvent.VERSION_NUMBER);
+ jsonObject.put(MapboxEvent.ATTRIBUTE_VENDOR_ID, mapboxVendorId);
+ jsonObject.put(MapboxEvent.ATTRIBUTE_APP_BUNDLE_ID, context.getPackageName());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_MODEL, Build.MODEL);
+ jsonObject.put(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM, Build.VERSION.RELEASE);
+ jsonObject.put(MapboxEvent.ATTRIBUTE_ORIENTATION, getOrientation());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL, getBatteryLevel());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_APPLICATION_STATE, getApplicationState());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_RESOLUTION, displayMetrics.density);
+ jsonObject.put(MapboxEvent.ATTRIBUTE_ACCESSIBILITY_FONT_SCALE, getAccesibilityFontScaleSize());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_CARRIER, getCellularCarrier());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE, getCellularNetworkType());
+ jsonObject.put(MapboxEvent.ATTRIBUTE_WIFI, getConnectedToWifi());
+
+ jsonArray.put(jsonObject);
+ }
+
+ // Based on http://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html
+ CertificatePinner certificatePinner = new CertificatePinner.Builder()
+ .add("cloudfront-staging.tilestream.net", "sha1/KcdiTca54HxWTV8VuAd67x8I=")
+ .add("cloudfront-staging.tilestream.net", "sha1//KDE76PP0DQBDcTnMFBv+efp4eg=")
+ .add("api.mapbox.com", "sha1/Uv71ooi32pyba+oLD7egnXm7/GQ=")
+ .add("api.mapbox.com", "sha1/hOP0d37/ZTSGgCSseE3DIZ1uSg0=")
+ .build();
+
+ OkHttpClient client = new OkHttpClient.Builder().certificatePinner(certificatePinner).build();
+ RequestBody body = RequestBody.create(JSON, jsonArray.toString());
+
+ String url = eventsURL + "/events/v1?access_token=" + accessToken;
+ Log.d(TAG, "url = " + url);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .header("User-Agent", userAgent)
+ .post(body)
+ .build();
+ Response response = client.newCall(request).execute();
+ Log.d(TAG, "Response Code from Mapbox Events Server: " + response.code() + " for " + events.size() + " events sent in.");
+
+ // Reset Events
+ // ============
+ events.removeAllElements();
+ } catch (Exception e) {
+ Log.e(TAG, "FlushTheEventsTask borked: " + e);
+ }
+
+ return null;
+ }
+
+ }
+
+
+ /**
+ * TimerTask responsible for sending event data to server
+ */
+ private class FlushEventsTimerTask extends TimerTask {
+ /**
+ * The task to run should be specified in the implementation of the {@code run()}
+ * method.
+ */
+ @Override
+ public void run() {
+ new FlushTheEventsTask().execute();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
new file mode 100644
index 0000000000..088d41be54
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
@@ -0,0 +1,71 @@
+package com.mapbox.mapboxsdk.telemetry;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import android.os.Handler;
+import android.util.Log;
+
+public class TelemetryLocationReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "TelemLocationReceiver";
+
+ public static final String INTENT_STRING = "com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver";
+
+ /**
+ * Default Constructor
+ */
+ public TelemetryLocationReceiver() {
+ super();
+ }
+
+ /**
+ * This method is called when the BroadcastReceiver is receiving an Intent
+ * broadcast. During this time you can use the other methods on
+ * BroadcastReceiver to view/modify the current result values. This method
+ * is always called within the main thread of its process, unless you
+ * explicitly asked for it to be scheduled on a different thread using
+ * {@link Context#registerReceiver(BroadcastReceiver,
+ * IntentFilter, String, Handler)}. When it runs on the main
+ * thread you should
+ * never perform long-running operations in it (there is a timeout of
+ * 10 seconds that the system allows before considering the receiver to
+ * be blocked and a candidate to be killed). You cannot launch a popup dialog
+ * in your implementation of onReceive().
+ * <p/>
+ * <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
+ * then the object is no longer alive after returning from this
+ * function.</b> This means you should not perform any operations that
+ * return a result to you asynchronously -- in particular, for interacting
+ * with services, you should use
+ * {@link Context#startService(Intent)} instead of
+ * {@link Context#bindService(Intent, ServiceConnection, int)}. If you wish
+ * to interact with a service that is already running, you can use
+ * {@link #peekService}.
+ * <p/>
+ * <p>The Intent filters used in {@link Context#registerReceiver}
+ * and in application manifests are <em>not</em> guaranteed to be exclusive. They
+ * are hints to the operating system about how to find suitable recipients. It is
+ * possible for senders to force delivery to specific recipients, bypassing filter
+ * resolution. For this reason, {@link #onReceive(Context, Intent) onReceive()}
+ * implementations should respond only to known actions, ignoring any unexpected
+ * Intents that they may receive.
+ *
+ * @param context The Context in which the receiver is running.
+ * @param intent The Intent being received.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Location location = (Location)intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
+ if (location != null) {
+ Log.d(TAG, "location received = " + location);
+ MapboxEventManager.getMapboxEventManager(context).addLocationEvent(location);
+ } else {
+ Log.d(TAG, "location NOT received");
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
new file mode 100644
index 0000000000..56006dadf6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
@@ -0,0 +1,145 @@
+package com.mapbox.mapboxsdk.telemetry;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ServiceInfo;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+public class TelemetryService extends Service {
+
+ private static final String TAG = "TelemetryService";
+
+ private TelemetryLocationReceiver telemetryLocationReceiver = null;
+ private PowerManager.WakeLock telemetryWakeLock;
+
+ /**
+ * Return the communication channel to the service. May return null if
+ * clients can not bind to the service. The returned
+ * {@link IBinder} is usually for a complex interface
+ * that has been <a href="{@docRoot}guide/components/aidl.html">described using
+ * aidl</a>.
+ * <p/>
+ * <p><em>Note that unlike other application components, calls on to the
+ * IBinder interface returned here may not happen on the main thread
+ * of the process</em>. More information about the main thread can be found in
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
+ * Threads</a>.</p>
+ *
+ * @param intent The Intent that was used to bind to this service,
+ * as given to {@link Context#bindService
+ * Context.bindService}. Note that any extras that were included with
+ * the Intent at that point will <em>not</em> be seen here.
+ * @return Return an IBinder through which clients can call on to the
+ * service.
+ */
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+
+ /**
+ * Called by the system when the service is first created. Do not call this method directly.
+ */
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Log.i(TAG, "onCreate() called");
+
+ // Enable Location Listening for lifecycle of app
+ IntentFilter filter = new IntentFilter(TelemetryLocationReceiver.INTENT_STRING);
+ telemetryLocationReceiver = new TelemetryLocationReceiver();
+ registerReceiver(telemetryLocationReceiver, filter);
+ }
+
+ /**
+ * Called by the system to notify a Service that it is no longer used and is being removed. The
+ * service should clean up any resources it holds (threads, registered
+ * receivers, etc) at this point. Upon return, there will be no more calls
+ * in to this Service object and it is effectively dead. Do not call this method directly.
+ */
+ @Override
+ public void onDestroy() {
+ shutdownTelemetry();
+ super.onDestroy();
+ }
+
+ /**
+ * This is called if the service is currently running and the user has
+ * removed a task that comes from the service's application. If you have
+ * set {@link ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
+ * then you will not receive this callback; instead, the service will simply
+ * be stopped.
+ *
+ * @param rootIntent The original root Intent that was used to launch
+ * the task that is being removed.
+ */
+ @Override
+ public void onTaskRemoved(Intent rootIntent) {
+ shutdownTelemetry();
+ super.onTaskRemoved(rootIntent);
+ }
+
+ /**
+ * Called by the system every time a client explicitly starts the service by calling
+ * {@link Context#startService}, providing the arguments it supplied and a
+ * unique integer token representing the start request. Do not call this method directly.
+ * <p/>
+ * <p>For backwards compatibility, the default implementation calls
+ * {@link #onStart} and returns either {@link #START_STICKY}
+ * or {@link #START_STICKY_COMPATIBILITY}.
+ * <p/>
+ * <p>If you need your application to run on platform versions prior to API
+ * level 5, you can use the following model to handle the older {@link #onStart}
+ * callback in that case. The <code>handleCommand</code> method is implemented by
+ * you as appropriate:
+ * <p/>
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
+ * start_compatibility}
+ * <p/>
+ * <p class="caution">Note that the system calls this on your
+ * service's main thread. A service's main thread is the same
+ * thread where UI operations take place for Activities running in the
+ * same process. You should always avoid stalling the main
+ * thread's event loop. When doing long-running operations,
+ * network calls, or heavy disk I/O, you should kick off a new
+ * thread, or use {@link AsyncTask}.</p>
+ *
+ * @param intent The Intent supplied to {@link Context#startService},
+ * as given. This may be null if the service is being restarted after
+ * its process has gone away, and it had previously returned anything
+ * except {@link #START_STICKY_COMPATIBILITY}.
+ * @param flags Additional data about this start request. Currently either
+ * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
+ * @param startId A unique integer representing this specific request to
+ * start. Use with {@link #stopSelfResult(int)}.
+ * @return The return value indicates what semantics the system should
+ * use for the service's current started state. It may be one of the
+ * constants associated with the {@link #START_CONTINUATION_MASK} bits.
+ * @see #stopSelfResult(int)
+ */
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ Log.i(TAG, "onStartCommand() called");
+
+ // Start WakeLock to keep Location Data working when device sleeps
+ PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ telemetryWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TelemetryWakeLock");
+ telemetryWakeLock.acquire();
+
+ return START_NOT_STICKY;
+ }
+
+ private void shutdownTelemetry() {
+ unregisterReceiver(telemetryLocationReceiver);
+ telemetryWakeLock.release();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java
new file mode 100644
index 0000000000..d6cb1ca852
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * This package contains the classes that manage the SDK's Telemetry services.
+ */
+package com.mapbox.mapboxsdk.telemetry;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ApiAccess.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ApiAccess.java
index 137d0730c3..4f968c3a13 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ApiAccess.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ApiAccess.java
@@ -37,7 +37,7 @@ public final class ApiAccess {
return token;
} catch (Exception e) {
// use fallback on string resource, used for development
- int tokenResId = context.getResources().getIdentifier("access_token", "string", context.getPackageName());
+ int tokenResId = context.getResources().getIdentifier("mapbox_access_token", "string", context.getPackageName());
return tokenResId != 0 ? context.getString(tokenResId) : null;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
index 777d879d48..be0038e8b8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
@@ -3,12 +3,12 @@
<!--Add references to exposed resources-->
<public name="AttributionAlertDialogStyle" type="style" />
- <public name="style_mapbox_streets" type="string" />
- <public name="style_emerald" type="string" />
- <public name="style_light" type="string" />
- <public name="style_dark" type="string" />
- <public name="style_satellite" type="string" />
- <public name="style_satellite_streets" type="string" />
+ <public name="mapbox_style_mapbox_streets" type="string" />
+ <public name="mapbox_style_emerald" type="string" />
+ <public name="mapbox_style_light" type="string" />
+ <public name="mapbox_style_dark" type="string" />
+ <public name="mapbox_style_satellite" type="string" />
+ <public name="mapbox_style_satellite_streets" type="string" />
<public name="center_longitude" type="attr" />
<public name="center_latitude" type="attr" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/attribution_telemetry_view.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/attribution_telemetry_view.xml
new file mode 100644
index 0000000000..04c47af90d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/attribution_telemetry_view.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ >
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/mapbox_attributionTelemetryMessage"
+ android:gravity="center_horizontal"/>
+
+ <ListView
+ android:id="@+id/telemetryOptionsList"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/infowindow_content.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/infowindow_content.xml
index 3e36cbf91a..a4fcc80681 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/infowindow_content.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/infowindow_content.xml
@@ -18,7 +18,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:maxEms="17"
- android:text="@string/infoWindowTitle"
+ android:text="@string/mapbox_infoWindowTitle"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
@@ -31,7 +31,7 @@
android:layout_marginTop="2dp"
android:lineSpacingExtra="1dp"
android:maxEms="17"
- android:text="@string/infoWindowDescription"
+ android:text="@string/mapbox_infoWindowDescription"
android:textColor="@color/gray"
android:textSize="14sp" />
@@ -40,7 +40,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxEms="17"
- android:text="@string/infoWindowAddress"
+ android:text="@string/mapbox_infoWindowAddress"
android:textColor="@color/black"
android:textSize="12sp"
android:visibility="gone" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
index d62fd9cfba..288fb441ad 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <com.mapbox.mapboxsdk.maps.CompassView
+ <com.mapbox.mapboxsdk.maps.widgets.CompassView
android:id="@+id/compassView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
@@ -15,7 +15,7 @@
android:id="@+id/logoView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:contentDescription="@string/mapboxIconContentDescription"
+ android:contentDescription="@string/mapbox_mapboxIconContentDescription"
android:src="@drawable/attribution_logo" />
<ImageView
@@ -24,12 +24,12 @@
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:clickable="true"
- android:contentDescription="@string/attributionsIconContentDescription"
+ android:contentDescription="@string/mapbox_attributionsIconContentDescription"
android:padding="7dp"
android:src="@drawable/ic_info_outline_24dp_selector"
android:background="@drawable/bg_default_selector"/>
- <com.mapbox.mapboxsdk.maps.UserLocationView
+ <com.mapbox.mapboxsdk.maps.widgets.UserLocationView
android:id="@+id/userLocationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
index 2c1fdf8d13..d5d26d09d2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
@@ -4,11 +4,23 @@
<item>&#169; Mapbox</item>
<item>&#169; OpenStreetMap</item>
<item>Improve this map</item>
+ <item>Telemetry Settings</item>
+ </array>
+ <array name="attribution_telemetry_options">
+ <item>Tell Me More</item>
+ <item>Don\'t Participate</item>
+ <item>Participate</item>
+ </array>
+ <array name="attribution_telemetry_options_already_participating">
+ <item>Tell Me More</item>
+ <item>Stop Participating</item>
+ <item>Keep Participating</item>
</array>
<!-- If editing this array update MapView.ATTRIBUTION_INDEX_IMPROVE_THIS_MAP -->
<array name="attribution_links" formatted="false" translatable="false">
<item>https://www.mapbox.com/about/maps/</item>
<item>http://www.openstreetmap.org/about/</item>
<item>https://www.mapbox.com/map-feedback/#/%1$f/%2$f/%3$d</item>
+ <item>https://www.mapbox.com/telemetry/</item>
</array>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index 63547247f3..f516e98dd8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -4,6 +4,8 @@
<attr name="center_longitude" format="float" />
<attr name="center_latitude" format="float" />
<attr name="zoom" format="float" />
+ <attr name="zoom_max" format="float" />
+ <attr name="zoom_min" format="float" />
<attr name="direction" format="float" />
<attr name="tilt" format="float" />
<attr name="zoom_enabled" format="boolean" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index fd612d511c..5167ecf936 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -5,7 +5,8 @@
<dimen name="infowindow_offset">-2dp</dimen>
<dimen name="infowindow_line_width">1.5dp</dimen>
<dimen name="seven_dp">7dp</dimen>
+ <dimen name="eight_dp">8dp</dimen>
<dimen name="ten_dp">10dp</dimen>
<dimen name="sixteen_dp">16dp</dimen>
<dimen name="seventy_six_dp">76dp</dimen>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
index eadcdcc043..f852c305b2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -1,18 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <string name="compassContentDescription">Map compass. Click to reset the map rotation to North.</string>
- <string name="attributionsIconContentDescription">Attribution icon. Click to show attribution dialog.</string>
- <string name="attributionsDialogTitle">Mapbox Android SDK</string>
- <string name="mapboxIconContentDescription">The Mapbox logo.</string>
- <string name="infoWindowTitle">Title</string>
- <string name="infoWindowDescription">Description</string>
- <string name="infoWindowAddress">Address</string>
+ <string name="mapbox_compassContentDescription">Map compass. Click to reset the map rotation to North.</string>
+ <string name="mapbox_attributionsIconContentDescription">Attribution icon. Click to show attribution dialog.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Make Mapbox Maps Better</string>
+ <string name="mapbox_attributionTelemetryMessage">You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.</string>
+ <string name="mapbox_mapboxIconContentDescription">The Mapbox logo.</string>
+ <string name="mapbox_infoWindowTitle">Title</string>
+ <string name="mapbox_infoWindowDescription">Description</string>
+ <string name="mapbox_infoWindowAddress">Address</string>
<!-- these are public -->
- <string name="style_mapbox_streets">mapbox://styles/mapbox/streets-v8</string>
- <string name="style_emerald">mapbox://styles/mapbox/emerald-v8</string>
- <string name="style_light">mapbox://styles/mapbox/light-v8</string>
- <string name="style_dark">mapbox://styles/mapbox/dark-v8</string>
- <string name="style_satellite">mapbox://styles/mapbox/satellite-v8</string>
- <string name="style_satellite_streets">mapbox://styles/mapbox/satellite-hybrid-v8</string>
+ <string name="mapbox_style_mapbox_streets">mapbox://styles/mapbox/streets-v8</string>
+ <string name="mapbox_style_emerald">mapbox://styles/mapbox/emerald-v8</string>
+ <string name="mapbox_style_light">mapbox://styles/mapbox/light-v8</string>
+ <string name="mapbox_style_dark">mapbox://styles/mapbox/dark-v8</string>
+ <string name="mapbox_style_satellite">mapbox://styles/mapbox/satellite-v8</string>
+ <string name="mapbox_style_satellite_streets">mapbox://styles/mapbox/satellite-hybrid-v8</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 7d18fabe32..76dd07b7d6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -7,7 +7,7 @@ task accessToken {
if (!tokenFile.exists()) {
String tokenFileContents = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<resources>\n" +
- " <string name=\"access_token\">" + "$System.env.MAPBOX_ACCESS_TOKEN" + "</string>\n" +
+ " <string name=\"mapbox_access_token\">" + "$System.env.MAPBOX_ACCESS_TOKEN" + "</string>\n" +
"</resources>"
if (tokenFileContents == null) {
@@ -33,8 +33,8 @@ android {
applicationId "com.mapbox.mapboxsdk.testapp"
minSdkVersion 15
targetSdkVersion 23
- versionCode 7
- versionName "3.1.0"
+ versionCode 8
+ versionName "4.0.0"
// Specify AndroidJUnitRunner as the default test instrumentation runner
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
index c6445ac6a4..255a724744 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
@@ -1,8 +1,6 @@
# Mapbox ProGuard configuration is handled in the SDK
-
-keep class android.support.** { *; }
-
--dontwarn retrofit.**
--keep class retrofit.** { *; }
--keepattributes Signature
--keepattributes Exceptions \ No newline at end of file
+-dontwarn com.squareup.**
+-dontwarn com.retrofit.**
+-dontwarn java.lang.**
+-dontwarn org.codehaus.** \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CameraActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CameraActivityTest.java
new file mode 100644
index 0000000000..1f176af879
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CameraActivityTest.java
@@ -0,0 +1,35 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on CameraActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CameraActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<CameraActivity> mActivityRule = new ActivityTestRule<>(CameraActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.cameraMapView);
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivityTest.java
new file mode 100644
index 0000000000..68633547ed
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on CameraActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CoordinateChangeActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<CoordinateChangeActivity> mActivityRule = new ActivityTestRule<>(CoordinateChangeActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DirectionsActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DirectionsActivityTest.java
new file mode 100644
index 0000000000..3ce8d00aa0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DirectionsActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on DirectionsActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DirectionsActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<DirectionsActivity> mActivityRule = new ActivityTestRule<>(DirectionsActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivityTest.java
new file mode 100644
index 0000000000..db014b69ac
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivityTest.java
@@ -0,0 +1,35 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on DoubleMapActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DoubleMapActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<DoubleMapActivity> mActivityRule = new ActivityTestRule<>(DoubleMapActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ checkViewIsDisplayed(R.id.mini_map);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivityTest.java
new file mode 100644
index 0000000000..b6feb8f1be
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivityTest.java
@@ -0,0 +1,33 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on DynamicMarkerChange
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DynamicMarkerChangeActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<DynamicMarkerChangeActivity> mActivityRule = new ActivityTestRule<>(
+ DynamicMarkerChangeActivity.class);
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+
+ @Test
+ public void testFabClick() {
+ ViewUtils.clickView(R.id.fab);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/GeocoderActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/GeocoderActivityTest.java
new file mode 100644
index 0000000000..c1ca7413c2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/GeocoderActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on GeocoderActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class GeocoderActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<GeocoderActivity> mActivityRule = new ActivityTestRule<>(GeocoderActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/InfoWindowConcurrentActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/InfoWindowConcurrentActivityTest.java
new file mode 100644
index 0000000000..e507c6cd61
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/InfoWindowConcurrentActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on InfoWindowConcurrentActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class InfoWindowConcurrentActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<InfoWindowConcurrentActivity> mActivityRule = new ActivityTestRule<>(InfoWindowConcurrentActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.infoWindowConcurrentMapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/VisibleCoordinateBoundsActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivityTest.java
index ad74ea21c8..057979aeb8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/VisibleCoordinateBoundsActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivityTest.java
@@ -14,7 +14,7 @@ import org.junit.runner.RunWith;
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
-public class VisibleCoordinateBoundsActivityTest extends BaseTest {
+public class LatLngBoundsActivityTest extends BaseTest {
@Rule
public ActivityTestRule<LatLngBoundsActivity> mActivityRule = new ActivityTestRule<>(
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityScreenTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityScreenTest.java
index bbfa4ec73a..7c56f4c874 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityScreenTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityScreenTest.java
@@ -4,17 +4,18 @@ import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
+import com.mapbox.mapboxsdk.testapp.utils.DrawerUtils;
+import com.mapbox.mapboxsdk.testapp.utils.GestureUtils;
+import com.mapbox.mapboxsdk.testapp.utils.ScreenshotUtil;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.doubleClick;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
/**
* Tests on MainActivity with screenshots
@@ -23,8 +24,6 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText;
@LargeTest
public class MainActivityScreenTest extends BaseTest {
- private final static String HOME_BUTTON_STRING = "Navigate up";
-
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class);
@@ -41,26 +40,49 @@ public class MainActivityScreenTest extends BaseTest {
checkViewIsDisplayed(R.id.mainMapView);
}
- /*
- * Take a screenshot of Mapbox Streets to monitor #1649
- */
+ @Test
+ public void testStyleEmerald() {
+ DrawerUtils.openDrawer();
+ DrawerUtils.clickItem(R.string.styleEmerald);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ takeNamedScreenshot(mActivity, "testEmeraldStyle");
+ }
@Test
- public void testMapboxStreetsBlackAndWhite() {
- // Click home and switch to Mapbox streets
- onView(withContentDescription(HOME_BUTTON_STRING))
- .perform(click());
- onView(withText(R.string.styleMapboxStreets))
- .perform(click());
+ public void testStyleStreets() {
+ DrawerUtils.openDrawer();
+ DrawerUtils.clickItem(R.string.styleMapboxStreets);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ takeNamedScreenshot(mActivity, "testStreetsStyle");
+ }
- // Zoom in
- onView(withId(R.id.mainMapView))
- .perform(doubleClick());
- onView(withId(R.id.mainMapView))
- .perform(doubleClick());
+ @Test
+ public void testStyleDark() {
+ DrawerUtils.openDrawer();
+ DrawerUtils.clickItem(R.string.styleDark);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ takeNamedScreenshot(mActivity, "testDarkStyle");
+ }
- // Standard screenshot
- takeNamedScreenshot(mActivity, "testMapboxStreetsBlackAndWhite");
+ @Test
+ public void testStyleLight() {
+ DrawerUtils.openDrawer();
+ DrawerUtils.clickItem(R.string.styleLight);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ takeNamedScreenshot(mActivity, "testLightStyle");
+ }
+
+ @Test
+ public void testStyleSatellite() {
+ DrawerUtils.openDrawer();
+ DrawerUtils.clickItem(R.string.styleSatellite);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ GestureUtils.doubleClickGesture(R.id.mainMapView);
+ takeNamedScreenshot(mActivity, "testSatelliteStyle");
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityTest.java
index c545bc118b..a5f3a2e791 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MainActivityTest.java
@@ -129,34 +129,6 @@ public class MainActivityTest extends BaseTest {
.check(matches(isDisplayed()));
}
- @Test
- public void testSwipeLeftMap() {
- onView(withId(R.id.mainMapView))
- .perform(swipeLeft())
- .check(matches(isDisplayed()));
- }
-
- @Test
- public void testSwipeRightMap() {
- onView(withId(R.id.mainMapView))
- .perform(swipeRight())
- .check(matches(isDisplayed()));
- }
-
- @Test
- public void testSwipeDownMap() {
- onView(withId(R.id.mainMapView))
- .perform(swipeDown())
- .check(matches(isDisplayed()));
- }
-
- @Test
- public void testSwipeUpMap() {
- onView(withId(R.id.mainMapView))
- .perform(swipeUp())
- .check(matches(isDisplayed()));
- }
-
/*
* Test the main drawer options
*/
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivityTest.java
new file mode 100644
index 0000000000..8ce8498d64
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on ManualZoomActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ManualZoomActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<ManualZoomActivity> mActivityRule = new ActivityTestRule<>(ManualZoomActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.manualZoomMapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivityTest.java
new file mode 100644
index 0000000000..c252077856
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on MapPaddingActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MapPaddingActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<MapPaddingActivity> mActivityRule = new ActivityTestRule<>(MapPaddingActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivityTest.java
new file mode 100644
index 0000000000..eaa1584a3f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on MapboxMapActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MapboxMapActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<MapboxMapActivity> mActivityRule = new ActivityTestRule<>(MapboxMapActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivityTest.java
new file mode 100644
index 0000000000..e93a7675f0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivityTest.java
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on MaxMinZoomActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MaxMinZoomActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<MaxMinZoomActivity> mActivityRule = new ActivityTestRule<>(MaxMinZoomActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.manualZoomMapView);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ScrollByActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ScrollByActivityTest.java
new file mode 100644
index 0000000000..05386b089e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/ScrollByActivityTest.java
@@ -0,0 +1,26 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on ScrollByActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ScrollByActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<ScrollByActivity> mActivityRule = new ActivityTestRule<>(ScrollByActivity.class);
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mapView);
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivityTest.java
new file mode 100644
index 0000000000..7ae03e0d07
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivityTest.java
@@ -0,0 +1,35 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests on SupportMapFragmentActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SupportMapFragmentActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<SupportMapFragmentActivity> mActivityRule = new ActivityTestRule<>(SupportMapFragmentActivity.class);
+
+ private Activity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.fragment_container);
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/DrawerUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/DrawerUtils.java
new file mode 100644
index 0000000000..8d8905fdf4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/DrawerUtils.java
@@ -0,0 +1,29 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+import android.support.annotation.StringRes;
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.espresso.matcher.ViewMatchers;
+
+import com.mapbox.mapboxsdk.testapp.R;
+
+import org.hamcrest.Matchers;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+
+public class DrawerUtils {
+
+ private final static String HOME_BUTTON_STRING = "Navigate up";
+
+ public static void openDrawer(){
+ onView(withContentDescription(HOME_BUTTON_STRING)).perform(click());
+ }
+
+ public static void clickItem(@StringRes int txtId){
+ Espresso.onView(Matchers.allOf(ViewMatchers.withId(R.id.design_menu_item_text),
+ ViewMatchers.hasSibling(ViewMatchers.withText(txtId)))).perform(ViewActions.click());
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/GestureUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/GestureUtils.java
new file mode 100644
index 0000000000..37c18399e4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/GestureUtils.java
@@ -0,0 +1,17 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+import android.support.annotation.IdRes;
+
+import com.mapbox.mapboxsdk.testapp.R;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.doubleClick;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+public class GestureUtils {
+
+ public static void doubleClickGesture(@IdRes int id){
+ onView(withId(id)).perform(doubleClick());
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ViewUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ViewUtils.java
new file mode 100644
index 0000000000..01ee3e9b9f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ViewUtils.java
@@ -0,0 +1,15 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+import android.support.annotation.IdRes;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+public class ViewUtils {
+
+ public static void clickView(@IdRes int viewRes) {
+ onView(withId(viewRes))
+ .perform(click());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index e331884224..4b44efdfe5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -5,6 +5,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:name=".MapboxApplication"
@@ -84,10 +86,27 @@
<activity
android:name=".ScrollByActivity"
android:label="@string/activity_scroll_by" />
+ <activity
+ android:name=".DynamicMarkerChangeActivity"
+ android:label="@string/activity_dynamic_marker" />
+ <activity
+ android:name=".MapPaddingActivity"
+ android:screenOrientation="portrait"
+ android:label="@string/activity_map_padding" />
<meta-data
android:name="com.mapbox.AccessToken"
android:value="" />
+
+ <meta-data
+ android:name="com.mapbox.TestEventsServer"
+ android:value="https://cloudfront-staging.tilestream.net" />
+
+ <meta-data
+ android:name="com.mapbox.TestEventsAccessToken"
+ android:value="sk.eyJ1IjoiYmxlZWdlIiwiYSI6InNpcml1c2x5In0.KyT-boMyC_xZYTYojTc8zg" />
+
+ <service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService" />
</application>
</manifest>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/BulkMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/BulkMarkerActivity.java
index 3c5e53a0ad..e85f0dda63 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/BulkMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/BulkMarkerActivity.java
@@ -17,7 +17,7 @@ import android.widget.Spinner;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -150,7 +150,7 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
public LoadBulkMarkerTask(Context context, MapboxMap mapboxMap, int amount) {
mMapboxMap = mapboxMap;
- mapboxMap.removeAllAnnotations();
+ mapboxMap.removeAnnotations();
mProgressDialog = ProgressDialog.show(context, "Loading", "Fetching markers", false);
mAppContext = context.getApplicationContext();
mAmount = amount;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CameraActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CameraActivity.java
index 9ccbc34c3d..50c3c3e42e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CameraActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CameraActivity.java
@@ -10,9 +10,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -47,6 +48,12 @@ public class CameraActivity extends AppCompatActivity {
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
// set a style
mapboxMap.setStyle(Style.MAPBOX_STREETS);
+ mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
+ @Override
+ public void onCameraChange(CameraPosition position) {
+ Log.v(MapboxConstants.TAG, position.toString());
+ }
+ });
// handle move button clicks
findViewById(R.id.cameraMoveButton).setOnClickListener(new View.OnClickListener() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivity.java
index 25c3896be2..615b3388c3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/CoordinateChangeActivity.java
@@ -10,7 +10,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DirectionsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DirectionsActivity.java
index 7c37fc9540..6045eeadfd 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DirectionsActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DirectionsActivity.java
@@ -17,7 +17,7 @@ import com.mapbox.directions.service.models.Waypoint;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java
index 9bf168ee75..7af3790443 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java
@@ -12,12 +12,13 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.UiSettings;
public class DoubleMapActivity extends AppCompatActivity {
@@ -63,7 +64,7 @@ public class DoubleMapActivity extends AppCompatActivity {
super.onViewCreated(view, savedInstanceState);
// MapView large
- mMapView = (MapView) view.findViewById(R.id.mapview);
+ mMapView = (MapView) view.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
@@ -72,7 +73,8 @@ public class DoubleMapActivity extends AppCompatActivity {
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(18));
try {
- mapboxMap.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ TrackingSettings settings = mapboxMap.getTrackingSettings();
+ settings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
} catch (SecurityException e) {
// permission is handled in MainActivity
getActivity().finish();
@@ -96,7 +98,8 @@ public class DoubleMapActivity extends AppCompatActivity {
uiSettings.setLogoEnabled(false);
try {
- mapboxMap.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ TrackingSettings settings = mapboxMap.getTrackingSettings();
+ settings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
}catch (SecurityException e){
// permission is handled in MainActivity
getActivity().finish();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivity.java
new file mode 100644
index 0000000000..6bd7596ea1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DynamicMarkerChangeActivity.java
@@ -0,0 +1,145 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.utils.ApiAccess;
+
+public class DynamicMarkerChangeActivity extends AppCompatActivity {
+
+ private static final LatLng LAT_LNG_CHELSEA = new LatLng(51.481670, -0.190849);
+ private static final LatLng LAT_LNG_ARSENAL = new LatLng(51.555062, -0.108417);
+
+ private MapView mMapView;
+ private MapboxMap mMapboxMap;
+ private IconFactory mIconFactory;
+ private Marker mMarker;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dynamic_marker);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ mIconFactory = IconFactory.getInstance(this);
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMapView.setTag(true);
+ mMapView.setAccessToken(ApiAccess.getToken(this));
+ mMapView.onCreate(savedInstanceState);
+ mMapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ mMapboxMap = mapboxMap;
+ mapboxMap.setStyle(Style.MAPBOX_STREETS);
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.506675, -0.128699), 10));
+
+ // Create marker
+ MarkerOptions markerOptions = new MarkerOptions()
+ .position(LAT_LNG_CHELSEA)
+ .icon(mIconFactory.fromResource(R.drawable.ic_chelsea));
+ mMarker = mapboxMap.addMarker(markerOptions);
+ }
+ });
+
+
+ FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ fab.setColorFilter(ContextCompat.getColor(this, R.color.primary));
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mMapboxMap != null) {
+ updateMarker();
+ }
+ }
+ });
+ }
+
+ private void updateMarker() {
+ // update model
+ boolean first = (boolean) mMapView.getTag();
+ mMapView.setTag(!first);
+
+ // update marker
+ mMarker.setPosition(first ? LAT_LNG_CHELSEA : LAT_LNG_ARSENAL);
+ mMarker.setIcon(mIconFactory.fromResource(first ? R.drawable.ic_chelsea : R.drawable.ic_arsenal));
+ }
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mMapView.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mMapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mMapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mMapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mMapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mMapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mMapView.onLowMemory();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java
index b87812277c..5594348be7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java
@@ -78,7 +78,7 @@ public class GeocoderActivity extends AppCompatActivity {
@Override
public void onMapClick(@NonNull LatLng point) {
setMessage("Geocoding...");
- mapboxMap.removeAllAnnotations();
+ mapboxMap.removeAnnotations();
mapboxMap.addMarker(new MarkerOptions()
.position(point)
.title("Your finger is here"));
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowActivity.java
index e34bff9eed..f12a183563 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowActivity.java
@@ -6,6 +6,7 @@ import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
+import android.widget.Toast;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.annotations.Marker;
@@ -46,21 +47,24 @@ public class InfoWindowActivity extends AppCompatActivity {
mapboxMap.addMarker(new MarkerOptions()
.title("Intersection")
.snippet("H St NW with 15th St NW")
- .icon(IconFactory.getInstance(InfoWindowActivity.this)
- .fromAsset("london-underground-24.png"))
.position(new LatLng(38.9002073, -77.03364419)));
mapboxMap.addMarker(new MarkerOptions()
.title("White House")
.snippet("The official residence and principal workplace of the President of the United States, located at 1600 Pennsylvania Avenue NW in Washington, D.C. It has been the residence of every U.S. president since John Adams in 1800.")
- .icon(IconFactory.getInstance(InfoWindowActivity.this).fromAsset("town-hall-24.png"))
.position(new LatLng(38.897705003219784, -77.03655168667463)));
mapboxMap.addMarker(new MarkerOptions().title("Intersection")
.snippet("E St NW with 17th St NW")
- .icon(IconFactory.getInstance(InfoWindowActivity.this).fromAsset("commercial-24.png"))
.position(new LatLng(38.8954236, -77.0394623)));
+ mapboxMap.setOnInfoWindowCloseListener(new MapboxMap.OnInfoWindowCloseListener() {
+ @Override
+ public void onInfoWindowClose(Marker marker) {
+ Toast.makeText(getApplicationContext(),"OnClose: "+marker.getTitle(),Toast.LENGTH_LONG).show();
+ }
+ });
+
final DecimalFormat formatter = new DecimalFormat("#.#####");
mapboxMap.setOnMapLongClickListener(new MapboxMap.OnMapLongClickListener() {
@Override
@@ -78,6 +82,25 @@ public class InfoWindowActivity extends AppCompatActivity {
.position(point));
}
});
+
+
+ mapboxMap.setOnInfoWindowClickListener(new MapboxMap.OnInfoWindowClickListener() {
+ @Override
+ public boolean onInfoWindowClick(@NonNull Marker marker) {
+ Toast.makeText(getApplicationContext(), "OnClick: " + marker.getTitle(), Toast.LENGTH_LONG).show();
+ // return false to close the info window
+ // return true to leave the info window open
+ return false;
+ }
+ });
+
+ mapboxMap.setOnInfoWindowLongClickListener(new MapboxMap.OnInfoWindowLongClickListener() {
+ @Override
+ public void onInfoWindowLongClick(Marker marker) {
+ Toast.makeText(getApplicationContext(),"OnLongClick: "+marker.getTitle(),Toast.LENGTH_LONG).show();
+ }
+ });
+
}
});
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowAdapterActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowAdapterActivity.java
index 52f0bddc28..02380e59f2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowAdapterActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/InfoWindowAdapterActivity.java
@@ -16,10 +16,11 @@ import android.widget.TextView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.testapp.annotations.CityStateMarker;
+import com.mapbox.mapboxsdk.testapp.annotations.CityStateMarkerOptions;
import com.mapbox.mapboxsdk.utils.ApiAccess;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -54,12 +55,12 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
// add markers
- mapboxMap.addMarker(generateMarker("Andorra", 42.505777, 1.52529, "#F44336"));
- mapboxMap.addMarker(generateMarker("Luxembourg", 49.815273, 6.129583, "#3F51B5"));
- mapboxMap.addMarker(generateMarker("Monaco", 43.738418, 7.424616, "#673AB7"));
- mapboxMap.addMarker(generateMarker("Vatican City", 41.902916, 12.453389, "#009688"));
- mapboxMap.addMarker(generateMarker("San Marino", 43.942360, 12.457777, "#795548"));
- mapboxMap.addMarker(generateMarker("Liechtenstein", 47.166000, 9.555373, "#FF5722"));
+ mapboxMap.addMarker(generateCityStateMarker("Andorra", 42.505777, 1.52529, "#F44336"));
+ mapboxMap.addMarker(generateCityStateMarker("Luxembourg", 49.815273, 6.129583, "#3F51B5"));
+ mapboxMap.addMarker(generateCityStateMarker("Monaco", 43.738418, 7.424616, "#673AB7"));
+ mapboxMap.addMarker(generateCityStateMarker("Vatican City", 41.902916, 12.453389, "#009688"));
+ mapboxMap.addMarker(generateCityStateMarker("San Marino", 43.942360, 12.457777, "#795548"));
+ mapboxMap.addMarker(generateCityStateMarker("Liechtenstein", 47.166000, 9.555373, "#FF5722"));
// add custom window adapter
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
@@ -71,7 +72,12 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
TextView textView = new TextView(InfoWindowAdapterActivity.this);
textView.setText(marker.getTitle());
textView.setTextColor(Color.WHITE);
- textView.setBackgroundColor(Color.parseColor(marker.getSnippet()));
+
+ if(marker instanceof CityStateMarker){
+ CityStateMarker cityStateMarker = (CityStateMarker)marker;
+ textView.setBackgroundColor(Color.parseColor(cityStateMarker.getInfoWindowBackgroundColor()));
+ }
+
textView.setPadding(tenDp, tenDp, tenDp, tenDp);
return textView;
}
@@ -80,13 +86,13 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
});
}
- private MarkerOptions generateMarker(String title, double lat, double lng, String color) {
- MarkerOptions marker = new MarkerOptions();
+ private CityStateMarkerOptions generateCityStateMarker(String title, double lat, double lng, String color) {
+ CityStateMarkerOptions marker = new CityStateMarkerOptions();
marker.title(title);
- marker.snippet(color);
marker.position(new LatLng(lat, lng));
+ marker.infoWindowBackground(color);
- mIconDrawable.setColorFilter(Color.parseColor(marker.getSnippet()), PorterDuff.Mode.SRC_IN);
+ mIconDrawable.setColorFilter(Color.parseColor(color), PorterDuff.Mode.SRC_IN);
Icon icon = mIconFactory.fromDrawable(mIconDrawable);
marker.icon(icon);
return marker;
@@ -144,4 +150,5 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
}
+
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivity.java
index ee39beb04a..3246807f89 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/LatLngBoundsActivity.java
@@ -10,7 +10,7 @@ import android.view.MenuItem;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
index 3a473f63c5..d1ac656cd0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java
@@ -38,6 +38,7 @@ import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.layers.CustomLayer;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.layers.ExampleCustomLayer;
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
@@ -213,13 +214,21 @@ public class MainActivity extends AppCompatActivity {
mMapboxMap.setOnInfoWindowClickListener(new MapboxMap.OnInfoWindowClickListener() {
@Override
- public boolean onMarkerClick(@NonNull Marker marker) {
+ public boolean onInfoWindowClick(@NonNull Marker marker) {
Snackbar.make(mCoordinatorLayout, "InfoWindow Click Listener for " + marker.getTitle(), Snackbar.LENGTH_SHORT).show();
marker.hideInfoWindow();
return true;
}
});
+
+ mMapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
+ @Override
+ public void onCameraChange(CameraPosition position) {
+ Log.v(TAG, "OnCameraChange : " + position);
+ }
+ });
+
changeMapStyle(mSelectedStyle);
}
});
@@ -455,6 +464,14 @@ public class MainActivity extends AppCompatActivity {
startActivity(new Intent(getApplicationContext(), ScrollByActivity.class));
return true;
+ case R.id.action_dynamic_marker:
+ startActivity(new Intent(getApplicationContext(), DynamicMarkerChangeActivity.class));
+ return true;
+
+ case R.id.action_map_padding:
+ startActivity(new Intent(getApplicationContext(),MapPaddingActivity.class));
+ return true;
+
default:
return changeMapStyle(menuItem.getItemId());
}
@@ -539,12 +556,20 @@ public class MainActivity extends AppCompatActivity {
}
});
mMapboxMap.setMyLocationEnabled(true);
- mMapboxMap.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
- mMapboxMap.setMyBearingTrackingMode(MyBearingTracking.GPS);
+
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.GPS);
+
mLocationFAB.setColorFilter(ContextCompat.getColor(this, R.color.primary));
}
} else {
- mMapboxMap.setMyLocationEnabled(false);
+ if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED)) {
+ mMapboxMap.setMyLocationEnabled(false);
+ }
mLocationFAB.setColorFilter(Color.TRANSPARENT);
}
}
@@ -630,7 +655,7 @@ public class MainActivity extends AppCompatActivity {
private void removeAnnotations() {
mMarkerList.clear();
- mMapboxMap.removeAllAnnotations();
+ mMapboxMap.removeAnnotations();
}
private void addCustomLayer() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivity.java
index 83f50f7e61..1f74d1e7f8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ManualZoomActivity.java
@@ -10,7 +10,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapFragmentActivity.java
index e8750b66d7..4615d35e33 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapFragmentActivity.java
@@ -9,7 +9,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.MapFragment;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivity.java
new file mode 100644
index 0000000000..524925d51b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapPaddingActivity.java
@@ -0,0 +1,162 @@
+package com.mapbox.mapboxsdk.testapp;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.constants.MyLocationTracking;
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
+import com.mapbox.mapboxsdk.utils.ApiAccess;
+
+public class MapPaddingActivity extends AppCompatActivity {
+
+ private MapView mMapView;
+ private MapboxMap mMapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_map_padding);
+
+ final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMapView.setTag(true);
+ mMapView.setAccessToken(ApiAccess.getToken(this));
+ mMapView.onCreate(savedInstanceState);
+ mMapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ mMapboxMap = mapboxMap;
+ mapboxMap.setStyle(Style.MAPBOX_STREETS);
+
+ moveToBangalore();
+
+ int paddingLeft = (int) getResources().getDimension(R.dimen.map_padding_left);
+ int paddingBottom = (int) getResources().getDimension(R.dimen.map_padding_bottom);
+ int paddingRight = (int) getResources().getDimension(R.dimen.map_padding_right);
+ mapboxMap.setPadding(paddingLeft, toolbar.getHeight(), paddingRight, paddingBottom);
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mMapView.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mMapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mMapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mMapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mMapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mMapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mMapView.onLowMemory();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_padding, menu);
+ return true;
+ }
+
+ private void toggleGps(boolean enable) {
+ try {
+ // Enable user location
+ mMapboxMap.setMyLocationEnabled(enable);
+
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+ trackingSettings.setDismissTrackingOnGesture(false);
+ trackingSettings.setMyLocationTrackingMode(enable ? MyLocationTracking.TRACKING_FOLLOW : MyLocationTracking.TRACKING_NONE);
+ } catch (SecurityException e) {
+ // permission not granted is handled in MainActivity
+ finish();
+ }
+ }
+
+ private void moveToBangalore() {
+ toggleGps(false);
+ LatLng bangalore = new LatLng(12.9810816, 77.6368034);
+ mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .zoom(16)
+ .target(bangalore)
+ .bearing(40)
+ .tilt(45)
+ .build()));
+ mMapboxMap.addMarker(new MarkerOptions().title("Center map").position(bangalore));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+
+ case R.id.action_user_tracking:
+ if (mMapboxMap != null) {
+ toggleGps(true);
+ }
+ return true;
+
+ case R.id.action_bangalore:
+ if (mMapboxMap != null) {
+ moveToBangalore();
+ }
+ return true;
+
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivity.java
index 89ae1150ea..16160a2fc6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxMapActivity.java
@@ -9,7 +9,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivity.java
index 3ace776e02..19c2578db2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MaxMinZoomActivity.java
@@ -9,12 +9,13 @@ import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.utils.ApiAccess;
public class MaxMinZoomActivity extends AppCompatActivity {
@@ -44,8 +45,11 @@ public class MaxMinZoomActivity extends AppCompatActivity {
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mMapboxMap = mapboxMap;
mMapboxMap.setStyle(Style.SATELLITE_STREETS);
- mMapboxMap.setMinZoom(3);
- mMapboxMap.setMaxZoom(5);
+
+ UiSettings uiSettings = mapboxMap.getUiSettings();
+ uiSettings.setMinZoom(3);
+ uiSettings.setMaxZoom(5);
+
mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(-1.063510, 32.895425)));
}
});
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MyLocationTrackingModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MyLocationTrackingModeActivity.java
index 411ca36316..2f3f744e71 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MyLocationTrackingModeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MyLocationTrackingModeActivity.java
@@ -15,12 +15,13 @@ import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.utils.ApiAccess;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -39,25 +40,13 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
- ActionBar actionBar = getSupportActionBar();
+ final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
}
- ArrayAdapter<CharSequence> locationTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item);
- locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mLocationSpinner = (Spinner) findViewById(R.id.spinner_location);
- mLocationSpinner.setAdapter(locationTrackingAdapter);
- mLocationSpinner.setOnItemSelectedListener(this);
-
- ArrayAdapter<CharSequence> bearingTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item);
- bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mBearingSpinner = (Spinner) findViewById(R.id.spinner_bearing);
- mBearingSpinner.setAdapter(bearingTrackingAdapter);
- mBearingSpinner.setOnItemSelectedListener(this);
-
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.setAccessToken(ApiAccess.getToken(this));
mMapView.onCreate(savedInstanceState);
@@ -68,6 +57,18 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
mapboxMap.setOnMyLocationChangeListener(MyLocationTrackingModeActivity.this);
+ ArrayAdapter<CharSequence> locationTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item);
+ locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mLocationSpinner = (Spinner) findViewById(R.id.spinner_location);
+ mLocationSpinner.setAdapter(locationTrackingAdapter);
+ mLocationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this);
+
+ ArrayAdapter<CharSequence> bearingTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item);
+ bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mBearingSpinner = (Spinner) findViewById(R.id.spinner_bearing);
+ mBearingSpinner.setAdapter(bearingTrackingAdapter);
+ mBearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this);
+
try {
mapboxMap.setMyLocationEnabled(true);
} catch (SecurityException e) {
@@ -135,28 +136,29 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) throws SecurityException {
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
if (parent.getId() == R.id.spinner_location) {
switch (position) {
case 0:
- mMapboxMap.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
break;
case 1:
- mMapboxMap.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
break;
}
} else if (parent.getId() == R.id.spinner_bearing) {
switch (position) {
case 0:
- mMapboxMap.setMyBearingTrackingMode(MyBearingTracking.NONE);
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
break;
case 1:
- mMapboxMap.setMyBearingTrackingMode(MyBearingTracking.GPS);
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.GPS);
break;
case 2:
- mMapboxMap.setMyBearingTrackingMode(MyBearingTracking.COMPASS);
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.COMPASS);
break;
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java
index eaf2b240b0..313eb6722b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java
@@ -169,7 +169,7 @@ public class PolylineActivity extends AppCompatActivity {
case R.id.action_id_remove:
// test to remove all annotations
mPolylineOptions.clear();
- mMapboxMap.removeAllAnnotations();
+ mMapboxMap.removeAnnotations();
return true;
case android.R.id.home:
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ScrollByActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ScrollByActivity.java
index 47b81d35a8..2e0e741677 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ScrollByActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/ScrollByActivity.java
@@ -15,7 +15,7 @@ import android.widget.TextView;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivity.java
index 67d329d0d6..bf690b7943 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/SupportMapFragmentActivity.java
@@ -9,7 +9,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/TiltActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/TiltActivity.java
index 75c1eae191..1713673129 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/TiltActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/TiltActivity.java
@@ -8,7 +8,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.maps.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarker.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarker.java
new file mode 100644
index 0000000000..1ec5aa9c76
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarker.java
@@ -0,0 +1,18 @@
+package com.mapbox.mapboxsdk.testapp.annotations;
+
+import com.mapbox.mapboxsdk.annotations.Marker;
+
+public class CityStateMarker extends Marker {
+
+ private String mInfoWindowBackgroundColor;
+
+ public CityStateMarker(CityStateMarkerOptions cityStateOptions, String color) {
+ super(cityStateOptions);
+ mInfoWindowBackgroundColor = color;
+ }
+
+ public String getInfoWindowBackgroundColor() {
+ return mInfoWindowBackgroundColor;
+ }
+
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarkerOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarkerOptions.java
new file mode 100644
index 0000000000..379a9210e5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/annotations/CityStateMarkerOptions.java
@@ -0,0 +1,68 @@
+package com.mapbox.mapboxsdk.testapp.annotations;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+public class CityStateMarkerOptions extends BaseMarkerOptions<CityStateMarker, CityStateMarkerOptions> {
+
+ private String mInfoWindowBackgroundColor;
+
+ public CityStateMarkerOptions infoWindowBackground(String color) {
+ mInfoWindowBackgroundColor = color;
+ return getThis();
+ }
+
+ public CityStateMarkerOptions() {
+ }
+
+ private CityStateMarkerOptions(Parcel in) {
+ position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
+ snippet(in.readString());
+ String iconId = in.readString();
+ Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ Icon icon = IconFactory.recreate(iconId, iconBitmap);
+ icon(icon);
+ title(in.readString());
+ }
+
+ @Override
+ public CityStateMarkerOptions getThis() {
+ return this;
+ }
+
+ @Override
+ public CityStateMarker getMarker() {
+ return new CityStateMarker(this, mInfoWindowBackgroundColor);
+ }
+
+ public static final Parcelable.Creator<CityStateMarkerOptions> CREATOR
+ = new Parcelable.Creator<CityStateMarkerOptions>() {
+ public CityStateMarkerOptions createFromParcel(Parcel in) {
+ return new CityStateMarkerOptions(in);
+ }
+
+ public CityStateMarkerOptions[] newArray(int size) {
+ return new CityStateMarkerOptions[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(position, flags);
+ out.writeString(snippet);
+ out.writeString(icon.getId());
+ out.writeParcelable(icon.getBitmap(), flags);
+ out.writeString(title);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png
new file mode 100644
index 0000000000..6fdac4ef09
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png
new file mode 100644
index 0000000000..6cd376b281
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_dynamic_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_dynamic_marker.xml
new file mode 100644
index 0000000000..e16f6b317d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_dynamic_marker.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7,7h10v3l4,-4 -4,-4v3H5v6h2V7zm10,10H7v-3l-4,4 4,4v-3h12v-6h-2v4zm-4,-2V9h-1l-2,1v1h1.5v4H13z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_map_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_map_padding.xml
new file mode 100644
index 0000000000..60b75a5493
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_map_padding.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml
index 5de3651272..21684ccadb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml
@@ -16,6 +16,6 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets" />
+ app:style_url="@string/mapbox_style_mapbox_streets" />
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml
new file mode 100644
index 0000000000..73592448b2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="@color/primary"
+ android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@+id/toolbar">
+
+ <android.support.design.widget.CoordinatorLayout
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_animate_coordinates"
+ app:backgroundTint="@color/white" />
+
+ </android.support.design.widget.CoordinatorLayout>
+
+ </FrameLayout>
+
+</RelativeLayout>
+
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
index eccd3ea8eb..f9e0145356 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
@@ -16,7 +16,7 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:center_latitude="38.897705003219784"
app:center_longitude="-77.03655168667463"
app:zoom="15" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
index ccced6bbff..8cf30a4475 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
@@ -16,7 +16,7 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:center_latitude="47.798202"
app:center_longitude="7.573781"
app:zoom="4" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_concurrent.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_concurrent.xml
index 062726fcb2..69276ad491 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_concurrent.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_concurrent.xml
@@ -16,7 +16,7 @@
android:id="@+id/infoWindowConcurrentMapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:center_latitude="38.897705003219784"
app:center_longitude="-77.03655168667463"
app:zoom="15" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml
new file mode 100644
index 0000000000..aa3c50d65c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <View
+ android:layout_width="@dimen/map_padding_left"
+ android:layout_height="match_parent"
+ android:layout_marginTop="?attr/actionBarSize"
+ android:alpha="0.5"
+ android:background="@color/mapbox_blue" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/map_padding_bottom"
+ android:layout_gravity="bottom"
+ android:layout_marginEnd="@dimen/map_padding_right"
+ android:layout_marginLeft="@dimen/map_padding_left"
+ android:layout_marginRight="@dimen/map_padding_right"
+ android:layout_marginStart="@dimen/map_padding_left"
+ android:alpha="0.5"
+ android:background="@color/mapbox_blue" />
+
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:alpha="0.5"
+ android:background="@color/primary"
+ android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <View
+ android:layout_width="@dimen/map_padding_right"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:layout_marginLeft="@dimen/map_padding_left"
+ android:layout_marginStart="@dimen/map_padding_left"
+ android:alpha="0.5"
+ android:layout_marginTop="?attr/actionBarSize"
+ android:background="@color/mapbox_blue" />
+
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapboxmap.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapboxmap.xml
index eccd3ea8eb..f9e0145356 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapboxmap.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_mapboxmap.xml
@@ -16,7 +16,7 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:center_latitude="38.897705003219784"
app:center_longitude="-77.03655168667463"
app:zoom="15" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
index ce108ba129..5e9b8e62d7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
@@ -25,7 +25,7 @@
android:layout_height="match_parent"
app:center_latitude="38.897705003219784"
app:center_longitude="-77.03655168667463"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:zoom="15" />
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml
index 699fa4be6b..7b16910953 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml
@@ -42,7 +42,7 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:zoom="15" />
</LinearLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
index 7875fc2021..7f4012f74e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
@@ -19,7 +19,7 @@
android:layout_below="@+id/toolbar"
app:center_latitude="47.798202"
app:center_longitude="7.573781"
- app:style_url="@string/style_mapbox_streets"
+ app:style_url="@string/mapbox_style_mapbox_streets"
app:zoom="4" />
<android.support.design.widget.FloatingActionButton
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml
index 230a0a308e..88788fc429 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml
@@ -5,10 +5,10 @@
android:layout_height="fill_parent">
<com.mapbox.mapboxsdk.maps.MapView
- android:id="@+id/mapview"
+ android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- mapbox:access_token="@string/access_token" />
+ mapbox:access_token="@string/mapbox_access_token" />
<FrameLayout
android:id="@+id/map_card"
@@ -22,6 +22,6 @@
android:id="@+id/mini_map"
android:layout_width="100dp"
android:layout_height="100dp"
- mapbox:access_token="@string/access_token" />
+ mapbox:access_token="@string/mapbox_access_token" />
</FrameLayout>
</RelativeLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
index b008a4f636..512d195593 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml
@@ -192,7 +192,18 @@
android:icon="@drawable/ic_input_24dp"
android:title="@string/activity_scroll_by" />
+ <item
+ android:id="@+id/action_dynamic_marker"
+ android:checkable="false"
+ android:icon="@drawable/ic_dynamic_marker"
+ android:title="@string/action_dynamic_marker" />
+
+ <item
+ android:id="@+id/action_map_padding"
+ android:checkable="false"
+ android:icon="@drawable/ic_map_padding"
+ android:title="@string/action_map_padding" />
+
</menu>
</item>
-
</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml
new file mode 100644
index 0000000000..0db887c4e7
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:mapbox="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/action_user_tracking"
+ android:title="My Location Tracking"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_bangalore"
+ android:title="Bangalore"
+ mapbox:showAsAction="never" />
+</menu> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
index 87cfebffd6..c852ed0e7a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
@@ -3,4 +3,8 @@
<dimen name="fab_margin">16dp</dimen>
<dimen name="attr_margin">10dp</dimen>
<dimen name="coordinatebounds_margin">32dp</dimen>
+ <dimen name="map_padding_left">96dp</dimen>
+ <dimen name="map_padding_bottom">256dp</dimen>
+ <dimen name="map_padding_right">32dp</dimen>
+
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index 773642f291..ea346674b5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -25,6 +25,8 @@
<string name="activity_geocoder">Geocoder Activity</string>
<string name="activity_double_map">Double Map Activity</string>
<string name="activity_scroll_by">Scroll By Activity</string>
+ <string name="activity_dynamic_marker">Dynamic Marker Activity</string>
+ <string name="activity_map_padding">Map Padding Activity</string>
<string name="navdrawer_menu_title_mainactivity_controls">Main Activity Controls</string>
<string name="navdrawer_menu_title_mainactivity_styles">Main Activity Styles</string>
@@ -52,6 +54,8 @@
<string name="action_visible_bounds_explanation">Center map around 2 markers</string>
<string name="action_remove_polylines">Remove polylines</string>
<string name="action_double_mapview">Double MapView</string>
+ <string name="action_dynamic_marker">Dynamic Marker</string>
+ <string name="action_map_padding">Map Padding</string>
<string name="button_camera_move">Move</string>
<string name="button_camera_ease">Ease</string>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
new file mode 100644
index 0000000000..9e95451cb1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
@@ -0,0 +1,55 @@
+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;
+
+public class IconTest {
+
+ @Mock
+ Bitmap mBitmap;
+
+ @Before
+ public void beforeTest() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @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", mBitmap);
+ assertEquals("bitmap should match", mBitmap, icon.getBitmap());
+ }
+
+ @Test
+ public void testEquals() {
+ Icon icon1 = IconFactory.recreate("test", mBitmap);
+ Icon icon2 = IconFactory.recreate("test", mBitmap);
+ 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", mBitmap);
+ long expectedHashcode = 31 * mBitmap.hashCode() + "test".hashCode();
+ assertEquals("hashcode should match", expectedHashcode, icon.hashCode());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
new file mode 100644
index 0000000000..11ab8173fd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/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.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().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().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/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
new file mode 100644
index 0000000000..76e29c208b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
@@ -0,0 +1,119 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+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();
+ assertNotNull("marker should not be null", 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");
+ Marker marker = markerOptions.getMarker();
+ assertEquals(marker.getTitle(), "Mapbox");
+ assertEquals(markerOptions.getTitle(), "Mapbox");
+ }
+
+ @Test
+ public void testSnippet() {
+ MarkerOptions markerOptions = new MarkerOptions().snippet("Mapbox");
+ 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().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(10, 12)).getMarker();
+ assertEquals("hash code should match", marker.hashCode(), -1946419200);
+ }
+
+ @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 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 [longitude=0.0, latitude=0.0, altitude=0.0]" + "]]");
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolygonTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
index 281277692f..744bf55c07 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolygonTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.annotations;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolylineTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
index 78af961e02..b95c9dba2a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/PolylineTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.maps;
+package com.mapbox.mapboxsdk.annotations;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
new file mode 100644
index 0000000000..e2109adf47
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
@@ -0,0 +1,77 @@
+package com.mapbox.mapboxsdk.camera;
+
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.constants.MathConstants;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.utils.MathUtils;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class CameraPositionTest {
+
+ @Test
+ public void testSanity() {
+ LatLng latLng = new LatLng(1, 2);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ assertNotNull("cameraPosition should not be null", cameraPosition);
+ }
+
+ @Test
+ public void testToString() {
+ LatLng latLng = new LatLng(1, 2);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ assertEquals("toString should match", "Target: LatLng [longitude=2.0, latitude=1.0, altitude=0.0], Zoom:3.0, Bearing:5.0, Tilt:4.0", cameraPosition.toString());
+ }
+
+ @Test
+ public void testHashcode() {
+ LatLng latLng = new LatLng(1, 2);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ assertEquals("toString should match", -1007681505, cameraPosition.hashCode());
+ }
+
+ @Test
+ public void testRadiantBuilder() {
+ LatLng latLng = new LatLng(1, 2);
+ CameraPosition.Builder builder = new CameraPosition.Builder(true);
+ builder.target(latLng);
+ builder.zoom(3);
+ builder.tilt(4);
+ builder.bearing(5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ assertEquals("CameraPosition should match", cameraPosition, builder.build());
+ }
+
+ @Test
+ public void testDegreesRadiantBuilder() {
+ LatLng latLng = new LatLng(1, 2);
+ float tilt = 4;
+ float bearing = 5;
+ float bearingRadiant = (float) (-bearing * MathConstants.DEG2RAD);
+ float tiltRadiant = (float) (MathUtils.clamp(tilt, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT) * MathConstants.DEG2RAD);
+
+ CameraPosition.Builder degreeBuilder = new CameraPosition.Builder(false);
+ degreeBuilder.target(latLng);
+ degreeBuilder.zoom(3);
+ degreeBuilder.tilt(tilt);
+ degreeBuilder.bearing(bearing);
+
+ CameraPosition.Builder radiantBuilder = new CameraPosition.Builder(true);
+ radiantBuilder.target(latLng);
+ radiantBuilder.zoom(3);
+ radiantBuilder.tilt(tiltRadiant);
+ radiantBuilder.bearing(bearingRadiant);
+ assertEquals("CameraPosition should match", radiantBuilder.build(), degreeBuilder.build());
+ }
+
+ @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);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index 451d774a78..e3870b63e2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -2,9 +2,11 @@ package com.mapbox.mapboxsdk.geometry;
import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -85,6 +87,18 @@ public class LatLngBoundsTest {
}
@Test
+ public void testToLatLngs() {
+ mLatLngBounds = 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},
+ mLatLngBounds.toLatLngs());
+ }
+
+ @Test
public void testIncluding() {
assertTrue("LatLng should be included", mLatLngBounds.including(new LatLng(1, 1)));
}
@@ -106,6 +120,7 @@ public class LatLngBoundsTest {
.include(LAT_LNG_NOT_NULL_ISLAND)
.build();
assertEquals("equality should match", mLatLngBounds, latLngBounds);
+ assertEquals("not equal to a different object type", mLatLngBounds.equals(LAT_LNG_NOT_NULL_ISLAND), false);
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
index 452046082e..7bf164166c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
@@ -10,6 +10,7 @@ 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() {
@@ -18,6 +19,12 @@ public class LatLngSpanTest {
}
@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);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
index 057cbaed56..bd40221706 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
@@ -1,17 +1,55 @@
package com.mapbox.mapboxsdk.geometry;
-import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
-
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());
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
index 9423108214..83cfa37841 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
@@ -20,6 +20,13 @@ public class VisibleRegionTest {
}
@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);
@@ -57,6 +64,12 @@ public class VisibleRegionTest {
}
@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",
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
index 0f75655dc9..2fac586da1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
@@ -1,11 +1,17 @@
package com.mapbox.mapboxsdk.maps;
+import android.graphics.Color;
import android.graphics.Point;
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.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -15,9 +21,13 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.matches;
import static org.mockito.Mockito.mock;
import static org.junit.Assert.assertNotNull;
@@ -35,6 +45,39 @@ public class MapboxMapTest {
@Mock
MapboxMap.OnMarkerClickListener mOnMarkerClickListener;
+ @Mock
+ MapboxMap.OnCameraChangeListener mOnCameraChangeListener;
+
+ @Mock
+ MapboxMap.InfoWindowAdapter mInfoWindowAdapter;
+
+ @Mock
+ MapboxMap.OnScrollListener mScrollListener;
+
+ @Mock
+ MapboxMap.OnFlingListener mFlingListener;
+
+ @Mock
+ MapboxMap.OnFpsChangedListener mFpsChangedListener;
+
+ @Mock
+ MapboxMap.OnInfoWindowClickListener mWindowClickListener;
+
+ @Mock
+ MapboxMap.OnInfoWindowCloseListener mWindowCloseListener;
+
+ @Mock
+ MapboxMap.OnInfoWindowLongClickListener mWindowLongClickListener;
+
+ @Mock
+ MapboxMap.OnMyLocationChangeListener mLocationChangeListener;
+
+ @Mock
+ MapboxMap.OnMyLocationTrackingModeChangeListener mMyLocationTrackingModeChangeListener;
+
+ @Mock
+ MapboxMap.OnMyBearingTrackingModeChangeListener mMyBearingTrackingModeChangeListener;
+
@Before
public void beforeTest() {
MockitoAnnotations.initMocks(this);
@@ -46,6 +89,16 @@ public class MapboxMapTest {
assertNotNull("mMapboxMap should not be null", mMapboxMap);
}
+ @Test
+ public void testMock() {
+ assertNotNull("mMapView should be mocked", mMapView);
+ }
+
+ @Test
+ public void testGetMapView() {
+ assertNotNull("MapView should be non null", mMapboxMap.getMapView());
+ }
+
//
// UiSettings
//
@@ -56,15 +109,22 @@ public class MapboxMapTest {
}
//
- // Projection
+ // TrackingSettings
//
@Test
- public void testProjection(){
- assertNotNull("Projection should not be null",mMapboxMap.getProjection());
+ public void testTrackingSettings() {
+ assertNotNull("TrackingSettings should not be null", mMapboxMap.getTrackingSettings());
}
+ //
+ // Projection
+ //
+ @Test
+ public void testProjection() {
+ assertNotNull("Projection should not be null", mMapboxMap.getProjection());
+ }
//
// InfoWindow
@@ -82,31 +142,97 @@ public class MapboxMapTest {
assertFalse("ConcurrentWindows should be false", mMapboxMap.isAllowConcurrentMultipleOpenInfoWindows());
}
+ @Test
+ public void testInfoWindowAdapter() {
+ mMapboxMap.setInfoWindowAdapter(mInfoWindowAdapter);
+ assertEquals("InfoWindowAdpter should be the same", mInfoWindowAdapter, mMapboxMap.getInfoWindowAdapter());
+ }
+
//
// Location
//
@Test
public void testMyLocationEnabled() {
- try {
- mMapboxMap.setMyLocationEnabled(true);
- assertTrue("MyLocationEnabled should be true", mMapboxMap.isMyLocationEnabled());
- } catch (SecurityException e) {
- assertTrue(false);
- }
+ when(mMapView.isPermissionsAccepted()).thenReturn(true);
+ mMapboxMap.setMyLocationEnabled(true);
+ assertTrue("MyLocationEnabled should be true", mMapboxMap.isMyLocationEnabled());
+
}
@Test
public void testMyLocationDisabled() {
- try {
- mMapboxMap.setMyLocationEnabled(false);
- assertFalse("MyLocationEnabled should be false", mMapboxMap.isMyLocationEnabled());
- } catch (SecurityException e) {
- assertTrue(false);
- }
+ when(mMapView.isPermissionsAccepted()).thenReturn(true);
+ mMapboxMap.setMyLocationEnabled(false);
+ assertFalse("MyLocationEnabled should be false", mMapboxMap.isMyLocationEnabled());
+ }
+
+ //
+ // padding
+ //
+
+ @Test
+ public void testPadding() {
+ mMapboxMap.setOnCameraChangeListener(mOnCameraChangeListener);
+ CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build();
+ mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
+ mMapboxMap.setPadding(0, 0, 0, 0);
+ verify(mOnCameraChangeListener, times(2)).onCameraChange(position);
}
//
+ // setters/getters interfaces
+ //
+
+ @Test
+ public void testScrollListener() {
+ mMapboxMap.setOnScrollListener(mScrollListener);
+ assertEquals("ScrollListener should match", mScrollListener, mMapboxMap.getOnScrollListener());
+ }
+
+ @Test
+ public void testFlingListener() {
+ mMapboxMap.setOnFlingListener(mFlingListener);
+ assertEquals("FlingListener should match", mFlingListener, mMapboxMap.getOnFlingListener());
+ }
+
+ @Test
+ public void testFpsListener() {
+ mMapboxMap.setOnFpsChangedListener(mFpsChangedListener);
+ assertEquals("FpsListener should match", mFpsChangedListener, mMapboxMap.getOnFpsChangedListener());
+ }
+
+ @Test
+ public void testInfoWindowClickListener() {
+ mMapboxMap.setOnInfoWindowClickListener(mWindowClickListener);
+ assertEquals("InfoWidowClickListener should match", mWindowClickListener, mMapboxMap.getOnInfoWindowClickListener());
+ }
+
+ @Test
+ public void testInfoWindowCloseListener() {
+ mMapboxMap.setOnInfoWindowCloseListener(mWindowCloseListener);
+ assertEquals("InfoWindowCloseListener should match", mWindowCloseListener, mMapboxMap.getOnInfoWindowCloseListener());
+ }
+
+ @Test
+ public void testInfoWindowLongClickListener() {
+ mMapboxMap.setOnInfoWindowLongClickListener(mWindowLongClickListener);
+ assertEquals("InfoWindowLongClickListener should match", mWindowLongClickListener, mMapboxMap.getOnInfoWindowLongClickListener());
+ }
+
+ @Test
+ public void testOnBearingTrackingModeChangeListener(){
+ mMapboxMap.setOnMyBearingTrackingModeChangeListener(mMyBearingTrackingModeChangeListener);
+ assertEquals("MyBearingTrackingChangeListerner should match",mMyBearingTrackingModeChangeListener, mMapboxMap.getOnMyBearingTrackingModeChangeListener());
+ }
+
+ @Test
+ public void testOnLocationTrackingModeChangeListener(){
+ mMapboxMap.setOnMyLocationTrackingModeChangeListener(mMyLocationTrackingModeChangeListener);
+ assertEquals("MyLocationTrackigChangeListener should match",mMyLocationTrackingModeChangeListener, mMapboxMap.getOnMyLocationTrackingModeChangeListener());
+ }
+
+ //
// Style
//
@@ -183,7 +309,7 @@ public class MapboxMapTest {
@Test
public void testNewCameraPositionEaseCamera() {
CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build();
- mMapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(position), 1000);
+ mMapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(position));
assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition());
}
@@ -369,6 +495,238 @@ public class MapboxMapTest {
}
//
+ // OnCameraChangeListener
+ //
+
+ @Test
+ public void testOnCameraChangeListener() {
+ CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build();
+ mMapboxMap.setOnCameraChangeListener(mOnCameraChangeListener);
+ mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
+ verify(mOnCameraChangeListener, times(1)).onCameraChange(position);
+ }
+
+ //
+ // Annotations
+ //
+
+ @Test
+ public void testAddMarker() {
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker = mMapboxMap.addMarker(markerOptions);
+ assertTrue("Marker should be contained", mMapboxMap.getMarkers().contains(marker));
+ }
+
+ @Test
+ public void testAddMarkers() {
+ List<MarkerOptions> markerList = new ArrayList<>();
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a");
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ markerList.add(markerOptions1);
+ markerList.add(markerOptions2);
+ mMapboxMap.addMarkers(markerList);
+ assertEquals("Markers size should be 2", 2, mMapboxMap.getMarkers().size());
+ assertTrue(mMapboxMap.getMarkers().contains(markerOptions1.getMarker()));
+ assertTrue(mMapboxMap.getMarkers().contains(markerOptions2.getMarker()));
+ }
+
+ @Test
+ public void testAddPolygon() {
+ PolygonOptions polygonOptions = new PolygonOptions().add(new LatLng());
+ Polygon polygon = mMapboxMap.addPolygon(polygonOptions);
+ assertTrue("Polygon should be contained", mMapboxMap.getPolygons().contains(polygon));
+ }
+
+ @Test
+ public void testAddEmptyPolygon() {
+ PolygonOptions polygonOptions = new PolygonOptions();
+ Polygon polygon = mMapboxMap.addPolygon(polygonOptions);
+ assertTrue("Polygon should be ignored", !mMapboxMap.getPolygons().contains(polygon));
+ }
+
+ @Test
+ public void testAddPolygons() {
+ List<PolygonOptions> polygonList = new ArrayList<>();
+ PolygonOptions polygonOptions1 = new PolygonOptions().fillColor(Color.BLACK).add(new LatLng());
+ PolygonOptions polygonOptions2 = new PolygonOptions().fillColor(Color.WHITE).add(new LatLng());
+ PolygonOptions polygonOptions3 = new PolygonOptions();
+ polygonList.add(polygonOptions1);
+ polygonList.add(polygonOptions2);
+ polygonList.add(polygonOptions3);
+ mMapboxMap.addPolygons(polygonList);
+ assertEquals("Polygons size should be 2", 2, mMapboxMap.getPolygons().size());
+ assertTrue(mMapboxMap.getPolygons().contains(polygonOptions1.getPolygon()));
+ assertTrue(mMapboxMap.getPolygons().contains(polygonOptions2.getPolygon()));
+ assertTrue("Polygon should be ignored", !mMapboxMap.getPolygons().contains(polygonOptions3.getPolygon()));
+ }
+
+ @Test
+ public void testAddPolyline() {
+ PolylineOptions polylineOptions = new PolylineOptions().add(new LatLng());
+ Polyline polyline = mMapboxMap.addPolyline(polylineOptions);
+ assertTrue("Polyline should be contained", mMapboxMap.getPolylines().contains(polyline));
+ }
+
+ @Test
+ public void testAddEmptyPolyline() {
+ PolylineOptions polylineOptions = new PolylineOptions();
+ Polyline polyline = mMapboxMap.addPolyline(polylineOptions);
+ assertTrue("Polyline should be ignored", !mMapboxMap.getPolylines().contains(polyline));
+ }
+
+ @Test
+ public void testAddPolylines() {
+ List<PolylineOptions> polylineList = new ArrayList<>();
+ PolylineOptions polygonOptions1 = new PolylineOptions().color(Color.BLACK).add(new LatLng());
+ PolylineOptions polygonOptions2 = new PolylineOptions().color(Color.WHITE).add(new LatLng());
+ PolylineOptions polygonOptions3 = new PolylineOptions();
+ polylineList.add(polygonOptions1);
+ polylineList.add(polygonOptions2);
+ polylineList.add(polygonOptions3);
+ mMapboxMap.addPolylines(polylineList);
+ assertEquals("Polygons size should be 2", 2, mMapboxMap.getPolylines().size());
+ assertTrue(mMapboxMap.getPolylines().contains(polygonOptions1.getPolyline()));
+ assertTrue(mMapboxMap.getPolylines().contains(polygonOptions2.getPolyline()));
+ assertTrue("Polyline should be ignored", !mMapboxMap.getPolylines().contains(polygonOptions3.getPolyline()));
+ }
+
+ @Test
+ public void testRemoveMarker() {
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker = mMapboxMap.addMarker(markerOptions);
+ mMapboxMap.removeMarker(marker);
+ assertTrue("Markers should be empty", mMapboxMap.getMarkers().isEmpty());
+ }
+
+ @Test
+ public void testRemovePolygon() {
+ PolygonOptions polygonOptions = new PolygonOptions();
+ Polygon polygon = mMapboxMap.addPolygon(polygonOptions);
+ mMapboxMap.removePolygon(polygon);
+ assertTrue("Polygons should be empty", mMapboxMap.getPolylines().isEmpty());
+ }
+
+ @Test
+ public void testRemovePolyline() {
+ PolylineOptions polylineOptions = new PolylineOptions();
+ Polyline polyline = mMapboxMap.addPolyline(polylineOptions);
+ mMapboxMap.removePolyline(polyline);
+ assertTrue("Polylines should be empty", mMapboxMap.getPolylines().isEmpty());
+ }
+
+ @Test
+ public void testRemoveAnnotation() {
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker = mMapboxMap.addMarker(markerOptions);
+ mMapboxMap.removeAnnotation(marker);
+ assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty());
+ }
+
+ @Test
+ public void testRemoveAnnotationById() {
+ MarkerOptions markerOptions = new MarkerOptions();
+ mMapboxMap.addMarker(markerOptions);
+ // id will always be 0 in unit tests
+ mMapboxMap.removeAnnotation(0);
+ assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty());
+ }
+
+ @Test
+ public void testRemoveAnnotations() {
+ List<MarkerOptions> markerList = new ArrayList<>();
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a");
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ markerList.add(markerOptions1);
+ markerList.add(markerOptions2);
+ mMapboxMap.addMarkers(markerList);
+ mMapboxMap.removeAnnotations();
+ assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty());
+ }
+
+ @Test
+ public void testRemoveAnnotationsByList() {
+ List<MarkerOptions> markerList = new ArrayList<>();
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a");
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ markerList.add(markerOptions1);
+ markerList.add(markerOptions2);
+ List<Marker> markers = mMapboxMap.addMarkers(markerList);
+ Marker marker = mMapboxMap.addMarker(new MarkerOptions().title("c"));
+ mMapboxMap.removeAnnotations(markers);
+ assertTrue("Annotations should not be empty", mMapboxMap.getAnnotations().size() == 1);
+ assertTrue("Marker should be contained", mMapboxMap.getAnnotations().contains(marker));
+ }
+
+ @Test
+ public void testGetAnnotationById() {
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker initialMarker = mMapboxMap.addMarker(markerOptions);
+ Marker retrievedMarker = (Marker) mMapboxMap.getAnnotation(0);
+ assertEquals("Markers should match", initialMarker, retrievedMarker);
+ }
+
+ @Test
+ public void testGetAnnotations() {
+ assertNotNull("Annotations should be non null", mMapboxMap.getAnnotations());
+ }
+
+ @Test
+ public void testGetMarkers() {
+ assertNotNull("Markers should be non null", mMapboxMap.getMarkers());
+ }
+
+ @Test
+ public void testGetPolygons() {
+ assertNotNull("Polygons should be non null", mMapboxMap.getPolygons());
+ }
+
+ @Test
+ public void testGetPolylines() {
+ assertNotNull("Polylines should be non null", mMapboxMap.getPolylines());
+ }
+
+ @Test
+ public void testGetSelectedMarkers() {
+ assertNotNull("Selected markers should be non null", mMapboxMap.getSelectedMarkers());
+ }
+
+ @Test
+ public void testSelectMarker() {
+ mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker = mMapboxMap.addMarker(markerOptions);
+ when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true);
+ mMapboxMap.selectMarker(marker);
+ assertTrue("Marker should be contained", mMapboxMap.getSelectedMarkers().contains(marker));
+ }
+
+ @Test
+ public void testDeselectMarker() {
+ mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker = mMapboxMap.addMarker(markerOptions);
+ when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true);
+ mMapboxMap.selectMarker(marker);
+ mMapboxMap.deselectMarker(marker);
+ assertTrue("Selected markers should be empty", mMapboxMap.getSelectedMarkers().isEmpty());
+ }
+
+ @Test
+ public void testDeselectMarkers() {
+ mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
+ MarkerOptions markerOptions = new MarkerOptions();
+ Marker marker1 = mMapboxMap.addMarker(markerOptions);
+ Marker marker2 = mMapboxMap.addMarker(markerOptions);
+ when(mOnMarkerClickListener.onMarkerClick(marker1)).thenReturn(true);
+ when(mOnMarkerClickListener.onMarkerClick(marker2)).thenReturn(true);
+ mMapboxMap.selectMarker(marker1);
+ mMapboxMap.selectMarker(marker2);
+ mMapboxMap.deselectMarkers();
+ assertTrue("Selected markers should be empty", mMapboxMap.getSelectedMarkers().isEmpty());
+ }
+
+
+ //
// OnMarkerClick interface
//
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MarkerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MarkerTest.java
deleted file mode 100644
index efe94e5396..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MarkerTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.mapbox.mapboxsdk.maps;
-
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-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();
- assertNotNull("marker should not be null", markerOptions.getMarker());
- }
-
- @Test
- public void testPosition() {
- Marker marker = new MarkerOptions().position(new LatLng(10, 12)).getMarker();
- assertEquals(marker.getPosition(), new LatLng(10, 12));
- }
-
- @Test
- public void testTitle() {
- Marker marker = new MarkerOptions().title("Mapbox").getMarker();
- assertEquals(marker.getTitle(), "Mapbox");
- }
-
- @Test
- public void testSnippet() {
- Marker marker = new MarkerOptions().snippet("Mapbox").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.getTitle(), "title");
- assertEquals(marker.getSnippet(), "snippet");
- assertEquals(marker.getPosition(), new LatLng(10, 12));
- }
-
- @Test
- public void testIcon() {
- // find a way to test Icon
- }
-
- @Test
- public void testHashCode() {
- Marker marker = new MarkerOptions().position(new LatLng(10, 12)).getMarker();
- assertEquals("hash code should match", marker.hashCode(), -1946419200);
- }
-
- @Test
- public void testEquality() {
- 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 testToString() {
- Marker marker = new MarkerOptions().position(new LatLng(0, 0)).getMarker();
- assertEquals(marker.toString(), "Marker [position[" + "LatLng [longitude=0.0, latitude=0.0, altitude=0.0]" + "]]");
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
new file mode 100644
index 0000000000..266bbadd95
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
@@ -0,0 +1,53 @@
+package com.mapbox.mapboxsdk.maps;
+
+import com.mapbox.mapboxsdk.constants.MyBearingTracking;
+import com.mapbox.mapboxsdk.constants.MyLocationTracking;
+
+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.mockito.Mockito.mock;
+
+public class TrackingSettingsTest {
+
+ @InjectMocks
+ MapView mMapView = mock(MapView.class);
+
+ @Test
+ public void testSanity() {
+ TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView));
+ assertNotNull("trackingsettings should not be null", trackingSettings);
+ }
+
+ @Test
+ public void testMyLocationTrackingMode() {
+ TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView));
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ assertEquals("MyLocationTrackingMode should match", MyLocationTracking.TRACKING_FOLLOW, trackingSettings.getMyLocationTrackingMode());
+ }
+
+ @Test
+ public void testMyBearingTrackingMode() {
+ TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView));
+ trackingSettings.setMyBearingTrackingMode(MyBearingTracking.COMPASS);
+ assertEquals("MyLocationTrackingMode should match", MyBearingTracking.COMPASS, trackingSettings.getMyBearingTrackingMode());
+ }
+
+ @Test
+ public void testDismissTrackingModesOnGesture() {
+ TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView));
+ trackingSettings.setDismissTrackingOnGesture(false);
+ assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isDismissTrackingOnGesture());
+ }
+
+ @Test
+ public void testValidateGesturesForTrackingModes(){
+ TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView));
+ trackingSettings.setDismissTrackingOnGesture(false);
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isDismissTrackingOnGesture());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
index 9c867bf776..cb9031c66e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
@@ -22,6 +22,30 @@ public class UiSettingsTest {
}
@Test
+ public void testMinZoom() {
+ double zoom = 10;
+ UiSettings uiSettings = new UiSettings(mMapView);
+ uiSettings.setMinZoom(zoom);
+ assertEquals("MinZoom should match", zoom, uiSettings.getMinZoom(), 0);
+ }
+
+ @Test
+ public void testMaxZoom() {
+ double zoom = 10;
+ UiSettings uiSettings = new UiSettings(mMapView);
+ uiSettings.setMaxZoom(zoom);
+ assertEquals("MaxZoom should match", zoom, uiSettings.getMaxZoom(), 0);
+ }
+
+ @Test
+ public void testInitialZoomLevels() {
+ //we are mocking MapView we expect a value of 0 to be returned
+ UiSettings uiSettings = new UiSettings(mMapView);
+ assertEquals("MaxZoom should match", 0, uiSettings.getMaxZoom(), 0);
+ assertEquals("MinZoom should match", 0, uiSettings.getMinZoom(), 0);
+ }
+
+ @Test
public void testCompassEnabled() {
UiSettings uiSettings = new UiSettings(mMapView);
uiSettings.setCompassEnabled(true);
@@ -204,4 +228,10 @@ public class UiSettingsTest {
assertEquals("Scroll gesture should be disabled", false, uiSettings.isScrollGesturesEnabled());
}
+ @Test
+ public void testInvalidate() {
+ UiSettings uiSettings = new UiSettings(mMapView);
+ uiSettings.invalidate();
+ }
+
} \ No newline at end of file
diff --git a/platform/android/mapboxgl-app.gypi b/platform/android/mapboxgl-app.gypi
index 0945fc1be2..ecc5ceff04 100644
--- a/platform/android/mapboxgl-app.gypi
+++ b/platform/android/mapboxgl-app.gypi
@@ -26,6 +26,7 @@
'cflags_cc': [
'<@(boost_cflags)',
+ '<@(variant_cflags)',
],
'libraries': [
'<@(libpng_static_libs)',
@@ -113,6 +114,9 @@
{
'files': [
'../../common/ca-bundle.crt',
+ '../../platform/default/resources/api_mapbox_com-digicert.der',
+ '../../platform/default/resources/api_mapbox_com-geotrust.der',
+ '../../platform/default/resources/star_tilestream_net.der',
],
'destination': '<(pwd)/../platform/android/MapboxGLAndroidSDK/src/main/assets'
},
diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp
index 7eb2007778..d2aab30a52 100644
--- a/platform/android/src/asset_file_source.cpp
+++ b/platform/android/src/asset_file_source.cpp
@@ -2,6 +2,7 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/thread.hpp>
+#include <mbgl/util/url.hpp>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -59,7 +60,8 @@ public:
struct zip_stat stat;
::zip_stat_init(&stat);
- std::string path = std::string("assets/") + url.substr(8);
+ std::string path = std::string("assets/") + mbgl::util::percentDecode(url.substr(8));
+
int ret = ::zip_stat(archive.archive, path.c_str(), 0, &stat);
if (ret < 0 || !(stat.valid & ZIP_STAT_SIZE)) {
reportError(Response::Error::Reason::NotFound, "Could not stat file in zip archive", callback);
diff --git a/platform/android/src/http_request_android.cpp b/platform/android/src/http_request_android.cpp
index 390334627a..2e2fd6408d 100644
--- a/platform/android/src/http_request_android.cpp
+++ b/platform/android/src/http_request_android.cpp
@@ -199,17 +199,18 @@ void HTTPAndroidRequest::onResponse(JNIEnv* env, int code, jstring /* message */
response->expires = util::parseTimePoint(mbgl::android::std_string_from_jstring(env, expires).c_str());
}
- if (body != nullptr) {
- jbyte* bodyData = env->GetByteArrayElements(body, nullptr);
- response->data = std::make_shared<std::string>(reinterpret_cast<char*>(bodyData), env->GetArrayLength(body));
- env->ReleaseByteArrayElements(body, bodyData, JNI_ABORT);
- }
-
if (code == 200) {
- // Nothing to do; this is what we want
+ if (body != nullptr) {
+ jbyte* bodyData = env->GetByteArrayElements(body, nullptr);
+ response->data = std::make_shared<std::string>(reinterpret_cast<char*>(bodyData), env->GetArrayLength(body));
+ env->ReleaseByteArrayElements(body, bodyData, JNI_ABORT);
+ } else {
+ response->data = std::make_shared<std::string>();
+ }
+ } else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) {
+ response->noContent = true;
} else if (code == 304) {
response->notModified = true;
- response->data.reset();
} else if (code == 404) {
response->error = std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404");
} else if (code >= 500 && code < 600) {
@@ -248,6 +249,10 @@ std::unique_ptr<HTTPContextBase> HTTPContextBase::createContext() {
return std::make_unique<HTTPAndroidContext>();
}
+uint32_t HTTPContextBase::maximumConcurrentRequests() {
+ return 20;
+}
+
void JNICALL nativeOnFailure(JNIEnv* env, jobject, jlong nativePtr, jint type, jstring message) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeOnFailure");
assert(nativePtr != 0);
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 00148562bb..db6bc73726 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -60,6 +60,7 @@ jfieldID iconIdId = nullptr;
jclass markerClass = nullptr;
jfieldID markerPositionId = nullptr;
jfieldID markerIconId = nullptr;
+jfieldID markerIdId = nullptr;
jclass polylineClass = nullptr;
jfieldID polylineAlphaId = nullptr;
@@ -834,6 +835,47 @@ jlong JNICALL nativeAddMarker(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
return nativeMapView->getMap().addPointAnnotation(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), id));
}
+void JNICALL nativeUpdateMarker(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject marker) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdateMarker");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+
+ jlong markerId = env->GetLongField(marker, markerIdId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+
+ if (markerId == -1) {
+ return;
+ }
+
+ jobject position = env->GetObjectField(marker, markerPositionId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+
+ jobject icon = env->GetObjectField(marker, markerIconId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+
+ jstring jid = reinterpret_cast<jstring>(env->GetObjectField(icon, iconIdId));
+ std::string iconId = std_string_from_jstring(env, jid);
+
+ jdouble latitude = env->GetDoubleField(position, latLngLatitudeId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+
+ jdouble longitude = env->GetDoubleField(position, latLngLongitudeId);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+
+ // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
+ nativeMapView->getMap().updatePointAnnotation(markerId, mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), iconId));
+}
+
jlongArray JNICALL nativeAddMarkers(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject jlist) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddMarkers");
assert(nativeMapViewPtr != 0);
@@ -1685,6 +1727,12 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_ERR;
}
+ markerIdId = env->GetFieldID(markerClass, "id", "J");
+ if (markerIdId == nullptr) {
+ env->ExceptionDescribe();
+ return JNI_ERR;
+ }
+
polylineClass = env->FindClass("com/mapbox/mapboxsdk/annotations/Polyline");
if (polylineClass == nullptr) {
env->ExceptionDescribe();
@@ -2044,6 +2092,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
reinterpret_cast<void *>(&nativeAddPolygon)},
{"nativeAddPolygons", "(JLjava/util/List;)[J",
reinterpret_cast<void *>(&nativeAddPolygons)},
+ {"nativeUpdateMarker", "(JLcom/mapbox/mapboxsdk/annotations/Marker;)V",
+ reinterpret_cast<void *>(&nativeUpdateMarker)} ,
{"nativeRemoveAnnotation", "(JJ)V", reinterpret_cast<void *>(&nativeRemoveAnnotation)},
{"nativeRemoveAnnotations", "(J[J)V", reinterpret_cast<void *>(&nativeRemoveAnnotations)},
{"nativeGetAnnotationsInBounds", "(JLcom/mapbox/mapboxsdk/geometry/LatLngBounds;)[J",
@@ -2304,6 +2354,7 @@ extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
markerClass = nullptr;
markerPositionId = nullptr;
markerIconId = nullptr;
+ markerIdId = nullptr;
env->DeleteGlobalRef(polylineClass);
polylineClass = nullptr;
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 8c7115a1e4..d32f3c81cb 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -15,7 +15,7 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/platform/event.hpp>
#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/constants.hpp>
namespace mbgl {
diff --git a/include/mbgl/darwin/MGLAnnotation.h b/platform/darwin/include/MGLAnnotation.h
index e4726f9503..e4726f9503 100644
--- a/include/mbgl/darwin/MGLAnnotation.h
+++ b/platform/darwin/include/MGLAnnotation.h
diff --git a/include/mbgl/darwin/MGLGeometry.h b/platform/darwin/include/MGLGeometry.h
index 8d185805db..8cb1da10fc 100644
--- a/include/mbgl/darwin/MGLGeometry.h
+++ b/platform/darwin/include/MGLGeometry.h
@@ -72,8 +72,7 @@ NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsOffset(MGLCoordinateBounds boun
}
/** Returns `YES` if the coordinate bounds covers no area.
-
- Note that a bounds may be empty but have a non-zero coordinate span (e.g., when its northeast point lies due north of its southwest point). */
+ Note that a bounds may be empty but have a non-zero coordinate span (e.g., when its northeast point lies due north of its southwest point). */
NS_INLINE BOOL MGLCoordinateBoundsIsEmpty(MGLCoordinateBounds bounds) {
MGLCoordinateSpan span = MGLCoordinateBoundsGetCoordinateSpan(bounds);
return span.latitudeDelta == 0 || span.longitudeDelta == 0;
diff --git a/include/mbgl/darwin/MGLMapCamera.h b/platform/darwin/include/MGLMapCamera.h
index 3cb902ba52..3cb902ba52 100644
--- a/include/mbgl/darwin/MGLMapCamera.h
+++ b/platform/darwin/include/MGLMapCamera.h
diff --git a/include/mbgl/darwin/MGLMultiPoint.h b/platform/darwin/include/MGLMultiPoint.h
index ad9db1e681..ad9db1e681 100644
--- a/include/mbgl/darwin/MGLMultiPoint.h
+++ b/platform/darwin/include/MGLMultiPoint.h
diff --git a/include/mbgl/darwin/MGLOverlay.h b/platform/darwin/include/MGLOverlay.h
index aa80fe3900..aa80fe3900 100644
--- a/include/mbgl/darwin/MGLOverlay.h
+++ b/platform/darwin/include/MGLOverlay.h
diff --git a/include/mbgl/darwin/MGLPointAnnotation.h b/platform/darwin/include/MGLPointAnnotation.h
index d186cbff18..d186cbff18 100644
--- a/include/mbgl/darwin/MGLPointAnnotation.h
+++ b/platform/darwin/include/MGLPointAnnotation.h
diff --git a/include/mbgl/darwin/MGLPolygon.h b/platform/darwin/include/MGLPolygon.h
index c5480264fb..c5480264fb 100644
--- a/include/mbgl/darwin/MGLPolygon.h
+++ b/platform/darwin/include/MGLPolygon.h
diff --git a/include/mbgl/darwin/MGLPolyline.h b/platform/darwin/include/MGLPolyline.h
index c28299c7e0..c28299c7e0 100644
--- a/include/mbgl/darwin/MGLPolyline.h
+++ b/platform/darwin/include/MGLPolyline.h
diff --git a/include/mbgl/darwin/MGLShape.h b/platform/darwin/include/MGLShape.h
index c1b84816f2..c1b84816f2 100644
--- a/include/mbgl/darwin/MGLShape.h
+++ b/platform/darwin/include/MGLShape.h
diff --git a/include/mbgl/darwin/MGLStyle.h b/platform/darwin/include/MGLStyle.h
index e5b2de877c..e5b2de877c 100644
--- a/include/mbgl/darwin/MGLStyle.h
+++ b/platform/darwin/include/MGLStyle.h
diff --git a/include/mbgl/darwin/MGLTypes.h b/platform/darwin/include/MGLTypes.h
index c107055dbb..c107055dbb 100644
--- a/include/mbgl/darwin/MGLTypes.h
+++ b/platform/darwin/include/MGLTypes.h
diff --git a/platform/darwin/MGLGeometry.mm b/platform/darwin/src/MGLGeometry.mm
index 70f00afd2f..70f00afd2f 100644
--- a/platform/darwin/MGLGeometry.mm
+++ b/platform/darwin/src/MGLGeometry.mm
diff --git a/platform/darwin/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 72123827df..72123827df 100644
--- a/platform/darwin/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
diff --git a/platform/darwin/MGLMapCamera.mm b/platform/darwin/src/MGLMapCamera.mm
index 93f3bd45e0..93f3bd45e0 100644
--- a/platform/darwin/MGLMapCamera.mm
+++ b/platform/darwin/src/MGLMapCamera.mm
diff --git a/platform/darwin/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 3cd0f0c117..3cd0f0c117 100644
--- a/platform/darwin/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
diff --git a/platform/darwin/MGLMultiPoint_Private.h b/platform/darwin/src/MGLMultiPoint_Private.h
index c1f1fa1584..c1f1fa1584 100644
--- a/platform/darwin/MGLMultiPoint_Private.h
+++ b/platform/darwin/src/MGLMultiPoint_Private.h
diff --git a/platform/darwin/MGLPointAnnotation.m b/platform/darwin/src/MGLPointAnnotation.m
index 13fbba1083..13fbba1083 100644
--- a/platform/darwin/MGLPointAnnotation.m
+++ b/platform/darwin/src/MGLPointAnnotation.m
diff --git a/platform/darwin/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 5019385cb2..5019385cb2 100644
--- a/platform/darwin/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
diff --git a/platform/darwin/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index f560a571bc..f560a571bc 100644
--- a/platform/darwin/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
diff --git a/platform/darwin/MGLShape.m b/platform/darwin/src/MGLShape.m
index e3d92c38c8..e3d92c38c8 100644
--- a/platform/darwin/MGLShape.m
+++ b/platform/darwin/src/MGLShape.m
diff --git a/platform/darwin/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 15a25db9e3..15a25db9e3 100644
--- a/platform/darwin/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
diff --git a/platform/darwin/MGLTypes.m b/platform/darwin/src/MGLTypes.m
index 01e9a1467c..01e9a1467c 100644
--- a/platform/darwin/MGLTypes.m
+++ b/platform/darwin/src/MGLTypes.m
diff --git a/platform/darwin/NSException+MGLAdditions.h b/platform/darwin/src/NSException+MGLAdditions.h
index f75b54c15c..f75b54c15c 100644
--- a/platform/darwin/NSException+MGLAdditions.h
+++ b/platform/darwin/src/NSException+MGLAdditions.h
diff --git a/platform/darwin/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 6064f8b40f..6064f8b40f 100644
--- a/platform/darwin/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
diff --git a/platform/darwin/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index b94a5f0198..b94a5f0198 100644
--- a/platform/darwin/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
diff --git a/platform/darwin/application_root.mm b/platform/darwin/src/application_root.mm
index d4702c7ec5..d4702c7ec5 100644
--- a/platform/darwin/application_root.mm
+++ b/platform/darwin/src/application_root.mm
diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/src/http_request_nsurl.mm
index fa705638b4..e58441e4d2 100644
--- a/platform/darwin/http_request_nsurl.mm
+++ b/platform/darwin/src/http_request_nsurl.mm
@@ -10,6 +10,7 @@
#include <map>
#include <cassert>
+#include <mutex>
namespace mbgl {
@@ -17,17 +18,17 @@ class HTTPNSURLContext;
class HTTPNSURLRequest : public HTTPRequestBase {
public:
- HTTPNSURLRequest(HTTPNSURLContext*, const Resource&, Callback);
+ HTTPNSURLRequest(HTTPNSURLContext*, Resource, Callback);
~HTTPNSURLRequest();
void cancel() final;
private:
- void handleResult(NSData *data, NSURLResponse *res, NSError *error);
+ static std::unique_ptr<Response> handleResult(NSData *data, NSURLResponse *res, NSError *error, Resource);
void handleResponse();
HTTPNSURLContext *context = nullptr;
- bool cancelled = false;
+ std::shared_ptr<std::pair<bool, std::mutex>> cancelled;
NSURLSessionDataTask *task = nullptr;
std::unique_ptr<Response> response;
util::AsyncTask async;
@@ -81,15 +82,18 @@ HTTPRequestBase* HTTPNSURLContext::createRequest(const Resource& resource, HTTPR
// -------------------------------------------------------------------------------------------------
HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_,
- const Resource& resource_,
+ Resource resource_,
Callback callback_)
: HTTPRequestBase(resource_, callback_),
context(context_),
async([this] { handleResponse(); }) {
- // Hold the main loop alive until the request returns. This
- // is needed because completion handler runs in another
- // thread and will notify this thread using AsyncTask.
- util::RunLoop::Get()->ref();
+
+ // Ensure that a stack-allocated std::shared_ptr gets copied into the Objective-C
+ // block used as the completion handler below. Objective-C will implicitly copy captured
+ // stack variables. For member variable access it will implicitly copy the this pointer.
+ // That wouldn't work here because we need the block to have its own shared_ptr.
+ auto cancelled_ = cancelled = std::make_shared<std::pair<bool, std::mutex>>();
+ cancelled->first = false;
@autoreleasepool {
NSURL* url = [NSURL URLWithString:@(resource.url.c_str())];
@@ -114,7 +118,12 @@ HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_,
task = [context->session
dataTaskWithRequest:req
completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) {
- handleResult(data, res, error);
+ std::unique_ptr<Response> response_ = HTTPNSURLRequest::handleResult(data, res, error, resource_);
+ std::lock_guard<std::mutex> lock(cancelled_->second);
+ if (!cancelled_->first) {
+ response = std::move(response_);
+ async.send();
+ }
}];
[task retain];
[task resume];
@@ -122,7 +131,6 @@ HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_,
}
HTTPNSURLRequest::~HTTPNSURLRequest() {
- util::RunLoop::Get()->unref();
assert(!task);
}
@@ -132,28 +140,34 @@ void HTTPNSURLRequest::handleResponse() {
task = nullptr;
}
- if (!cancelled) {
- assert(response);
- notify(*response);
- }
+ assert(response);
+ notify(*response);
delete this;
}
void HTTPNSURLRequest::cancel() {
- cancelled = true;
-
if (task) {
[task cancel];
[task release];
task = nullptr;
- } else {
- delete this;
}
+
+ {
+ std::lock_guard<std::mutex> lock(cancelled->second);
+ cancelled->first = true;
+ }
+
+ // The lock is in place to enforce that `async` is not accessed if the request has been
+ // cancelled. Therefore it's not necessary to hold the lock beyond setting cancelled to
+ // true, and in fact it's unsafe to so: if this is the last remaining shared reference,
+ // `delete this` will destroy the mutex. If the lock was held, it would then be orphaned.
+
+ delete this;
}
-void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
- response = std::make_unique<Response>();
+std::unique_ptr<Response> HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error, Resource resource) {
+ std::unique_ptr<Response> response = std::make_unique<Response>();
using Error = Response::Error;
if (error) {
@@ -194,8 +208,6 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e
} else if ([res isKindOfClass:[NSHTTPURLResponse class]]) {
const long responseCode = [(NSHTTPURLResponse *)res statusCode];
- response->data = std::make_shared<std::string>((const char *)[data bytes], [data length]);
-
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
NSString *cache_control = [headers objectForKey:@"Cache-Control"];
if (cache_control) {
@@ -218,10 +230,11 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e
}
if (responseCode == 200) {
- // Nothing to do; this is what we want.
+ response->data = std::make_shared<std::string>((const char *)[data bytes], [data length]);
+ } else if (responseCode == 204 || (responseCode == 404 && resource.kind == Resource::Kind::Tile)) {
+ response->noContent = true;
} else if (responseCode == 304) {
response->notModified = true;
- response->data.reset();
} else if (responseCode == 404) {
response->error =
std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404");
@@ -240,11 +253,15 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e
"Response class is not NSHTTPURLResponse");
}
- async.send();
+ return response;
}
std::unique_ptr<HTTPContextBase> HTTPContextBase::createContext() {
return std::make_unique<HTTPNSURLContext>();
}
+uint32_t HTTPContextBase::maximumConcurrentRequests() {
+ return 20;
+}
+
}
diff --git a/platform/darwin/image.mm b/platform/darwin/src/image.mm
index 854b9157f8..854b9157f8 100644
--- a/platform/darwin/image.mm
+++ b/platform/darwin/src/image.mm
diff --git a/platform/darwin/log_nslog.mm b/platform/darwin/src/log_nslog.mm
index a2e31968ab..a2e31968ab 100644
--- a/platform/darwin/log_nslog.mm
+++ b/platform/darwin/src/log_nslog.mm
diff --git a/platform/darwin/nsthread.mm b/platform/darwin/src/nsthread.mm
index 9ac1d2caa0..9ac1d2caa0 100644
--- a/platform/darwin/nsthread.mm
+++ b/platform/darwin/src/nsthread.mm
diff --git a/platform/darwin/reachability.m b/platform/darwin/src/reachability.m
index 8abcf5ae6d..8abcf5ae6d 100644
--- a/platform/darwin/reachability.m
+++ b/platform/darwin/src/reachability.m
diff --git a/platform/darwin/settings_nsuserdefaults.mm b/platform/darwin/src/settings_nsuserdefaults.mm
index 548ee9b220..548ee9b220 100644
--- a/platform/darwin/settings_nsuserdefaults.mm
+++ b/platform/darwin/src/settings_nsuserdefaults.mm
diff --git a/platform/darwin/string_nsstring.mm b/platform/darwin/src/string_nsstring.mm
index 9bf199afc0..9bf199afc0 100644
--- a/platform/darwin/string_nsstring.mm
+++ b/platform/darwin/src/string_nsstring.mm
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index a1f8bc2c48..bdf02ee69a 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -1,10 +1,15 @@
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/asset_file_source.hpp>
#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/offline_download.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/url.hpp>
+#include <mbgl/util/thread.hpp>
+#include <mbgl/util/work_request.hpp>
+
+#include <cassert>
namespace {
@@ -20,45 +25,194 @@ namespace mbgl {
class DefaultFileSource::Impl {
public:
- Impl(const std::string& cachePath, const std::string& assetRoot)
- : assetFileSource(assetRoot),
- cache(SQLiteCache::getShared(cachePath)),
- onlineFileSource(cache.get()) {
+ class Task {
+ public:
+ Task(Resource resource, FileSource::Callback callback, DefaultFileSource::Impl* impl) {
+ auto offlineResponse = impl->offlineDatabase.get(resource);
+
+ Resource revalidation = resource;
+
+ if (offlineResponse) {
+ revalidation.priorModified = offlineResponse->modified;
+ revalidation.priorExpires = offlineResponse->expires;
+ revalidation.priorEtag = offlineResponse->etag;
+ callback(*offlineResponse);
+ }
+
+ if (!impl->offline) {
+ onlineRequest = impl->onlineFileSource.request(revalidation, [=] (Response onlineResponse) {
+ impl->offlineDatabase.put(revalidation, onlineResponse);
+ callback(onlineResponse);
+ });
+ }
+ }
+
+ std::unique_ptr<FileRequest> onlineRequest;
+ };
+
+ Impl(const std::string& cachePath, uint64_t maximumCacheSize)
+ : offlineDatabase(cachePath, maximumCacheSize) {
+ }
+
+ void setAccessToken(const std::string& accessToken) {
+ onlineFileSource.setAccessToken(accessToken);
+ }
+
+ std::string getAccessToken() const {
+ return onlineFileSource.getAccessToken();
+ }
+
+ void listRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
+ try {
+ callback({}, offlineDatabase.listRegions());
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void createRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) {
+ try {
+ callback({}, offlineDatabase.createRegion(definition, metadata));
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void getRegionStatus(int64_t regionID, std::function<void (std::exception_ptr, optional<OfflineRegionStatus>)> callback) {
+ try {
+ callback({}, getDownload(regionID).getStatus());
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void deleteRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) {
+ try {
+ offlineDatabase.deleteRegion(std::move(region));
+ callback({});
+ } catch (...) {
+ callback(std::current_exception());
+ }
+ }
+
+ void setRegionObserver(int64_t regionID, std::unique_ptr<OfflineRegionObserver> observer) {
+ getDownload(regionID).setObserver(std::move(observer));
+ }
+
+ void setRegionDownloadState(int64_t regionID, OfflineRegionDownloadState state) {
+ getDownload(regionID).setState(state);
+ }
+
+ void request(FileRequest* req, Resource resource, Callback callback) {
+ tasks[req] = std::make_unique<Task>(resource, callback, this);
+ }
+
+ void cancel(FileRequest* req) {
+ tasks.erase(req);
+ }
+
+ void put(const Resource& resource, const Response& response) {
+ offlineDatabase.put(resource, response);
+ }
+
+ void goOffline() {
+ offline = true;
}
- AssetFileSource assetFileSource;
- std::shared_ptr<SQLiteCache> cache;
+private:
+ OfflineDownload& getDownload(int64_t regionID) {
+ auto it = downloads.find(regionID);
+ if (it != downloads.end()) {
+ return *it->second;
+ }
+ return *downloads.emplace(regionID,
+ std::make_unique<OfflineDownload>(regionID, offlineDatabase.getRegionDefinition(regionID), offlineDatabase, onlineFileSource)).first->second;
+ }
+
+ OfflineDatabase offlineDatabase;
OnlineFileSource onlineFileSource;
+ std::unordered_map<FileRequest*, std::unique_ptr<Task>> tasks;
+ std::unordered_map<int64_t, std::unique_ptr<OfflineDownload>> downloads;
+ bool offline = false;
};
-DefaultFileSource::DefaultFileSource(const std::string& cachePath, const std::string& assetRoot)
- : impl(std::make_unique<DefaultFileSource::Impl>(cachePath, assetRoot)) {
+DefaultFileSource::DefaultFileSource(const std::string& cachePath,
+ const std::string& assetRoot,
+ uint64_t maximumCacheSize)
+ : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low},
+ cachePath, maximumCacheSize)),
+ assetFileSource(std::make_unique<AssetFileSource>(assetRoot)) {
}
DefaultFileSource::~DefaultFileSource() = default;
void DefaultFileSource::setAccessToken(const std::string& accessToken) {
- impl->onlineFileSource.setAccessToken(accessToken);
+ thread->invokeSync(&Impl::setAccessToken, accessToken);
}
std::string DefaultFileSource::getAccessToken() const {
- return impl->onlineFileSource.getAccessToken();
+ return thread->invokeSync<std::string>(&Impl::getAccessToken);
}
-void DefaultFileSource::setMaximumCacheSize(uint64_t size) {
- impl->cache->setMaximumCacheSize(size);
-}
+std::unique_ptr<FileRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
+ class DefaultFileRequest : public FileRequest {
+ public:
+ DefaultFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<DefaultFileSource::Impl>& thread_)
+ : thread(thread_),
+ workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::request, callback_, this, resource_)) {
+ }
-void DefaultFileSource::setMaximumCacheEntrySize(uint64_t size) {
- impl->cache->setMaximumCacheEntrySize(size);
-}
+ ~DefaultFileRequest() {
+ thread.invoke(&DefaultFileSource::Impl::cancel, this);
+ }
+
+ util::Thread<DefaultFileSource::Impl>& thread;
+ std::unique_ptr<WorkRequest> workRequest;
+ };
-std::unique_ptr<FileRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
if (isAssetURL(resource.url)) {
- return impl->assetFileSource.request(resource, callback);
+ return assetFileSource->request(resource, callback);
} else {
- return impl->onlineFileSource.request(resource, callback);
+ return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
}
}
+void DefaultFileSource::listOfflineRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
+ thread->invoke(&Impl::listRegions, callback);
+}
+
+void DefaultFileSource::createOfflineRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) {
+ thread->invoke(&Impl::createRegion, definition, metadata, callback);
+}
+
+void DefaultFileSource::deleteOfflineRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) {
+ thread->invoke(&Impl::deleteRegion, std::move(region), callback);
+}
+
+void DefaultFileSource::setOfflineRegionObserver(OfflineRegion& region, std::unique_ptr<OfflineRegionObserver> observer) {
+ thread->invoke(&Impl::setRegionObserver, region.getID(), std::move(observer));
+}
+
+void DefaultFileSource::setOfflineRegionDownloadState(OfflineRegion& region, OfflineRegionDownloadState state) {
+ thread->invoke(&Impl::setRegionDownloadState, region.getID(), state);
+}
+
+void DefaultFileSource::getOfflineRegionStatus(OfflineRegion& region, std::function<void (std::exception_ptr, optional<OfflineRegionStatus>)> callback) const {
+ thread->invoke(&Impl::getRegionStatus, region.getID(), callback);
+}
+
+// For testing only:
+
+void DefaultFileSource::put(const Resource& resource, const Response& response) {
+ thread->invokeSync(&Impl::put, resource, response);
+}
+
+void DefaultFileSource::goOffline() {
+ thread->invokeSync(&Impl::goOffline);
+}
+
} // namespace mbgl
diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp
index 83e2c65585..a4e8d7059f 100644
--- a/platform/default/glfw_view.cpp
+++ b/platform/default/glfw_view.cpp
@@ -1,10 +1,12 @@
+#include <mbgl/platform/default/glfw_view.hpp>
#include <mbgl/annotation/point_annotation.hpp>
#include <mbgl/annotation/shape_annotation.hpp>
#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/platform/default/glfw_view.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_values.hpp>
+#include <mbgl/gl/gl_helper.hpp>
#include <mbgl/platform/log.hpp>
-#include <mbgl/util/gl_helper.hpp>
+#include <mbgl/platform/platform.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/chrono.hpp>
@@ -135,6 +137,9 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
if (!mods)
view->map->resetPosition();
break;
+ case GLFW_KEY_C:
+ view->toggleClipMasks();
+ break;
case GLFW_KEY_S:
if (view->changeStyleCallback)
view->changeStyleCallback();
@@ -231,6 +236,11 @@ void GLFWView::nextOrientation() {
}
}
+void GLFWView::toggleClipMasks() {
+ showClipMasks = !showClipMasks;
+ map->update(mbgl::Update::Repaint);
+}
+
void GLFWView::addRandomCustomPointAnnotations(int count) {
std::vector<mbgl::PointAnnotation> points;
@@ -438,9 +448,52 @@ void GLFWView::beforeRender() {
}
void GLFWView::afterRender() {
+ if (showClipMasks) {
+ renderClipMasks();
+ }
+
glfwSwapBuffers(window);
}
+void GLFWView::renderClipMasks() {
+ // Read the stencil buffer
+ auto pixels = std::make_unique<uint8_t[]>(fbWidth * fbHeight);
+ glReadPixels(0, // GLint x
+ 0, // GLint y
+ fbWidth, // GLsizei width
+ fbHeight, // GLsizei height
+ GL_STENCIL_INDEX, // GLenum format
+ GL_UNSIGNED_BYTE, // GLenum type
+ pixels.get() // GLvoid * data
+ );
+
+ // Scale the Stencil buffer to cover the entire color space.
+ auto it = pixels.get();
+ auto end = it + fbWidth * fbHeight;
+ const auto factor = 255.0f / *std::max_element(it, end);
+ for (; it != end; ++it) {
+ *it *= factor;
+ }
+
+ using namespace mbgl::gl;
+ Preserve<PixelZoom> pixelZoom;
+ Preserve<RasterPos> rasterPos;
+ Preserve<StencilTest> stencilTest;
+ Preserve<DepthTest> depthTest;
+ Preserve<Program> program;
+ Preserve<ColorMask> colorMask;
+
+ MBGL_CHECK_ERROR(glPixelZoom(1.0f, 1.0f));
+ MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, -1.0f));
+ MBGL_CHECK_ERROR(glDisable(GL_STENCIL_TEST));
+ MBGL_CHECK_ERROR(glDisable(GL_DEPTH_TEST));
+ MBGL_CHECK_ERROR(glUseProgram(0));
+ MBGL_CHECK_ERROR(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
+ MBGL_CHECK_ERROR(glWindowPos2i(0, 0));
+
+ MBGL_CHECK_ERROR(glDrawPixels(fbWidth, fbHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
+}
+
void GLFWView::report(float duration) {
frames++;
frameTime += duration;
@@ -496,8 +549,8 @@ void showDebugImage(std::string name, const char *data, size_t width, size_t hei
float scale = static_cast<float>(fbWidth) / static_cast<float>(width);
{
- gl::PreservePixelZoom pixelZoom;
- gl::PreserveRasterPos rasterPos;
+ gl::Preserve<gl::PixelZoom> pixelZoom;
+ gl::Preserve<gl::RasterPos> rasterPos;
MBGL_CHECK_ERROR(glPixelZoom(scale, -scale));
MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
@@ -533,11 +586,11 @@ void showColorDebugImage(std::string name, const char *data, size_t logicalWidth
float yScale = static_cast<float>(fbHeight) / static_cast<float>(height);
{
- gl::PreserveClearColor clearColor;
- gl::PreserveBlend blend;
- gl::PreserveBlendFunc blendFunc;
- gl::PreservePixelZoom pixelZoom;
- gl::PreserveRasterPos rasterPos;
+ gl::Preserve<gl::ClearColor> clearColor;
+ gl::Preserve<gl::Blend> blend;
+ gl::Preserve<gl::BlendFunc> blendFunc;
+ gl::Preserve<gl::PixelZoom> pixelZoom;
+ gl::Preserve<gl::RasterPos> rasterPos;
MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1));
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp
index f7fb27afc5..58c574fee1 100644
--- a/platform/default/http_request_curl.cpp
+++ b/platform/default/http_request_curl.cpp
@@ -509,19 +509,16 @@ void HTTPCURLRequest::handleResult(CURLcode code) {
long responseCode = 0;
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode);
- // Move over any data we got. We're storing this in a separate object because the Response
- // object defines it as const.
- if (data) {
- response->data = std::move(data);
- } else {
- response->data = std::make_shared<std::string>();
- }
-
if (responseCode == 200) {
- // Nothing to do; this is what we want.
+ if (data) {
+ response->data = std::move(data);
+ } else {
+ response->data = std::make_shared<std::string>();
+ }
+ } else if (responseCode == 204 || (responseCode == 404 && resource.kind == Resource::Kind::Tile)) {
+ response->noContent = true;
} else if (responseCode == 304) {
response->notModified = true;
- response->data.reset();
} else if (responseCode == 404) {
response->error =
std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404");
@@ -545,4 +542,8 @@ std::unique_ptr<HTTPContextBase> HTTPContextBase::createContext() {
return std::make_unique<HTTPCURLContext>();
}
+uint32_t HTTPContextBase::maximumConcurrentRequests() {
+ return 20;
+}
+
} // namespace mbgl
diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp
index 73b0b9c1b2..b9518c71bc 100644
--- a/platform/default/jpeg_reader.cpp
+++ b/platform/default/jpeg_reader.cpp
@@ -153,7 +153,7 @@ PremultipliedImage decodeJPEG(const uint8_t* data, size_t size) {
jpeg_finish_decompress(&cinfo);
- return std::move(image);
+ return image;
}
}
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp
new file mode 100644
index 0000000000..931e079771
--- /dev/null
+++ b/platform/default/mbgl/storage/offline.cpp
@@ -0,0 +1,122 @@
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/source/source_info.hpp>
+
+#include <rapidjson/document.h>
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/writer.h>
+
+#include <cmath>
+
+namespace mbgl {
+
+OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
+ const std::string& styleURL_, const LatLngBounds& bounds_, double minZoom_, double maxZoom_, float pixelRatio_)
+ : styleURL(styleURL_),
+ bounds(bounds_),
+ minZoom(minZoom_),
+ maxZoom(maxZoom_),
+ pixelRatio(pixelRatio_) {
+ if (minZoom < 0 || maxZoom < 0 || maxZoom < minZoom || pixelRatio < 0 ||
+ !std::isfinite(minZoom) || std::isnan(maxZoom) || !std::isfinite(pixelRatio)) {
+ throw std::invalid_argument("Invalid offline region definition");
+ }
+}
+
+std::vector<TileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const SourceInfo& info) const {
+ double minZ = std::max<double>(coveringZoomLevel(minZoom, type, tileSize), info.minZoom);
+ double maxZ = std::min<double>(coveringZoomLevel(maxZoom, type, tileSize), info.maxZoom);
+
+ assert(minZ >= 0);
+ assert(maxZ >= 0);
+ assert(minZ < std::numeric_limits<uint8_t>::max());
+ assert(maxZ < std::numeric_limits<uint8_t>::max());
+
+ std::vector<TileID> result;
+
+ for (uint8_t z = minZ; z <= maxZ; z++) {
+ for (const auto& tile : mbgl::tileCover(bounds, z, z)) {
+ result.push_back(tile.normalized());
+ }
+ }
+
+ return result;
+}
+
+OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) {
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
+ doc.Parse<0>(region.c_str());
+
+ if (doc.HasParseError() ||
+ !doc.HasMember("style_url") || !doc["style_url"].IsString() ||
+ !doc.HasMember("bounds") || !doc["bounds"].IsArray() || doc["bounds"].Size() != 4 ||
+ !doc["bounds"][0].IsDouble() || !doc["bounds"][1].IsDouble() ||
+ !doc["bounds"][2].IsDouble() || !doc["bounds"][3].IsDouble() ||
+ !doc.HasMember("min_zoom") || !doc["min_zoom"].IsDouble() ||
+ (doc.HasMember("max_zoom") && !doc["max_zoom"].IsDouble()) ||
+ !doc.HasMember("pixel_ratio") || !doc["pixel_ratio"].IsDouble()) {
+ throw std::runtime_error("Malformed offline region definition");
+ }
+
+ std::string styleURL { doc["style_url"].GetString(), doc["style_url"].GetStringLength() };
+ LatLngBounds bounds = LatLngBounds::hull(
+ LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()),
+ LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble()));
+ double minZoom = doc["min_zoom"].GetDouble();
+ double maxZoom = doc.HasMember("max_zoom") ? doc["max_zoom"].GetDouble() : INFINITY;
+ float pixelRatio = doc["pixel_ratio"].GetDouble();
+
+ return { styleURL, bounds, minZoom, maxZoom, pixelRatio };
+}
+
+std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) {
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
+ doc.SetObject();
+
+ doc.AddMember("style_url", rapidjson::StringRef(region.styleURL.data(), region.styleURL.length()), doc.GetAllocator());
+
+ rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> bounds(rapidjson::kArrayType);
+ bounds.PushBack(region.bounds.south(), doc.GetAllocator());
+ bounds.PushBack(region.bounds.west(), doc.GetAllocator());
+ bounds.PushBack(region.bounds.north(), doc.GetAllocator());
+ bounds.PushBack(region.bounds.east(), doc.GetAllocator());
+ doc.AddMember("bounds", bounds, doc.GetAllocator());
+
+ doc.AddMember("min_zoom", region.minZoom, doc.GetAllocator());
+ if (std::isfinite(region.maxZoom)) {
+ doc.AddMember("max_zoom", region.maxZoom, doc.GetAllocator());
+ }
+
+ doc.AddMember("pixel_ratio", region.pixelRatio, doc.GetAllocator());
+
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ doc.Accept(writer);
+
+ return buffer.GetString();
+}
+
+OfflineRegion::OfflineRegion(int64_t id_,
+ const OfflineRegionDefinition& definition_,
+ const OfflineRegionMetadata& metadata_)
+ : id(id_),
+ definition(definition_),
+ metadata(metadata_) {
+}
+
+OfflineRegion::OfflineRegion(OfflineRegion&&) = default;
+OfflineRegion::~OfflineRegion() = default;
+
+const OfflineRegionDefinition& OfflineRegion::getDefinition() const {
+ return definition;
+}
+
+const OfflineRegionMetadata& OfflineRegion::getMetadata() const {
+ return metadata;
+}
+
+int64_t OfflineRegion::getID() const {
+ return id;
+}
+
+} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
new file mode 100644
index 0000000000..78f0272fef
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -0,0 +1,523 @@
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/compression.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/map/tile_id.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include "sqlite3.hpp"
+#include <sqlite3.h>
+
+namespace mbgl {
+
+using namespace mapbox::sqlite;
+
+// If you change the schema you must write a migration from the previous version.
+static const uint32_t schemaVersion = 2;
+
+OfflineDatabase::Statement::~Statement() {
+ stmt.reset();
+ stmt.clearBindings();
+}
+
+OfflineDatabase::OfflineDatabase(const std::string& path_, uint64_t maximumCacheSize_)
+ : path(path_),
+ maximumCacheSize(maximumCacheSize_) {
+ ensureSchema();
+}
+
+OfflineDatabase::~OfflineDatabase() {
+ // Deleting these SQLite objects may result in exceptions, but we're in a destructor, so we
+ // can't throw anything.
+ try {
+ statements.clear();
+ db.reset();
+ } catch (mapbox::sqlite::Exception& ex) {
+ Log::Error(Event::Database, ex.code, ex.what());
+ }
+}
+
+void OfflineDatabase::ensureSchema() {
+ if (path != ":memory:") {
+ try {
+ db = std::make_unique<Database>(path.c_str(), ReadWrite);
+ db->setBusyTimeout(Milliseconds::max());
+
+ {
+ auto userVersionStmt = db->prepare("PRAGMA user_version");
+ userVersionStmt.run();
+ switch (userVersionStmt.get<int>(0)) {
+ case 0: break; // cache-only database; ok to delete
+ case 1: break; // cache-only database; ok to delete
+ case 2: return;
+ default: throw std::runtime_error("unknown schema version");
+ }
+ }
+
+ removeExisting();
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db->setBusyTimeout(Milliseconds::max());
+ } catch (mapbox::sqlite::Exception& ex) {
+ if (ex.code == SQLITE_CANTOPEN) {
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db->setBusyTimeout(Milliseconds::max());
+ } else if (ex.code == SQLITE_NOTADB) {
+ removeExisting();
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db->setBusyTimeout(Milliseconds::max());
+ }
+ }
+ }
+
+ #include "offline_schema.cpp.include"
+
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db->setBusyTimeout(Milliseconds::max());
+ db->exec(schema);
+ db->exec("PRAGMA user_version = " + util::toString(schemaVersion));
+}
+
+void OfflineDatabase::removeExisting() {
+ Log::Warning(Event::Database, "Removing existing incompatible offline database");
+
+ db.reset();
+
+ try {
+ util::deleteFile(path);
+ } catch (util::IOException& ex) {
+ Log::Error(Event::Database, ex.code, ex.what());
+ }
+}
+
+OfflineDatabase::Statement OfflineDatabase::getStatement(const char * sql) {
+ auto it = statements.find(sql);
+
+ if (it != statements.end()) {
+ return Statement(*it->second);
+ }
+
+ return Statement(*statements.emplace(sql, std::make_unique<mapbox::sqlite::Statement>(db->prepare(sql))).first->second);
+}
+
+optional<Response> OfflineDatabase::get(const Resource& resource) {
+ if (resource.kind == Resource::Kind::Tile) {
+ assert(resource.tileData);
+ return getTile(*resource.tileData);
+ } else {
+ return getResource(resource);
+ }
+}
+
+uint64_t OfflineDatabase::put(const Resource& resource, const Response& response) {
+ return putInternal(resource, response, true);
+}
+
+uint64_t OfflineDatabase::putInternal(const Resource& resource, const Response& response, bool evict_) {
+ if (response.error) {
+ return 0;
+ }
+
+ std::string compressedData;
+ bool compressed = false;
+ uint64_t size = 0;
+
+ if (response.data) {
+ compressedData = util::compress(*response.data);
+ compressed = compressedData.size() < response.data->size();
+ size = compressed ? compressedData.size() : response.data->size();
+ }
+
+ if (evict_ && !evict(size)) {
+ Log::Warning(Event::Database, "Unable to make space for entry");
+ return 0;
+ }
+
+ if (resource.kind == Resource::Kind::Tile) {
+ assert(resource.tileData);
+ putTile(*resource.tileData, response,
+ compressed ? compressedData : *response.data,
+ compressed);
+ } else {
+ putResource(resource, response,
+ compressed ? compressedData : *response.data,
+ compressed);
+ }
+
+ return size;
+}
+
+optional<Response> OfflineDatabase::getResource(const Resource& resource) {
+ Statement accessedStmt = getStatement(
+ "UPDATE resources SET accessed = ?1 WHERE url = ?2");
+
+ accessedStmt->bind(1, SystemClock::now());
+ accessedStmt->bind(2, resource.url);
+ accessedStmt->run();
+
+ Statement stmt = getStatement(
+ // 0 1 2 3 4
+ "SELECT etag, expires, modified, data, compressed "
+ "FROM resources "
+ "WHERE url = ?");
+
+ stmt->bind(1, resource.url);
+
+ if (!stmt->run()) {
+ return {};
+ }
+
+ Response response;
+
+ response.etag = stmt->get<optional<std::string>>(0);
+ response.expires = stmt->get<optional<SystemTimePoint>>(1);
+ response.modified = stmt->get<optional<SystemTimePoint>>(2);
+
+ optional<std::string> data = stmt->get<optional<std::string>>(3);
+ if (!data) {
+ response.noContent = true;
+ } else if (stmt->get<int>(4)) {
+ response.data = std::make_shared<std::string>(util::decompress(*data));
+ } else {
+ response.data = std::make_shared<std::string>(*data);
+ }
+
+ return response;
+}
+
+void OfflineDatabase::putResource(const Resource& resource,
+ const Response& response,
+ const std::string& data,
+ bool compressed) {
+ if (response.notModified) {
+ Statement stmt = getStatement(
+ "UPDATE resources "
+ "SET accessed = ?1, "
+ " expires = ?2 "
+ "WHERE url = ?3 ");
+
+ stmt->bind(1, SystemClock::now());
+ stmt->bind(2, response.expires);
+ stmt->bind(3, resource.url);
+ stmt->run();
+ } else {
+ Statement stmt = getStatement(
+ "REPLACE INTO resources (url, kind, etag, expires, modified, accessed, data, compressed) "
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) ");
+
+ stmt->bind(1, resource.url);
+ stmt->bind(2, int(resource.kind));
+ stmt->bind(3, response.etag);
+ stmt->bind(4, response.expires);
+ stmt->bind(5, response.modified);
+ stmt->bind(6, SystemClock::now());
+
+ if (response.noContent) {
+ stmt->bind(7, nullptr);
+ stmt->bind(8, false);
+ } else {
+ stmt->bindBlob(7, data.data(), data.size(), false);
+ stmt->bind(8, compressed);
+ }
+
+ stmt->run();
+ }
+}
+
+optional<Response> OfflineDatabase::getTile(const Resource::TileData& tile) {
+ Statement accessedStmt = getStatement(
+ "UPDATE tiles "
+ "SET accessed = ?1 "
+ "WHERE url_template = ?2 "
+ " AND pixel_ratio = ?3 "
+ " AND x = ?4 "
+ " AND y = ?5 "
+ " AND z = ?6 ");
+
+ accessedStmt->bind(1, SystemClock::now());
+ accessedStmt->bind(2, tile.urlTemplate);
+ accessedStmt->bind(3, tile.pixelRatio);
+ accessedStmt->bind(4, tile.x);
+ accessedStmt->bind(5, tile.y);
+ accessedStmt->bind(6, tile.z);
+ accessedStmt->run();
+
+ Statement stmt = getStatement(
+ // 0 1 2 3 4
+ "SELECT etag, expires, modified, data, compressed "
+ "FROM tiles "
+ "WHERE url_template = ?1 "
+ " AND pixel_ratio = ?2 "
+ " AND x = ?3 "
+ " AND y = ?4 "
+ " AND z = ?5 ");
+
+ stmt->bind(1, tile.urlTemplate);
+ stmt->bind(2, tile.pixelRatio);
+ stmt->bind(3, tile.x);
+ stmt->bind(4, tile.y);
+ stmt->bind(5, tile.z);
+
+ if (!stmt->run()) {
+ return {};
+ }
+
+ Response response;
+
+ response.etag = stmt->get<optional<std::string>>(0);
+ response.expires = stmt->get<optional<SystemTimePoint>>(1);
+ response.modified = stmt->get<optional<SystemTimePoint>>(2);
+
+ optional<std::string> data = stmt->get<optional<std::string>>(3);
+ if (!data) {
+ response.noContent = true;
+ } else if (stmt->get<int>(4)) {
+ response.data = std::make_shared<std::string>(util::decompress(*data));
+ } else {
+ response.data = std::make_shared<std::string>(*data);
+ }
+
+ return response;
+}
+
+void OfflineDatabase::putTile(const Resource::TileData& tile,
+ const Response& response,
+ const std::string& data,
+ bool compressed) {
+ if (response.notModified) {
+ Statement stmt = getStatement(
+ "UPDATE tiles "
+ "SET accessed = ?1, "
+ " expires = ?2 "
+ "WHERE url_template = ?3 "
+ " AND pixel_ratio = ?4 "
+ " AND x = ?5 "
+ " AND y = ?6 "
+ " AND z = ?7 ");
+
+ stmt->bind(1, SystemClock::now());
+ stmt->bind(2, response.expires);
+ stmt->bind(3, tile.urlTemplate);
+ stmt->bind(4, tile.pixelRatio);
+ stmt->bind(5, tile.x);
+ stmt->bind(6, tile.y);
+ stmt->bind(7, tile.z);
+ stmt->run();
+ } else {
+ Statement stmt2 = getStatement(
+ "REPLACE INTO tiles (url_template, pixel_ratio, x, y, z, modified, etag, expires, accessed, data, compressed) "
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11) ");
+
+ stmt2->bind(1, tile.urlTemplate);
+ stmt2->bind(2, tile.pixelRatio);
+ stmt2->bind(3, tile.x);
+ stmt2->bind(4, tile.y);
+ stmt2->bind(5, tile.z);
+ stmt2->bind(6, response.modified);
+ stmt2->bind(7, response.etag);
+ stmt2->bind(8, response.expires);
+ stmt2->bind(9, SystemClock::now());
+
+ if (response.noContent) {
+ stmt2->bind(10, nullptr);
+ stmt2->bind(11, false);
+ } else {
+ stmt2->bindBlob(10, data.data(), data.size(), false);
+ stmt2->bind(11, compressed);
+ }
+
+ stmt2->run();
+ }
+}
+
+std::vector<OfflineRegion> OfflineDatabase::listRegions() {
+ Statement stmt = getStatement(
+ "SELECT id, definition, description FROM regions");
+
+ std::vector<OfflineRegion> result;
+
+ while (stmt->run()) {
+ result.push_back(OfflineRegion(
+ stmt->get<int64_t>(0),
+ decodeOfflineRegionDefinition(stmt->get<std::string>(1)),
+ stmt->get<std::vector<uint8_t>>(2)));
+ }
+
+ return result;
+}
+
+OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata) {
+ Statement stmt = getStatement(
+ "INSERT INTO regions (definition, description) "
+ "VALUES (?1, ?2) ");
+
+ stmt->bind(1, encodeOfflineRegionDefinition(definition));
+ stmt->bindBlob(2, metadata);
+ stmt->run();
+
+ return OfflineRegion(db->lastInsertRowid(), definition, metadata);
+}
+
+void OfflineDatabase::deleteRegion(OfflineRegion&& region) {
+ Statement stmt = getStatement(
+ "DELETE FROM regions WHERE id = ?");
+
+ stmt->bind(1, region.getID());
+ stmt->run();
+
+ evict(0);
+}
+
+optional<Response> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) {
+ auto response = get(resource);
+
+ if (response) {
+ markUsed(regionID, resource);
+ }
+
+ return response;
+}
+
+uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& resource, const Response& response) {
+ uint64_t result = putInternal(resource, response, false);
+ markUsed(regionID, resource);
+ return result;
+}
+
+void OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
+ if (resource.kind == Resource::Kind::Tile) {
+ Statement stmt = getStatement(
+ "REPLACE INTO region_tiles (region_id, tile_id) "
+ "SELECT ?1, tiles.id "
+ "FROM tiles "
+ "WHERE url_template = ?2 "
+ " AND pixel_ratio = ?3 "
+ " AND x = ?4 "
+ " AND y = ?5 "
+ " AND z = ?6 ");
+
+ const Resource::TileData& tile = *resource.tileData;
+ stmt->bind(1, regionID);
+ stmt->bind(2, tile.urlTemplate);
+ stmt->bind(3, tile.pixelRatio);
+ stmt->bind(4, tile.x);
+ stmt->bind(5, tile.y);
+ stmt->bind(6, tile.z);
+ stmt->run();
+ } else {
+ Statement stmt = getStatement(
+ "REPLACE INTO region_resources (region_id, resource_id) "
+ "SELECT ?1, resources.id "
+ "FROM resources "
+ "WHERE resources.url = ?2 ");
+
+ stmt->bind(1, regionID);
+ stmt->bind(2, resource.url);
+ stmt->run();
+ }
+}
+
+OfflineRegionDefinition OfflineDatabase::getRegionDefinition(int64_t regionID) {
+ Statement stmt = getStatement(
+ "SELECT definition FROM regions WHERE id = ?1");
+
+ stmt->bind(1, regionID);
+ stmt->run();
+
+ return decodeOfflineRegionDefinition(stmt->get<std::string>(0));
+}
+
+OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID) {
+ OfflineRegionStatus result;
+
+ Statement stmt = getStatement(
+ "SELECT COUNT(*), SUM(size) FROM ( "
+ " SELECT LENGTH(data) as size "
+ " FROM region_resources, resources "
+ " WHERE region_id = ?1 "
+ " AND resource_id = resources.id "
+ " UNION ALL "
+ " SELECT LENGTH(data) as size "
+ " FROM region_tiles, tiles "
+ " WHERE region_id = ?1 "
+ " AND tile_id = tiles.id "
+ ") ");
+
+ stmt->bind(1, regionID);
+ stmt->run();
+
+ result.completedResourceCount = stmt->get<int64_t>(0);
+ result.completedResourceSize = stmt->get<int64_t>(1);
+
+ return result;
+}
+
+template <class T>
+T OfflineDatabase::getPragma(const char * sql) {
+ Statement stmt = getStatement(sql);
+ stmt->run();
+ return stmt->get<T>(0);
+}
+
+// Remove least-recently used resources and tiles until the used database size,
+// as calculated by multiplying the number of in-use pages by the page size, is
+// less than the maximum cache size. Returns false if this condition cannot be
+// satisfied.
+//
+// SQLite database never shrinks in size unless we call VACCUM. We here
+// are monitoring the soft limit (i.e. number of free pages in the file)
+// and as it approaches to the hard limit (i.e. the actual file size) we
+// delete an arbitrary number of old cache entries. The free pages approach saves
+// us from calling VACCUM or keeping a running total, which can be costly.
+bool OfflineDatabase::evict(uint64_t neededFreeSize) {
+ uint64_t pageSize = getPragma<int64_t>("PRAGMA page_size");
+ uint64_t pageCount = getPragma<int64_t>("PRAGMA page_count");
+
+ if (pageSize * pageCount > maximumCacheSize) {
+ Log::Warning(mbgl::Event::Database, "Current size is larger than the maximum size. Database won't get truncated.");
+ }
+
+ auto usedSize = [&] {
+ return pageSize * (pageCount - getPragma<int64_t>("PRAGMA freelist_count"));
+ };
+
+ // The addition of pageSize is a fudge factor to account for non `data` column
+ // size, and because pages can get fragmented on the database.
+ while (usedSize() + neededFreeSize + pageSize > maximumCacheSize) {
+ Statement stmt1 = getStatement(
+ "DELETE FROM resources "
+ "WHERE id IN ( "
+ " SELECT id FROM resources "
+ " LEFT JOIN region_resources "
+ " ON resource_id = resources.id "
+ " WHERE resource_id IS NULL "
+ " ORDER BY accessed ASC LIMIT ?1 "
+ ") ");
+ stmt1->bind(1, 50);
+ stmt1->run();
+ uint64_t changes1 = db->changes();
+
+ Statement stmt2 = getStatement(
+ "DELETE FROM tiles "
+ "WHERE id IN ( "
+ " SELECT id FROM tiles "
+ " LEFT JOIN region_tiles "
+ " ON tile_id = tiles.id "
+ " WHERE tile_id IS NULL "
+ " ORDER BY accessed ASC LIMIT ?1 "
+ ") ");
+ stmt2->bind(1, 50);
+ stmt2->run();
+ uint64_t changes2 = db->changes();
+
+ if (changes1 == 0 && changes2 == 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
new file mode 100644
index 0000000000..854ebdb47d
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -0,0 +1,94 @@
+#ifndef MBGL_OFFLINE_DATABASE
+#define MBGL_OFFLINE_DATABASE
+
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/constants.hpp>
+
+#include <unordered_map>
+#include <memory>
+#include <string>
+
+namespace mapbox {
+namespace sqlite {
+class Database;
+class Statement;
+}
+}
+
+namespace mbgl {
+
+class Response;
+class TileID;
+
+class OfflineDatabase : private util::noncopyable {
+public:
+ // Limits affect ambient caching (put) only; resources required by offline
+ // regions are exempt.
+ OfflineDatabase(const std::string& path,
+ uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
+ ~OfflineDatabase();
+
+ optional<Response> get(const Resource&);
+ uint64_t put(const Resource&, const Response&);
+
+ std::vector<OfflineRegion> listRegions();
+
+ OfflineRegion createRegion(const OfflineRegionDefinition&,
+ const OfflineRegionMetadata&);
+
+ void deleteRegion(OfflineRegion&&);
+
+ optional<Response> getRegionResource(int64_t regionID, const Resource&);
+ uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&);
+
+ OfflineRegionDefinition getRegionDefinition(int64_t regionID);
+ OfflineRegionStatus getRegionCompletedStatus(int64_t regionID);
+
+private:
+ void ensureSchema();
+ void removeExisting();
+
+ class Statement {
+ public:
+ explicit Statement(mapbox::sqlite::Statement& stmt_) : stmt(stmt_) {}
+ Statement(Statement&&) = default;
+ Statement(const Statement&) = delete;
+ ~Statement();
+
+ mapbox::sqlite::Statement* operator->() { return &stmt; };
+
+ private:
+ mapbox::sqlite::Statement& stmt;
+ };
+
+ Statement getStatement(const char *);
+
+ optional<Response> getTile(const Resource::TileData&);
+ void putTile(const Resource::TileData&, const Response&,
+ const std::string&, bool compressed);
+
+ optional<Response> getResource(const Resource&);
+ void putResource(const Resource&, const Response&,
+ const std::string&, bool compressed);
+
+ uint64_t putInternal(const Resource&, const Response&, bool evict);
+ void markUsed(int64_t regionID, const Resource&);
+
+ const std::string path;
+ std::unique_ptr<::mapbox::sqlite::Database> db;
+ std::unordered_map<const char *, std::unique_ptr<::mapbox::sqlite::Statement>> statements;
+
+ template <class T>
+ T getPragma(const char *);
+
+ uint64_t maximumCacheSize;
+
+ bool evict(uint64_t neededFreeSize);
+};
+
+} // namespace mbgl
+
+#endif
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
new file mode 100644
index 0000000000..27bf3b8c5b
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -0,0 +1,241 @@
+#include <mbgl/storage/offline_download.hpp>
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/style/style_parser.hpp>
+#include <mbgl/layer/symbol_layer.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/tile_cover.hpp>
+
+#include <set>
+
+namespace mbgl {
+
+OfflineDownload::OfflineDownload(int64_t id_,
+ OfflineRegionDefinition&& definition_,
+ OfflineDatabase& offlineDatabase_,
+ FileSource& onlineFileSource_)
+ : id(id_),
+ definition(definition_),
+ offlineDatabase(offlineDatabase_),
+ onlineFileSource(onlineFileSource_) {
+ setObserver(nullptr);
+}
+
+OfflineDownload::~OfflineDownload() = default;
+
+void OfflineDownload::setObserver(std::unique_ptr<OfflineRegionObserver> observer_) {
+ observer = observer_ ? std::move(observer_) : std::make_unique<OfflineRegionObserver>();
+}
+
+void OfflineDownload::setState(OfflineRegionDownloadState state) {
+ if (status.downloadState == state) {
+ return;
+ }
+
+ status.downloadState = state;
+
+ if (status.downloadState == OfflineRegionDownloadState::Active) {
+ activateDownload();
+ } else {
+ deactivateDownload();
+ }
+}
+
+std::vector<Resource> OfflineDownload::spriteResources(const StyleParser& parser) const {
+ std::vector<Resource> result;
+
+ if (!parser.spriteURL.empty()) {
+ result.push_back(Resource::spriteImage(parser.spriteURL, definition.pixelRatio));
+ result.push_back(Resource::spriteJSON(parser.spriteURL, definition.pixelRatio));
+ }
+
+ return result;
+}
+
+std::vector<Resource> OfflineDownload::glyphResources(const StyleParser& parser) const {
+ std::vector<Resource> result;
+
+ if (!parser.glyphURL.empty()) {
+ for (const auto& fontStack : parser.fontStacks()) {
+ for (uint32_t i = 0; i < 256; i++) {
+ result.push_back(Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * 256)));
+ }
+ }
+ }
+
+ return result;
+}
+
+std::vector<Resource> OfflineDownload::tileResources(SourceType type, uint16_t tileSize, const SourceInfo& info) const {
+ std::vector<Resource> result;
+
+ for (const auto& tile : definition.tileCover(type, tileSize, info)) {
+ result.push_back(Resource::tile(info.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z));
+ }
+
+ return result;
+}
+
+OfflineRegionStatus OfflineDownload::getStatus() const {
+ if (status.downloadState == OfflineRegionDownloadState::Active) {
+ return status;
+ }
+
+ OfflineRegionStatus result = offlineDatabase.getRegionCompletedStatus(id);
+
+ result.requiredResourceCount++;
+ optional<Response> styleResponse = offlineDatabase.get(Resource::style(definition.styleURL));
+ if (!styleResponse) {
+ return result;
+ }
+
+ StyleParser parser;
+ parser.parse(*styleResponse->data);
+
+ result.requiredResourceCountIsIndeterminate = false;
+
+ for (const auto& source : parser.sources) {
+ switch (source->type) {
+ case SourceType::Vector:
+ case SourceType::Raster:
+ if (source->getInfo()) {
+ result.requiredResourceCount += tileResources(source->type, source->tileSize, *source->getInfo()).size();
+ } else {
+ result.requiredResourceCount += 1;
+ optional<Response> sourceResponse = offlineDatabase.get(Resource::source(source->url));
+ if (sourceResponse) {
+ result.requiredResourceCount += tileResources(source->type, source->tileSize,
+ *StyleParser::parseTileJSON(*sourceResponse->data, source->url, source->type, source->tileSize)).size();
+ } else {
+ result.requiredResourceCountIsIndeterminate = true;
+ }
+ }
+ break;
+
+ case SourceType::GeoJSON:
+ if (!source->url.empty()) {
+ result.requiredResourceCount += 1;
+ }
+ break;
+
+ case SourceType::Video:
+ case SourceType::Annotations:
+ break;
+ }
+ }
+
+ result.requiredResourceCount += spriteResources(parser).size();
+ result.requiredResourceCount += glyphResources(parser).size();
+
+ return result;
+}
+
+void OfflineDownload::activateDownload() {
+ status = offlineDatabase.getRegionCompletedStatus(id);
+ requiredSourceURLs.clear();
+
+ ensureResource(Resource::style(definition.styleURL), [&] (Response styleResponse) {
+ status.requiredResourceCountIsIndeterminate = false;
+
+ StyleParser parser;
+ parser.parse(*styleResponse.data);
+
+ for (const auto& source : parser.sources) {
+ SourceType type = source->type;
+ uint16_t tileSize = source->tileSize;
+ std::string url = source->url;
+
+ switch (type) {
+ case SourceType::Vector:
+ case SourceType::Raster:
+ if (source->getInfo()) {
+ ensureTiles(type, tileSize, *source->getInfo());
+ } else {
+ status.requiredResourceCountIsIndeterminate = true;
+ requiredSourceURLs.insert(url);
+
+ ensureResource(Resource::source(url), [=] (Response sourceResponse) {
+ ensureTiles(type, tileSize, *StyleParser::parseTileJSON(*sourceResponse.data, url, type, tileSize));
+
+ requiredSourceURLs.erase(url);
+ if (requiredSourceURLs.empty()) {
+ status.requiredResourceCountIsIndeterminate = false;
+ }
+ });
+ }
+ break;
+
+ case SourceType::GeoJSON:
+ if (!source->url.empty()) {
+ ensureResource(Resource::source(source->url));
+ }
+ break;
+
+ case SourceType::Video:
+ case SourceType::Annotations:
+ break;
+ }
+ }
+
+ for (const auto& resource : spriteResources(parser)) {
+ ensureResource(resource);
+ }
+
+ for (const auto& resource : glyphResources(parser)) {
+ ensureResource(resource);
+ }
+ });
+
+ // This will be the initial notification, after we've incremented requiredResourceCount
+ // to the reflect the extent to which required resources are already in the database.
+ observer->statusChanged(status);
+}
+
+void OfflineDownload::deactivateDownload() {
+ requests.clear();
+}
+
+void OfflineDownload::ensureTiles(SourceType type, uint16_t tileSize, const SourceInfo& info) {
+ for (const auto& resource : tileResources(type, tileSize, info)) {
+ ensureResource(resource);
+ }
+}
+
+void OfflineDownload::ensureResource(const Resource& resource, std::function<void (Response)> callback) {
+ status.requiredResourceCount++;
+
+ optional<Response> offlineResponse = offlineDatabase.getRegionResource(id, resource);
+ if (offlineResponse) {
+ if (callback) {
+ callback(*offlineResponse);
+ }
+
+ // Not incrementing status.completedResource{Size,Count} here because previously-existing
+ // resources are already accounted for by offlineDatabase.getRegionCompletedStatus();
+
+ return;
+ }
+
+ auto it = requests.insert(requests.begin(), nullptr);
+ *it = onlineFileSource.request(resource, [=] (Response onlineResponse) {
+ if (onlineResponse.error) {
+ observer->responseError(*onlineResponse.error);
+ return;
+ }
+
+ requests.erase(it);
+
+ if (callback) {
+ callback(onlineResponse);
+ }
+
+ status.completedResourceCount++;
+ status.completedResourceSize += offlineDatabase.putRegionResource(id, resource, onlineResponse);
+
+ observer->statusChanged(status);
+ });
+}
+
+} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline_download.hpp b/platform/default/mbgl/storage/offline_download.hpp
new file mode 100644
index 0000000000..4200020487
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_download.hpp
@@ -0,0 +1,62 @@
+ #pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <list>
+#include <set>
+#include <memory>
+
+namespace mbgl {
+
+class OfflineDatabase;
+class FileSource;
+class FileRequest;
+class Resource;
+class Response;
+class SourceInfo;
+class StyleParser;
+class Source;
+
+/**
+ * Coordinates the request and storage of all resources for an offline region.
+
+ * @private
+ */
+class OfflineDownload {
+public:
+ OfflineDownload(int64_t id, OfflineRegionDefinition&&, OfflineDatabase& offline, FileSource& online);
+ ~OfflineDownload();
+
+ void setObserver(std::unique_ptr<OfflineRegionObserver>);
+ void setState(OfflineRegionDownloadState);
+
+ OfflineRegionStatus getStatus() const;
+
+private:
+ void activateDownload();
+ void deactivateDownload();
+
+ std::vector<Resource> spriteResources(const StyleParser&) const;
+ std::vector<Resource> glyphResources(const StyleParser&) const;
+ std::vector<Resource> tileResources(SourceType, uint16_t, const SourceInfo&) const;
+
+ /*
+ * Ensure that the resource is stored in the database, requesting it if necessary.
+ * While the request is in progress, it is recorded in `requests`. If the download
+ * is deactivated, all in progress requests are cancelled.
+ */
+ void ensureResource(const Resource&, std::function<void (Response)> = {});
+ void ensureTiles(SourceType, uint16_t, const SourceInfo&);
+
+ int64_t id;
+ OfflineRegionDefinition definition;
+ OfflineDatabase& offlineDatabase;
+ FileSource& onlineFileSource;
+ OfflineRegionStatus status;
+ std::unique_ptr<OfflineRegionObserver> observer;
+ std::list<std::unique_ptr<FileRequest>> requests;
+ std::set<std::string> requiredSourceURLs;
+};
+
+} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline_schema.cpp.include b/platform/default/mbgl/storage/offline_schema.cpp.include
new file mode 100644
index 0000000000..3068dadfe0
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_schema.cpp.include
@@ -0,0 +1,53 @@
+/* THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD */
+static const char * schema =
+"CREATE TABLE resources (\n"
+" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n"
+" url TEXT NOT NULL,\n"
+" kind INTEGER NOT NULL,\n"
+" expires INTEGER,\n"
+" modified INTEGER,\n"
+" etag TEXT,\n"
+" data BLOB,\n"
+" compressed INTEGER NOT NULL DEFAULT 0,\n"
+" accessed INTEGER NOT NULL,\n"
+" UNIQUE (url)\n"
+");\n"
+"CREATE TABLE tiles (\n"
+" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n"
+" url_template TEXT NOT NULL,\n"
+" pixel_ratio INTEGER NOT NULL,\n"
+" z INTEGER NOT NULL,\n"
+" x INTEGER NOT NULL,\n"
+" y INTEGER NOT NULL,\n"
+" expires INTEGER,\n"
+" modified INTEGER,\n"
+" etag TEXT,\n"
+" data BLOB,\n"
+" compressed INTEGER NOT NULL DEFAULT 0,\n"
+" accessed INTEGER NOT NULL,\n"
+" UNIQUE (url_template, pixel_ratio, z, x, y)\n"
+");\n"
+"CREATE TABLE regions (\n"
+" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n"
+" definition TEXT NOT NULL,\n"
+" description BLOB\n"
+");\n"
+"CREATE TABLE region_resources (\n"
+" region_id INTEGER NOT NULL REFERENCES regions(id),\n"
+" resource_id INTEGER NOT NULL REFERENCES resources(id),\n"
+" UNIQUE (region_id, resource_id)\n"
+");\n"
+"CREATE TABLE region_tiles (\n"
+" region_id INTEGER NOT NULL REFERENCES regions(id),\n"
+" tile_id INTEGER NOT NULL REFERENCES tiles(id),\n"
+" UNIQUE (region_id, tile_id)\n"
+");\n"
+"CREATE INDEX resources_accessed\n"
+"ON resources (accessed);\n"
+"CREATE INDEX tiles_accessed\n"
+"ON tiles (accessed);\n"
+"CREATE INDEX region_resources_resource_id\n"
+"ON region_resources (resource_id);\n"
+"CREATE INDEX region_tiles_tile_id\n"
+"ON region_tiles (tile_id);\n"
+;
diff --git a/platform/default/mbgl/storage/offline_schema.js b/platform/default/mbgl/storage/offline_schema.js
new file mode 100644
index 0000000000..153ba34e38
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_schema.js
@@ -0,0 +1,24 @@
+// To regenerate:
+// (cd platform/default/mbgl/storage && node offline_schema.js)
+
+var fs = require('fs');
+var readline = require('readline');
+
+var lineReader = readline.createInterface({
+ input: fs.createReadStream('offline_schema.sql')
+});
+
+var lines = [
+ "/* THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD */",
+ "static const char * schema = ",
+];
+
+lineReader
+ .on('line', function (line) {
+ line = line.replace(/ *--.*/, '');
+ if (line) lines.push('"' + line + '\\n"');
+ })
+ .on('close', function () {
+ lines.push(';\n');
+ fs.writeFileSync('offline_schema.cpp.include', lines.join('\n'));
+ });
diff --git a/platform/default/mbgl/storage/offline_schema.sql b/platform/default/mbgl/storage/offline_schema.sql
new file mode 100644
index 0000000000..cba922f3f7
--- /dev/null
+++ b/platform/default/mbgl/storage/offline_schema.sql
@@ -0,0 +1,62 @@
+CREATE TABLE resources ( -- Generic table for style, source, sprite, and glyph resources.
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ url TEXT NOT NULL,
+ kind INTEGER NOT NULL,
+ expires INTEGER,
+ modified INTEGER,
+ etag TEXT,
+ data BLOB,
+ compressed INTEGER NOT NULL DEFAULT 0,
+ accessed INTEGER NOT NULL,
+ UNIQUE (url)
+);
+
+CREATE TABLE tiles (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ url_template TEXT NOT NULL,
+ pixel_ratio INTEGER NOT NULL,
+ z INTEGER NOT NULL,
+ x INTEGER NOT NULL,
+ y INTEGER NOT NULL,
+ expires INTEGER,
+ modified INTEGER,
+ etag TEXT,
+ data BLOB,
+ compressed INTEGER NOT NULL DEFAULT 0,
+ accessed INTEGER NOT NULL,
+ UNIQUE (url_template, pixel_ratio, z, x, y)
+);
+
+CREATE TABLE regions (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ definition TEXT NOT NULL, -- JSON formatted definition of region. Regions may be of variant types:
+ -- e.g. bbox and zoom range, route path, flyTo parameters, etc. Note that
+ -- the set of tiles required for a region may span multiple sources.
+ description BLOB -- User provided data in user-defined format
+);
+
+CREATE TABLE region_resources (
+ region_id INTEGER NOT NULL REFERENCES regions(id),
+ resource_id INTEGER NOT NULL REFERENCES resources(id),
+ UNIQUE (region_id, resource_id)
+);
+
+CREATE TABLE region_tiles (
+ region_id INTEGER NOT NULL REFERENCES regions(id),
+ tile_id INTEGER NOT NULL REFERENCES tiles(id),
+ UNIQUE (region_id, tile_id)
+);
+
+-- Indexes for efficient eviction queries
+
+CREATE INDEX resources_accessed
+ON resources (accessed);
+
+CREATE INDEX tiles_accessed
+ON tiles (accessed);
+
+CREATE INDEX region_resources_resource_id
+ON region_resources (resource_id);
+
+CREATE INDEX region_tiles_tile_id
+ON region_tiles (tile_id);
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index 988147a373..367777d623 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -1,7 +1,6 @@
#include <mbgl/storage/online_file_source.hpp>
#include <mbgl/storage/http_context_base.hpp>
#include <mbgl/storage/network_status.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/log.hpp>
@@ -16,42 +15,27 @@
#include <algorithm>
#include <cassert>
-#include <set>
+#include <list>
+#include <unordered_set>
#include <unordered_map>
namespace mbgl {
-class OnlineFileRequest : public FileRequest {
-public:
- OnlineFileRequest(OnlineFileSource& fileSource_)
- : fileSource(fileSource_) {
- }
-
- ~OnlineFileRequest() {
- fileSource.cancel(this);
- }
-
- OnlineFileSource& fileSource;
- std::unique_ptr<WorkRequest> workRequest;
-};
-
class OnlineFileRequestImpl : public util::noncopyable {
public:
using Callback = std::function<void (Response)>;
- OnlineFileRequestImpl(const Resource&, Callback, OnlineFileSource::Impl&);
+ OnlineFileRequestImpl(FileRequest*, const Resource&, Callback, OnlineFileSource::Impl&);
~OnlineFileRequestImpl();
void networkIsReachableAgain(OnlineFileSource::Impl&);
+ void schedule(OnlineFileSource::Impl&, bool forceImmediate = false);
+ void completed(OnlineFileSource::Impl&, Response);
-private:
- void scheduleCacheRequest(OnlineFileSource::Impl&);
- void scheduleRealRequest(OnlineFileSource::Impl&, bool forceImmediate = false);
-
+ FileRequest* key;
Resource resource;
- std::unique_ptr<WorkRequest> cacheRequest;
- HTTPRequestBase* realRequest = nullptr;
- util::Timer realRequestTimer;
+ HTTPRequestBase* request = nullptr;
+ util::Timer timer;
Callback callback;
// Counts the number of subsequent failed requests. We're using this value for exponential
@@ -62,140 +46,167 @@ private:
class OnlineFileSource::Impl {
public:
- using Callback = std::function<void (Response)>;
+ // Dummy parameter is a workaround for a gcc 4.9 bug.
+ Impl(int) {
+ NetworkStatus::Subscribe(&reachability);
+ }
+
+ ~Impl() {
+ NetworkStatus::Unsubscribe(&reachability);
+ }
+
+ void request(FileRequest* key, Resource resource, Callback callback) {
+ allRequests[key] = std::make_unique<OnlineFileRequestImpl>(key, resource, callback, *this);
+ }
- Impl(SQLiteCache*);
- ~Impl();
+ void cancel(FileRequest* key) {
+ allRequests.erase(key);
+ if (activeRequests.erase(key)) {
+ activatePendingRequest();
+ } else {
+ auto it = pendingRequestsMap.find(key);
+ if (it != pendingRequestsMap.end()) {
+ pendingRequestsList.erase(it->second);
+ pendingRequestsMap.erase(it);
+ }
+ }
+ }
- void networkIsReachableAgain();
+ void activateOrQueueRequest(OnlineFileRequestImpl* impl) {
+ assert(allRequests.find(impl->key) != allRequests.end());
+ assert(activeRequests.find(impl->key) == activeRequests.end());
+ assert(!impl->request);
- void add(Resource, FileRequest*, Callback);
- void cancel(FileRequest*);
+ if (activeRequests.size() >= HTTPContextBase::maximumConcurrentRequests()) {
+ queueRequest(impl);
+ } else {
+ activateRequest(impl);
+ }
+ }
+
+ void queueRequest(OnlineFileRequestImpl* impl) {
+ auto it = pendingRequestsList.insert(pendingRequestsList.end(), impl->key);
+ pendingRequestsMap.emplace(impl->key, std::move(it));
+ }
+
+ void activateRequest(OnlineFileRequestImpl* impl) {
+ activeRequests.insert(impl->key);
+ impl->request = httpContext->createRequest(impl->resource, [=] (Response response) {
+ impl->request = nullptr;
+ activeRequests.erase(impl->key);
+ activatePendingRequest();
+ impl->completed(*this, response);
+ });
+ }
+
+ void activatePendingRequest() {
+ if (pendingRequestsList.empty()) {
+ return;
+ }
+
+ FileRequest* key = pendingRequestsList.front();
+ pendingRequestsList.pop_front();
+
+ pendingRequestsMap.erase(key);
+
+ auto it = allRequests.find(key);
+ assert(it != allRequests.end());
+ activateRequest(it->second.get());
+ }
private:
- friend OnlineFileRequestImpl;
+ void networkIsReachableAgain() {
+ for (auto& req : allRequests) {
+ req.second->networkIsReachableAgain(*this);
+ }
+ }
- std::unordered_map<FileRequest*, std::unique_ptr<OnlineFileRequestImpl>> pending;
- SQLiteCache* const cache;
- const std::unique_ptr<HTTPContextBase> httpContext;
- util::AsyncTask reachability;
+ /**
+ * The lifetime of a request is:
+ *
+ * 1. Waiting for timeout (revalidation or retry)
+ * 2. Pending (waiting for room in the active set)
+ * 3. Active (open network connection)
+ * 4. Back to #1
+ *
+ * Requests in any state are in `allRequests`. Requests in the pending state are in
+ * `pendingRequests`. Requests in the active state are in `activeRequests`.
+ */
+ std::unordered_map<FileRequest*, std::unique_ptr<OnlineFileRequestImpl>> allRequests;
+ std::list<FileRequest*> pendingRequestsList;
+ std::unordered_map<FileRequest*, std::list<FileRequest*>::iterator> pendingRequestsMap;
+ std::unordered_set<FileRequest*> activeRequests;
+
+ const std::unique_ptr<HTTPContextBase> httpContext { HTTPContextBase::createContext() };
+ util::AsyncTask reachability { std::bind(&Impl::networkIsReachableAgain, this) };
};
-OnlineFileSource::OnlineFileSource(SQLiteCache* cache)
+OnlineFileSource::OnlineFileSource()
: thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{ "OnlineFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low },
- cache)) {
+ util::ThreadContext{ "OnlineFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low }, 0)) {
}
OnlineFileSource::~OnlineFileSource() = default;
std::unique_ptr<FileRequest> OnlineFileSource::request(const Resource& resource, Callback callback) {
- if (!callback) {
- throw util::MisuseException("FileSource callback can't be empty");
- }
-
- std::string url;
+ Resource res = resource;
switch (resource.kind) {
+ case Resource::Kind::Unknown:
+ break;
+
case Resource::Kind::Style:
- url = mbgl::util::mapbox::normalizeStyleURL(resource.url, accessToken);
+ res.url = mbgl::util::mapbox::normalizeStyleURL(resource.url, accessToken);
break;
case Resource::Kind::Source:
- url = util::mapbox::normalizeSourceURL(resource.url, accessToken);
+ res.url = util::mapbox::normalizeSourceURL(resource.url, accessToken);
break;
case Resource::Kind::Glyphs:
- url = util::mapbox::normalizeGlyphsURL(resource.url, accessToken);
+ res.url = util::mapbox::normalizeGlyphsURL(resource.url, accessToken);
break;
case Resource::Kind::SpriteImage:
case Resource::Kind::SpriteJSON:
- url = util::mapbox::normalizeSpriteURL(resource.url, accessToken);
+ res.url = util::mapbox::normalizeSpriteURL(resource.url, accessToken);
break;
- default:
- url = resource.url;
+ case Resource::Kind::Tile:
+ res.url = util::mapbox::normalizeTileURL(resource.url, accessToken);
+ break;
}
- Resource res { resource.kind, url };
- auto req = std::make_unique<OnlineFileRequest>(*this);
- req->workRequest = thread->invokeWithCallback(&Impl::add, callback, res, req.get());
- return std::move(req);
-}
-
-void OnlineFileSource::cancel(FileRequest* req) {
- thread->invoke(&Impl::cancel, req);
-}
-
-// ----- Impl -----
-
-OnlineFileSource::Impl::Impl(SQLiteCache* cache_)
- : cache(cache_),
- httpContext(HTTPContextBase::createContext()),
- reachability(std::bind(&Impl::networkIsReachableAgain, this)) {
- // Subscribe to network status changes, but make sure that this async handle doesn't keep the
- // loop alive; otherwise our app wouldn't terminate. After all, we only need status change
- // notifications when our app is still running.
- NetworkStatus::Subscribe(&reachability);
-}
-
-OnlineFileSource::Impl::~Impl() {
- NetworkStatus::Unsubscribe(&reachability);
-}
+ class OnlineFileRequest : public FileRequest {
+ public:
+ OnlineFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<OnlineFileSource::Impl>& thread_)
+ : thread(thread_),
+ workRequest(thread.invokeWithCallback(&OnlineFileSource::Impl::request, callback_, this, resource_)) {
+ }
-void OnlineFileSource::Impl::networkIsReachableAgain() {
- for (auto& req : pending) {
- req.second->networkIsReachableAgain(*this);
- }
-}
+ ~OnlineFileRequest() {
+ thread.invoke(&OnlineFileSource::Impl::cancel, this);
+ }
-void OnlineFileSource::Impl::add(Resource resource, FileRequest* req, Callback callback) {
- pending[req] = std::make_unique<OnlineFileRequestImpl>(resource, callback, *this);
-}
+ util::Thread<OnlineFileSource::Impl>& thread;
+ std::unique_ptr<WorkRequest> workRequest;
+ };
-void OnlineFileSource::Impl::cancel(FileRequest* req) {
- pending.erase(req);
+ return std::make_unique<OnlineFileRequest>(res, callback, *thread);
}
-// ----- OnlineFileRequest -----
-
-OnlineFileRequestImpl::OnlineFileRequestImpl(const Resource& resource_, Callback callback_, OnlineFileSource::Impl& impl)
- : resource(resource_),
- callback(callback_) {
- if (impl.cache) {
- scheduleCacheRequest(impl);
- } else {
- scheduleRealRequest(impl, true);
- }
+OnlineFileRequestImpl::OnlineFileRequestImpl(FileRequest* key_, const Resource& resource_, Callback callback_, OnlineFileSource::Impl& impl)
+ : key(key_),
+ resource(resource_),
+ callback(std::move(callback_)) {
+ // Force an immediate first request if we don't have an expiration time.
+ schedule(impl, !resource.priorExpires);
}
OnlineFileRequestImpl::~OnlineFileRequestImpl() {
- if (realRequest) {
- realRequest->cancel();
- realRequest = nullptr;
+ if (request) {
+ request->cancel();
}
- // realRequestTimer and cacheRequest are automatically canceled upon destruction.
-}
-
-void OnlineFileRequestImpl::scheduleCacheRequest(OnlineFileSource::Impl& impl) {
- // Check the cache for existing data so that we can potentially
- // revalidate the information without having to redownload everything.
- cacheRequest = impl.cache->get(resource, [this, &impl](std::shared_ptr<Response> response) {
- cacheRequest = nullptr;
-
- if (response) {
- resource.priorModified = response->modified;
- resource.priorExpires = response->expires;
- resource.priorEtag = response->etag;
- callback(*response);
- }
-
- // Force immediate revalidation if we don't have a cached response, or the cached
- // response does not have an expiration time. Otherwise revalidation will happen in
- // the normal scheduling flow.
- scheduleRealRequest(impl, !response || !response->expires);
- });
}
static Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, uint32_t failedRequests) {
@@ -220,8 +231,8 @@ static Duration expirationTimeout(optional<SystemTimePoint> expires) {
}
}
-void OnlineFileRequestImpl::scheduleRealRequest(OnlineFileSource::Impl& impl, bool forceImmediate) {
- if (realRequest) {
+void OnlineFileRequestImpl::schedule(OnlineFileSource::Impl& impl, bool forceImmediate) {
+ if (request) {
// There's already a request in progress; don't start another one.
return;
}
@@ -237,55 +248,50 @@ void OnlineFileRequestImpl::scheduleRealRequest(OnlineFileSource::Impl& impl, bo
return;
}
- realRequestTimer.start(timeout, Duration::zero(), [this, &impl] {
- assert(!realRequest);
- realRequest = impl.httpContext->createRequest(resource, [this, &impl](Response response) {
- realRequest = nullptr;
-
- // If we didn't get various caching headers in the response, continue using the
- // previous values. Otherwise, update the previous values to the new values.
+ timer.start(timeout, Duration::zero(), [&] {
+ impl.activateOrQueueRequest(this);
+ });
+}
- if (!response.modified) {
- response.modified = resource.priorModified;
- } else {
- resource.priorModified = response.modified;
- }
+void OnlineFileRequestImpl::completed(OnlineFileSource::Impl& impl, Response response) {
+ // If we didn't get various caching headers in the response, continue using the
+ // previous values. Otherwise, update the previous values to the new values.
- if (!response.expires) {
- response.expires = resource.priorExpires;
- } else {
- resource.priorExpires = response.expires;
- }
+ if (!response.modified) {
+ response.modified = resource.priorModified;
+ } else {
+ resource.priorModified = response.modified;
+ }
- if (!response.etag) {
- response.etag = resource.priorEtag;
- } else {
- resource.priorEtag = response.etag;
- }
+ if (!response.expires) {
+ response.expires = resource.priorExpires;
+ } else {
+ resource.priorExpires = response.expires;
+ }
- if (impl.cache) {
- impl.cache->put(resource, response);
- }
+ if (!response.etag) {
+ response.etag = resource.priorEtag;
+ } else {
+ resource.priorEtag = response.etag;
+ }
- if (response.error) {
- failedRequests++;
- failedRequestReason = response.error->reason;
- } else {
- failedRequests = 0;
- failedRequestReason = Response::Error::Reason::Success;
- }
+ if (response.error) {
+ failedRequests++;
+ failedRequestReason = response.error->reason;
+ } else {
+ failedRequests = 0;
+ failedRequestReason = Response::Error::Reason::Success;
+ }
- callback(response);
- scheduleRealRequest(impl);
- });
- });
+ callback(response);
+ schedule(impl);
}
void OnlineFileRequestImpl::networkIsReachableAgain(OnlineFileSource::Impl& impl) {
// We need all requests to fail at least once before we are going to start retrying
// them, and we only immediately restart request that failed due to connection issues.
if (failedRequestReason == Response::Error::Reason::Connection) {
- scheduleRealRequest(impl, true);
+ schedule(impl, true);
}
}
diff --git a/platform/default/resources/api_mapbox_com-digicert.der b/platform/default/resources/api_mapbox_com-digicert.der
new file mode 100644
index 0000000000..d84cee3908
--- /dev/null
+++ b/platform/default/resources/api_mapbox_com-digicert.der
Binary files differ
diff --git a/platform/default/resources/api_mapbox_com-geotrust.der b/platform/default/resources/api_mapbox_com-geotrust.der
new file mode 100644
index 0000000000..116144bc0c
--- /dev/null
+++ b/platform/default/resources/api_mapbox_com-geotrust.der
Binary files differ
diff --git a/platform/default/resources/star_tilestream_net.der b/platform/default/resources/star_tilestream_net.der
new file mode 100644
index 0000000000..3c7cea0ff7
--- /dev/null
+++ b/platform/default/resources/star_tilestream_net.der
Binary files differ
diff --git a/platform/default/run_loop.cpp b/platform/default/run_loop.cpp
index 27f97d65e6..76c01b80b7 100644
--- a/platform/default/run_loop.cpp
+++ b/platform/default/run_loop.cpp
@@ -1,4 +1,3 @@
-#include <mbgl/platform/log.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/async_task.hpp>
#include <mbgl/util/thread_local.hpp>
@@ -73,8 +72,6 @@ public:
return reinterpret_cast<uv_handle_t*>(holder);
}
- int refCount = 1;
-
uv_loop_t *loop = nullptr;
uv_async_t* holder = new uv_async_t;
@@ -164,28 +161,7 @@ void RunLoop::runOnce() {
}
void RunLoop::stop() {
- invoke([&] {
- unref();
-
- if (impl->refCount) {
- Log::Debug(mbgl::Event::General, "Blocking on pending events.");
- }
- });
-}
-
-void RunLoop::ref() {
- ++impl->refCount;
-}
-
-void RunLoop::unref() {
- // Main loop already stopped.
- if (impl->refCount == 0) {
- return;
- }
-
- if (!--impl->refCount) {
- uv_unref(impl->holderHandle());
- }
+ invoke([&] { uv_unref(impl->holderHandle()); });
}
void RunLoop::addWatch(int fd, Event event, std::function<void(int, Event)>&& callback) {
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 5122e01015..72296c6843 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -59,6 +59,15 @@ Database::operator bool() const {
return db != nullptr;
}
+void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
+ assert(db);
+ const int err = sqlite3_busy_timeout(db,
+ int(std::min<std::chrono::milliseconds::rep>(timeout.count(), std::numeric_limits<int>::max())));
+ if (err != SQLITE_OK) {
+ throw Exception { err, sqlite3_errmsg(db) };
+ }
+}
+
void Database::exec(const std::string &sql) {
assert(db);
char *msg = nullptr;
@@ -77,6 +86,16 @@ Statement Database::prepare(const char *query) {
return Statement(db, query);
}
+int64_t Database::lastInsertRowid() const {
+ assert(db);
+ return sqlite3_last_insert_rowid(db);
+}
+
+uint64_t Database::changes() const {
+ assert(db);
+ return sqlite3_changes(db);
+}
+
Statement::Statement(sqlite3 *db, const char *sql) {
const int err = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
if (err != SQLITE_OK) {
@@ -115,9 +134,19 @@ template <> void Statement::bind(int offset, std::nullptr_t) {
check(sqlite3_bind_null(stmt, offset));
}
-template <> void Statement::bind(int offset, int value) {
+template <> void Statement::bind(int offset, int8_t value) {
assert(stmt);
- check(sqlite3_bind_int(stmt, offset, value));
+ check(sqlite3_bind_int64(stmt, offset, value));
+}
+
+template <> void Statement::bind(int offset, int16_t value) {
+ assert(stmt);
+ check(sqlite3_bind_int64(stmt, offset, value));
+}
+
+template <> void Statement::bind(int offset, int32_t value) {
+ assert(stmt);
+ check(sqlite3_bind_int64(stmt, offset, value));
}
template <> void Statement::bind(int offset, int64_t value) {
@@ -125,6 +154,26 @@ template <> void Statement::bind(int offset, int64_t value) {
check(sqlite3_bind_int64(stmt, offset, value));
}
+template <> void Statement::bind(int offset, uint8_t value) {
+ assert(stmt);
+ check(sqlite3_bind_int64(stmt, offset, value));
+}
+
+template <> void Statement::bind(int offset, uint16_t value) {
+ assert(stmt);
+ check(sqlite3_bind_int64(stmt, offset, value));
+}
+
+template <> void Statement::bind(int offset, uint32_t value) {
+ assert(stmt);
+ check(sqlite3_bind_int64(stmt, offset, value));
+}
+
+template <> void Statement::bind(int offset, float value) {
+ assert(stmt);
+ check(sqlite3_bind_double(stmt, offset, value));
+}
+
template <> void Statement::bind(int offset, double value) {
assert(stmt);
check(sqlite3_bind_double(stmt, offset, value));
@@ -140,12 +189,39 @@ template <> void Statement::bind(int offset, const char *value) {
check(sqlite3_bind_text(stmt, offset, value, -1, SQLITE_STATIC));
}
+// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
+// was introduced in SQLite 3.8.7, and we need to support earlier versions:
+// iOS 7.0: 3.7.13
+// iOS 8.2: 3.8.5
+// According to http://stackoverflow.com/questions/14288128/what-version-of-sqlite-does-ios-provide,
+// the first iOS version with 3.8.7+ was 9.0, with 3.8.10.2.
+
+void Statement::bind(int offset, const char * value, std::size_t length, bool retain) {
+ assert(stmt);
+ if (length > std::numeric_limits<int>::max()) {
+ throw std::range_error("value too long for sqlite3_bind_text");
+ }
+ check(sqlite3_bind_text(stmt, offset, value, int(length),
+ retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
+}
+
void Statement::bind(int offset, const std::string& value, bool retain) {
+ bind(offset, value.data(), value.size(), retain);
+}
+
+void Statement::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
assert(stmt);
- check(sqlite3_bind_blob(stmt, offset, value.data(), int(value.size()),
+ if (length > std::numeric_limits<int>::max()) {
+ throw std::range_error("value too long for sqlite3_bind_text");
+ }
+ check(sqlite3_bind_blob(stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
+void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+ bindBlob(offset, value.data(), value.size(), retain);
+}
+
template <> void Statement::bind(int offset, std::chrono::system_clock::time_point value) {
assert(stmt);
check(sqlite3_bind_int64(stmt, offset, std::chrono::system_clock::to_time_t(value)));
@@ -204,6 +280,13 @@ template <> std::string Statement::get(int offset) {
};
}
+template <> std::vector<uint8_t> Statement::get(int offset) {
+ assert(stmt);
+ const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, offset));
+ const uint8_t* end = begin + sqlite3_column_bytes(stmt, offset);
+ return { begin, end };
+}
+
template <> std::chrono::system_clock::time_point Statement::get(int offset) {
assert(stmt);
return std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt, offset));
@@ -232,5 +315,10 @@ void Statement::reset() {
sqlite3_reset(stmt);
}
+void Statement::clearBindings() {
+ assert(stmt);
+ sqlite3_clear_bindings(stmt);
+}
+
} // namespace sqlite
} // namespace mapbox
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 29e8967db3..abe83a2d44 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -1,7 +1,9 @@
#pragma once
#include <string>
+#include <vector>
#include <stdexcept>
+#include <chrono>
typedef struct sqlite3 sqlite3;
typedef struct sqlite3_stmt sqlite3_stmt;
@@ -38,11 +40,15 @@ public:
~Database();
Database &operator=(Database &&);
- operator bool() const;
+ explicit operator bool() const;
+ void setBusyTimeout(std::chrono::milliseconds);
void exec(const std::string &sql);
Statement prepare(const char *query);
+ int64_t lastInsertRowid() const;
+ uint64_t changes() const;
+
private:
sqlite3 *db = nullptr;
};
@@ -60,14 +66,23 @@ public:
~Statement();
Statement &operator=(Statement &&);
- operator bool() const;
+ explicit operator bool() const;
template <typename T> void bind(int offset, T value);
- void bind(int offset, const std::string &value, bool retain = true);
+
+ // Text
+ void bind(int offset, const char *, std::size_t length, bool retain = true);
+ void bind(int offset, const std::string&, bool retain = true);
+
+ // Blob
+ void bindBlob(int offset, const void *, std::size_t length, bool retain = true);
+ void bindBlob(int offset, const std::vector<uint8_t>&, bool retain = true);
+
template <typename T> T get(int offset);
bool run();
void reset();
+ void clearBindings();
private:
sqlite3_stmt *stmt = nullptr;
diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp
deleted file mode 100644
index 1980b3dead..0000000000
--- a/platform/default/sqlite_cache.cpp
+++ /dev/null
@@ -1,505 +0,0 @@
-#include "sqlite_cache_impl.hpp"
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-
-#include <mbgl/util/compression.hpp>
-#include <mbgl/util/io.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/mapbox.hpp>
-#include <mbgl/platform/log.hpp>
-
-#include "sqlite3.hpp"
-#include <sqlite3.h>
-
-#include <unordered_map>
-#include <mutex>
-
-namespace {
-
-// The cache won't accept entries larger than this arbitrary size
-// and will silently discard request for adding them to the cache.
-// Large entries can cause the database to grow in disk size and
-// never shrink again.
-const uint64_t kMaximumCacheEntrySize = 5 * 1024 * 1024; // 5 MB
-
-// Number of records we delete when we are close to the maximum
-// database size, if set. The current criteria is to prune
-// the least used entries based on `accessed` time.
-const int kPrunedEntriesLimit = 100;
-
-} // namespace
-
-namespace mbgl {
-
-using namespace mapbox::sqlite;
-
-SQLiteCache::SQLiteCache(const std::string& path_)
- : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"SQLiteCache", util::ThreadType::Unknown, util::ThreadPriority::Low}, path_)) {
-}
-
-SQLiteCache::~SQLiteCache() = default;
-
-SQLiteCache::Impl::Impl(const std::string& path_)
- : maximumCacheSize(0), // Unlimited
- maximumCacheEntrySize(kMaximumCacheEntrySize),
- path(path_) {
-}
-
-SQLiteCache::Impl::~Impl() {
- // Deleting these SQLite objects may result in exceptions, but we're in a destructor, so we
- // can't throw anything.
- try {
- getStmt.reset();
- putStmt.reset();
- refreshStmt.reset();
- countStmt.reset();
- freeStmt.reset();
- pruneStmt.reset();
- accessedStmt.reset();
- db.reset();
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-}
-
-void SQLiteCache::Impl::createDatabase() {
- db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
-}
-
-int SQLiteCache::Impl::schemaVersion() const {
- // WARNING: Bump the version when changing the cache
- // scheme to force the table to be recreated.
- return 1;
-}
-
-void SQLiteCache::Impl::createSchema() {
- constexpr const char *const sql = ""
- "CREATE TABLE IF NOT EXISTS `http_cache` ("
- " `url` TEXT PRIMARY KEY NOT NULL,"
- " `status` INTEGER NOT NULL," // The response status (Successful or Error).
- " `kind` INTEGER NOT NULL," // The kind of file.
- " `modified` INTEGER," // Timestamp when the file was last modified.
- " `etag` TEXT,"
- " `expires` INTEGER," // Timestamp when the server says the file expires.
- " `accessed` INTEGER," // Timestamp when the database record was last accessed.
- " `data` BLOB,"
- " `compressed` INTEGER NOT NULL DEFAULT 0" // Whether the data is compressed.
- ");"
- "CREATE INDEX IF NOT EXISTS `http_cache_kind_idx` ON `http_cache` (`kind`);"
- "CREATE INDEX IF NOT EXISTS `http_cache_accessed_idx` ON `http_cache` (`accessed`);";
-
- ensureSchemaVersion();
-
- try {
- db->exec(sql);
- db->exec("PRAGMA user_version = " + util::toString(schemaVersion()));
- schema = true;
- } catch (mapbox::sqlite::Exception &ex) {
- if (ex.code == SQLITE_NOTADB) {
- Log::Warning(Event::Database, "Trashing invalid database");
- db.reset();
- try {
- util::deleteFile(path);
- } catch (util::IOException& ioEx) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
- db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
- } else {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-
- // Creating the database table + index failed. That means there may already be one, likely
- // with different columns. Drop it and try to create a new one.
- db->exec("DROP TABLE IF EXISTS `http_cache`");
- db->exec(sql);
- db->exec("PRAGMA user_version = " + util::toString(schemaVersion()));
- }
-}
-
-void SQLiteCache::Impl::ensureSchemaVersion() {
- try {
- Statement userVersionStmt(db->prepare("PRAGMA user_version"));
- if (userVersionStmt.run() && userVersionStmt.get<int>(0) == schemaVersion()) {
- return;
- }
- } catch (mapbox::sqlite::Exception& ex) {
- if (ex.code == SQLITE_NOTADB) {
- return;
- }
-
- Log::Error(Event::Database, ex.code, ex.what());
- }
-
- // Version mismatch, drop the table so it will
- // get recreated by `createSchema()`.
- try {
- db->exec("DROP TABLE IF EXISTS `http_cache`");
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-}
-
-void SQLiteCache::setMaximumCacheSize(uint64_t size) {
- thread->invoke(&Impl::setMaximumCacheSize, size);
-}
-
-void SQLiteCache::Impl::setMaximumCacheSize(uint64_t size) {
- maximumCacheSize = size;
-
- // Unlimited.
- if (size == 0) {
- return;
- }
-
- uint64_t lastSoftSize = cacheSoftSize();
-
- // Keep pruning until we fit in the new
- // size limit.
- while (lastSoftSize > maximumCacheSize) {
- pruneEntries();
-
- if (lastSoftSize != cacheSoftSize()) {
- lastSoftSize = cacheSoftSize();
- } else {
- break;
- }
- }
-
- if (cacheHardSize() > size) {
- Log::Warning(mbgl::Event::Database,
- "Current cache hard size is bigger than the defined "
- "maximum size. Database won't get truncated.");
- }
-}
-
-void SQLiteCache::setMaximumCacheEntrySize(uint64_t size) {
- thread->invoke(&Impl::setMaximumCacheEntrySize, size);
-}
-
-void SQLiteCache::Impl::setMaximumCacheEntrySize(uint64_t size) {
- maximumCacheEntrySize = size;
-}
-
-void SQLiteCache::Impl::initializeDatabase() {
- if (!db) {
- createDatabase();
- }
-
- if (!schema) {
- createSchema();
- }
-}
-
-int SQLiteCache::Impl::cachePageSize() {
- try {
- if (!pageSize) {
- Statement pageSizeStmt(db->prepare("PRAGMA page_size"));
- if (pageSizeStmt.run()) {
- pageSize = pageSizeStmt.get<int>(0);
- }
- }
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-
- return pageSize;
-}
-
-uint64_t SQLiteCache::Impl::cacheHardSize() {
- try {
- initializeDatabase();
-
- if (!countStmt) {
- countStmt = std::make_unique<Statement>(db->prepare("PRAGMA page_count"));
- } else {
- countStmt->reset();
- }
-
- if (countStmt->run()) {
- return cachePageSize() * countStmt->get<int>(0);
- }
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-
- return 0;
-}
-
-uint64_t SQLiteCache::Impl::cacheSoftSize() {
- if (!softSizeDirty) {
- return softSize;
- }
-
- try {
- initializeDatabase();
-
- if (!freeStmt) {
- freeStmt = std::make_unique<Statement>(db->prepare("PRAGMA freelist_count"));
- } else {
- freeStmt->reset();
- }
-
- uint64_t hardSize = cacheHardSize();
- if (!hardSize) {
- return 0;
- }
-
- if (freeStmt->run()) {
- return hardSize - cachePageSize() * freeStmt->get<int>(0);
- }
-
- softSizeDirty = false;
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-
- return 0;
-}
-
-bool SQLiteCache::Impl::needsPruning() {
- // SQLite database never shrinks in size unless we call VACCUM. We here
- // are monitoring the soft limit (i.e. number of free pages in the file)
- // and as it approaches to the hard limit (i.e. the actual file size) we
- // delete an arbitrary number of old cache entries.
- //
- // The free pages approach saves us from calling VACCUM or keeping a
- // running total, which can be costly. We need a buffer because pages can
- // get fragmented on the database.
- if (cacheSoftSize() + maximumCacheEntrySize * 2 < maximumCacheSize) {
- return false;
- } else {
- return true;
- }
-}
-
-void SQLiteCache::Impl::pruneEntries() {
- if (!maximumCacheSize) {
- return;
- }
-
- if (!needsPruning()) {
- return;
- }
-
- try {
- if (!pruneStmt) {
- pruneStmt = std::make_unique<Statement>(db->prepare(
- "DELETE FROM `http_cache` WHERE `rowid` IN (SELECT `rowid` FROM "
- // 1
- "`http_cache` ORDER BY `accessed` ASC LIMIT ?)"));
- } else {
- pruneStmt->reset();
- }
-
- pruneStmt->bind(1, kPrunedEntriesLimit);
-
- pruneStmt->run();
- softSizeDirty = true;
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-}
-
-std::unique_ptr<WorkRequest> SQLiteCache::get(const Resource &resource, Callback callback) {
- // Can be called from any thread, but most likely from the file source thread.
- // Will try to load the URL from the SQLite database and call the callback when done.
- // Note that the callback is probably going to invoked from another thread, so the caller
- // must make sure that it can run in that thread.
- return thread->invokeWithCallback(&Impl::get, callback, resource);
-}
-
-void SQLiteCache::Impl::get(const Resource &resource, Callback callback) {
- try {
- initializeDatabase();
-
- if (!getStmt) {
- // Initialize the statement 0 1
- getStmt = std::make_unique<Statement>(db->prepare("SELECT `status`, `modified`, "
- // 2 3 4 5 1
- "`etag`, `expires`, `data`, `compressed` FROM `http_cache` WHERE `url` = ?"));
- } else {
- getStmt->reset();
- }
-
- const auto canonicalURL = util::mapbox::canonicalURL(resource.url);
- getStmt->bind(1, canonicalURL.c_str());
- if (getStmt->run()) {
- // There is data.
- auto response = std::make_unique<Response>();
- const auto status = getStmt->get<int>(0);
- if (status > 1) {
- // Status codes > 1 indicate an error
- response->error = std::make_unique<Response::Error>(Response::Error::Reason(status));
- }
- response->modified = getStmt->get<optional<SystemTimePoint>>(1);
- response->etag = getStmt->get<optional<std::string>>(2);
- response->expires = getStmt->get<optional<SystemTimePoint>>(3);
- response->data = std::make_shared<std::string>(getStmt->get<std::string>(4));
- if (getStmt->get<int>(5)) { // == compressed
- response->data = std::make_shared<std::string>(util::decompress(*response->data));
- }
- callback(std::move(response));
- } else {
- // There is no data.
- callback(nullptr);
- }
-
- // We do an extra query for refreshing the last time
- // the record was accessed that can be costly and is only
- // worth doing if we are monitoring the database size.
- if (maximumCacheSize) {
- if (!accessedStmt) {
- accessedStmt = std::make_unique<Statement>(
- // 1 2
- db->prepare("UPDATE `http_cache` SET `accessed` = ? WHERE `url` = ?"));
- } else {
- accessedStmt->reset();
- }
-
- accessedStmt->bind(1, SystemClock::now());
- accessedStmt->bind(2, canonicalURL.c_str());
- accessedStmt->run();
- }
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- callback(nullptr);
- } catch (std::runtime_error& ex) {
- Log::Error(Event::Database, "%s", ex.what());
- callback(nullptr);
- }
-}
-
-void SQLiteCache::put(const Resource& resource, const Response& response) {
- // Except for 404s, don't store errors in the cache.
- if (response.error && response.error->reason != Response::Error::Reason::NotFound) {
- return;
- }
-
- if (response.notModified) {
- thread->invoke(&Impl::refresh, resource, response.expires);
- } else {
- thread->invoke(&Impl::put, resource, response);
- }
-}
-
-void SQLiteCache::Impl::put(const Resource& resource, const Response& response) {
- try {
- initializeDatabase();
- pruneEntries();
-
- if (response.data) {
- auto entrySize = response.data->size();
-
- if (entrySize > maximumCacheEntrySize) {
- Log::Warning(Event::Database, "Entry too big for caching.");
- return;
- }
-
- if (maximumCacheSize && entrySize + cacheSoftSize() > maximumCacheSize) {
- Log::Warning(Event::Database, "Unable to make space for new entries.");
- return;
- }
- }
-
- if (!putStmt) {
- putStmt = std::make_unique<Statement>(db->prepare("REPLACE INTO `http_cache` ("
- // 1 2 3 4 5 6 7 8 9
- "`url`, `status`, `kind`, `modified`, `etag`, `expires`, `accessed`, `data`, `compressed`"
- ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
- } else {
- putStmt->reset();
- }
-
- const auto canonicalURL = util::mapbox::canonicalURL(resource.url);
- putStmt->bind(1 /* url */, canonicalURL.c_str());
- if (response.error) {
- putStmt->bind(2 /* status */, int(response.error->reason));
- } else {
- putStmt->bind(2 /* status */, 1 /* success */);
- }
- putStmt->bind(3 /* kind */, int(resource.kind));
- putStmt->bind(4 /* modified */, response.modified);
- putStmt->bind(5 /* etag */, response.etag);
- putStmt->bind(6 /* expires */, response.expires);
- putStmt->bind(7 /* accessed */, SystemClock::now());
-
- std::string data;
- if (resource.kind != Resource::SpriteImage && response.data) {
- // Do not compress images, since they are typically compressed already.
- data = util::compress(*response.data);
- }
-
- if (!data.empty() && data.size() < response.data->size()) {
- // Store the compressed data when it is smaller than the original
- // uncompressed data.
- putStmt->bind(8 /* data */, data, false); // do not retain the string internally.
- putStmt->bind(9 /* compressed */, true);
- } else if (response.data) {
- putStmt->bind(8 /* data */, *response.data, false); // do not retain the string internally.
- putStmt->bind(9 /* compressed */, false);
- } else {
- putStmt->bind(8 /* data */, "", false);
- putStmt->bind(9 /* compressed */, false);
- }
-
- putStmt->run();
- softSizeDirty = true;
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- } catch (std::runtime_error& ex) {
- Log::Error(Event::Database, "%s", ex.what());
- }
-}
-
-void SQLiteCache::Impl::refresh(const Resource& resource, optional<SystemTimePoint> expires) {
- try {
- initializeDatabase();
-
- if (!refreshStmt) {
- refreshStmt = std::make_unique<Statement>(
- db->prepare("UPDATE `http_cache` SET "
- // 1 2 3
- "`accessed` = ?, `expires` = ? WHERE `url` = ?"));
- } else {
- refreshStmt->reset();
- }
-
- const auto canonicalURL = util::mapbox::canonicalURL(resource.url);
- refreshStmt->bind(1, SystemClock::now());
- refreshStmt->bind(2, expires);
- refreshStmt->bind(3, canonicalURL.c_str());
- refreshStmt->run();
- } catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
- }
-}
-
-namespace {
-
-static std::mutex sharedMutex;
-static std::unordered_map<std::string, std::weak_ptr<SQLiteCache>> shared;
-
-} // namespace
-
-std::shared_ptr<SQLiteCache> SQLiteCache::getShared(const std::string &path) {
- std::lock_guard<std::mutex> lock(sharedMutex);
-
- std::shared_ptr<SQLiteCache> cache;
-
- auto it = shared.find(path);
- if (it != shared.end()) {
- cache = it->second.lock();
- if (!cache) {
- cache = std::make_shared<SQLiteCache>(path);
- it->second = cache;
- }
- } else {
- cache = std::make_shared<SQLiteCache>(path);
- shared.emplace(path, cache);
- }
-
- return cache;
-}
-
-} // namespace mbgl
diff --git a/platform/default/sqlite_cache_impl.hpp b/platform/default/sqlite_cache_impl.hpp
deleted file mode 100644
index e156532402..0000000000
--- a/platform/default/sqlite_cache_impl.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_SQLITE_CACHE_IMPL
-#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE_IMPL
-
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/optional.hpp>
-
-namespace mapbox {
-namespace sqlite {
-class Database;
-class Statement;
-}
-}
-
-namespace mbgl {
-
-class SQLiteCache::Impl {
-public:
- explicit Impl(const std::string &path = ":memory:");
- ~Impl();
-
- void setMaximumCacheSize(uint64_t size);
- void setMaximumCacheEntrySize(uint64_t size);
-
- void get(const Resource&, Callback);
- void put(const Resource&, const Response&);
- void refresh(const Resource&, optional<SystemTimePoint> expires);
-
-private:
- void initializeDatabase();
-
- int cachePageSize();
-
- uint64_t cacheHardSize();
- uint64_t cacheSoftSize();
-
- uint64_t softSize = 0;
- bool softSizeDirty = true;
-
- bool needsPruning();
- void pruneEntries();
-
- void createDatabase();
- void createSchema();
-
- int schemaVersion() const;
- void ensureSchemaVersion();
-
- int pageSize = 0;
-
- uint64_t maximumCacheSize;
- uint64_t maximumCacheEntrySize;
-
- const std::string path;
- std::unique_ptr<::mapbox::sqlite::Database> db;
- std::unique_ptr<::mapbox::sqlite::Statement> getStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> putStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> refreshStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> countStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> freeStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> pruneStmt;
- std::unique_ptr<::mapbox::sqlite::Statement> accessedStmt;
- bool schema = false;
-};
-
-} // namespace mbgl
-
-#endif
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index f4d903532f..1aeb152b98 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -48,7 +48,7 @@ Run
To run the included integration tests on the command line.
-If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `test/ios/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target.
+If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `platform/ios/test/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target.
### Usage
diff --git a/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 51e1a27257..51e1a27257 100644
--- a/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
diff --git a/platform/ios/README.md b/platform/ios/README.md
index 2ca32fde97..2350d1e527 100644
--- a/platform/ios/README.md
+++ b/platform/ios/README.md
@@ -9,4 +9,4 @@ This repository is for day-to-day development of the SDK. Building the SDK yours
* [Integrating the Mapbox iOS SDK into your application](INSTALL.md)
* [Contributing to the Mapbox iOS SDK](DEVELOPING.md)
-![](../../ios/screenshot.png)
+![](screenshot.png)
diff --git a/ios/app/MBXAppDelegate.h b/platform/ios/app/MBXAppDelegate.h
index da081fdcd5..da081fdcd5 100644
--- a/ios/app/MBXAppDelegate.h
+++ b/platform/ios/app/MBXAppDelegate.h
diff --git a/ios/app/MBXAppDelegate.m b/platform/ios/app/MBXAppDelegate.m
index a06424feb7..a06424feb7 100644
--- a/ios/app/MBXAppDelegate.m
+++ b/platform/ios/app/MBXAppDelegate.m
diff --git a/ios/app/MBXCustomCalloutView.h b/platform/ios/app/MBXCustomCalloutView.h
index a61619b79f..a61619b79f 100644
--- a/ios/app/MBXCustomCalloutView.h
+++ b/platform/ios/app/MBXCustomCalloutView.h
diff --git a/ios/app/MBXCustomCalloutView.m b/platform/ios/app/MBXCustomCalloutView.m
index 8f9bd8ed40..8f9bd8ed40 100644
--- a/ios/app/MBXCustomCalloutView.m
+++ b/platform/ios/app/MBXCustomCalloutView.m
diff --git a/ios/app/MBXViewController.h b/platform/ios/app/MBXViewController.h
index 924d3af60c..924d3af60c 100644
--- a/ios/app/MBXViewController.h
+++ b/platform/ios/app/MBXViewController.h
diff --git a/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm
index 8269b09f32..af4e425841 100644
--- a/ios/app/MBXViewController.mm
+++ b/platform/ios/app/MBXViewController.mm
@@ -2,7 +2,7 @@
#import "MBXCustomCalloutView.h"
#import <Mapbox/Mapbox.h>
-#import "../../include/mbgl/util/default_styles.hpp"
+#import "../../../include/mbgl/util/default_styles.hpp"
#import <CoreLocation/CoreLocation.h>
#import <OpenGLES/ES2/gl.h>
diff --git a/ios/app/Settings.bundle/Root.plist b/platform/ios/app/Settings.bundle/Root.plist
index 889610e152..889610e152 100644
--- a/ios/app/Settings.bundle/Root.plist
+++ b/platform/ios/app/Settings.bundle/Root.plist
diff --git a/ios/app/Settings.bundle/en.lproj/Root.strings b/platform/ios/app/Settings.bundle/en.lproj/Root.strings
index 5343a34ae5..5343a34ae5 100644
--- a/ios/app/Settings.bundle/en.lproj/Root.strings
+++ b/platform/ios/app/Settings.bundle/en.lproj/Root.strings
diff --git a/ios/app/app-info.plist b/platform/ios/app/app-info.plist
index eb2080dd08..eb2080dd08 100644
--- a/ios/app/app-info.plist
+++ b/platform/ios/app/app-info.plist
diff --git a/ios/app/img/Default-568h@2x.png b/platform/ios/app/img/Default-568h@2x.png
index ea3706427a..ea3706427a 100644
--- a/ios/app/img/Default-568h@2x.png
+++ b/platform/ios/app/img/Default-568h@2x.png
Binary files differ
diff --git a/ios/app/img/Default-667h@2x.png b/platform/ios/app/img/Default-667h@2x.png
index 03f139de66..03f139de66 100644
--- a/ios/app/img/Default-667h@2x.png
+++ b/platform/ios/app/img/Default-667h@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-40.png b/platform/ios/app/img/Icon-40.png
index eca13393e6..eca13393e6 100644
--- a/ios/app/img/Icon-40.png
+++ b/platform/ios/app/img/Icon-40.png
Binary files differ
diff --git a/ios/app/img/Icon-40@2x.png b/platform/ios/app/img/Icon-40@2x.png
index 070d037539..070d037539 100644
--- a/ios/app/img/Icon-40@2x.png
+++ b/platform/ios/app/img/Icon-40@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-60.png b/platform/ios/app/img/Icon-60.png
index ff4c6ab4b1..ff4c6ab4b1 100644
--- a/ios/app/img/Icon-60.png
+++ b/platform/ios/app/img/Icon-60.png
Binary files differ
diff --git a/ios/app/img/Icon-60@2x.png b/platform/ios/app/img/Icon-60@2x.png
index b7f25955f5..b7f25955f5 100644
--- a/ios/app/img/Icon-60@2x.png
+++ b/platform/ios/app/img/Icon-60@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-60@3x.png b/platform/ios/app/img/Icon-60@3x.png
index b00d479839..b00d479839 100644
--- a/ios/app/img/Icon-60@3x.png
+++ b/platform/ios/app/img/Icon-60@3x.png
Binary files differ
diff --git a/ios/app/img/Icon-72.png b/platform/ios/app/img/Icon-72.png
index 0c876f664d..0c876f664d 100644
--- a/ios/app/img/Icon-72.png
+++ b/platform/ios/app/img/Icon-72.png
Binary files differ
diff --git a/ios/app/img/Icon-72@2x.png b/platform/ios/app/img/Icon-72@2x.png
index 6da408204a..6da408204a 100644
--- a/ios/app/img/Icon-72@2x.png
+++ b/platform/ios/app/img/Icon-72@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-76.png b/platform/ios/app/img/Icon-76.png
index 895b4a1761..895b4a1761 100644
--- a/ios/app/img/Icon-76.png
+++ b/platform/ios/app/img/Icon-76.png
Binary files differ
diff --git a/ios/app/img/Icon-76@2x.png b/platform/ios/app/img/Icon-76@2x.png
index 7bc5208976..7bc5208976 100644
--- a/ios/app/img/Icon-76@2x.png
+++ b/platform/ios/app/img/Icon-76@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-76@3x.png b/platform/ios/app/img/Icon-76@3x.png
index 64edff1835..64edff1835 100644
--- a/ios/app/img/Icon-76@3x.png
+++ b/platform/ios/app/img/Icon-76@3x.png
Binary files differ
diff --git a/ios/app/img/Icon-Small-50.png b/platform/ios/app/img/Icon-Small-50.png
index 6d17da4b00..6d17da4b00 100644
--- a/ios/app/img/Icon-Small-50.png
+++ b/platform/ios/app/img/Icon-Small-50.png
Binary files differ
diff --git a/ios/app/img/Icon-Small-50@2x.png b/platform/ios/app/img/Icon-Small-50@2x.png
index ac4ec19282..ac4ec19282 100644
--- a/ios/app/img/Icon-Small-50@2x.png
+++ b/platform/ios/app/img/Icon-Small-50@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-Small.png b/platform/ios/app/img/Icon-Small.png
index aecbbc8a1d..aecbbc8a1d 100644
--- a/ios/app/img/Icon-Small.png
+++ b/platform/ios/app/img/Icon-Small.png
Binary files differ
diff --git a/ios/app/img/Icon-Small@2x.png b/platform/ios/app/img/Icon-Small@2x.png
index 7773852e7a..7773852e7a 100644
--- a/ios/app/img/Icon-Small@2x.png
+++ b/platform/ios/app/img/Icon-Small@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-Small@3x.png b/platform/ios/app/img/Icon-Small@3x.png
index e16f3fa6a9..e16f3fa6a9 100644
--- a/ios/app/img/Icon-Small@3x.png
+++ b/platform/ios/app/img/Icon-Small@3x.png
Binary files differ
diff --git a/ios/app/img/Icon-Spotlight-40.png b/platform/ios/app/img/Icon-Spotlight-40.png
index eca13393e6..eca13393e6 100644
--- a/ios/app/img/Icon-Spotlight-40.png
+++ b/platform/ios/app/img/Icon-Spotlight-40.png
Binary files differ
diff --git a/ios/app/img/Icon-Spotlight-40@2x.png b/platform/ios/app/img/Icon-Spotlight-40@2x.png
index 070d037539..070d037539 100644
--- a/ios/app/img/Icon-Spotlight-40@2x.png
+++ b/platform/ios/app/img/Icon-Spotlight-40@2x.png
Binary files differ
diff --git a/ios/app/img/Icon-Spotlight-40@3x.png b/platform/ios/app/img/Icon-Spotlight-40@3x.png
index a3789dcb78..a3789dcb78 100644
--- a/ios/app/img/Icon-Spotlight-40@3x.png
+++ b/platform/ios/app/img/Icon-Spotlight-40@3x.png
Binary files differ
diff --git a/ios/app/img/Icon.png b/platform/ios/app/img/Icon.png
index 9ca8194eef..9ca8194eef 100644
--- a/ios/app/img/Icon.png
+++ b/platform/ios/app/img/Icon.png
Binary files differ
diff --git a/ios/app/img/Icon@2x.png b/platform/ios/app/img/Icon@2x.png
index 7c2e8ba037..7c2e8ba037 100644
--- a/ios/app/img/Icon@2x.png
+++ b/platform/ios/app/img/Icon@2x.png
Binary files differ
diff --git a/ios/app/img/TrackingHeadingMask.png b/platform/ios/app/img/TrackingHeadingMask.png
index 9ec0567a3f..9ec0567a3f 100644
--- a/ios/app/img/TrackingHeadingMask.png
+++ b/platform/ios/app/img/TrackingHeadingMask.png
Binary files differ
diff --git a/ios/app/img/TrackingHeadingMask@2x.png b/platform/ios/app/img/TrackingHeadingMask@2x.png
index 0df8ccc229..0df8ccc229 100644
--- a/ios/app/img/TrackingHeadingMask@2x.png
+++ b/platform/ios/app/img/TrackingHeadingMask@2x.png
Binary files differ
diff --git a/ios/app/img/TrackingHeadingMask@3x.png b/platform/ios/app/img/TrackingHeadingMask@3x.png
index e4b93e42e7..e4b93e42e7 100644
--- a/ios/app/img/TrackingHeadingMask@3x.png
+++ b/platform/ios/app/img/TrackingHeadingMask@3x.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationMask.png b/platform/ios/app/img/TrackingLocationMask.png
index bb7348c482..bb7348c482 100644
--- a/ios/app/img/TrackingLocationMask.png
+++ b/platform/ios/app/img/TrackingLocationMask.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationMask@2x.png b/platform/ios/app/img/TrackingLocationMask@2x.png
index 35c5a293ec..35c5a293ec 100644
--- a/ios/app/img/TrackingLocationMask@2x.png
+++ b/platform/ios/app/img/TrackingLocationMask@2x.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationMask@3x.png b/platform/ios/app/img/TrackingLocationMask@3x.png
index af523975a5..af523975a5 100644
--- a/ios/app/img/TrackingLocationMask@3x.png
+++ b/platform/ios/app/img/TrackingLocationMask@3x.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationOffMask.png b/platform/ios/app/img/TrackingLocationOffMask.png
index 87b26c5710..87b26c5710 100644
--- a/ios/app/img/TrackingLocationOffMask.png
+++ b/platform/ios/app/img/TrackingLocationOffMask.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationOffMask@2x.png b/platform/ios/app/img/TrackingLocationOffMask@2x.png
index 232d534b41..232d534b41 100644
--- a/ios/app/img/TrackingLocationOffMask@2x.png
+++ b/platform/ios/app/img/TrackingLocationOffMask@2x.png
Binary files differ
diff --git a/ios/app/img/TrackingLocationOffMask@3x.png b/platform/ios/app/img/TrackingLocationOffMask@3x.png
index b609fbe84e..b609fbe84e 100644
--- a/ios/app/img/TrackingLocationOffMask@3x.png
+++ b/platform/ios/app/img/TrackingLocationOffMask@3x.png
Binary files differ
diff --git a/ios/app/img/iTunesArtwork b/platform/ios/app/img/iTunesArtwork
index ac6a0c58e8..ac6a0c58e8 100644
--- a/ios/app/img/iTunesArtwork
+++ b/platform/ios/app/img/iTunesArtwork
Binary files differ
diff --git a/ios/app/img/iTunesArtwork.png b/platform/ios/app/img/iTunesArtwork.png
index b10824b048..b10824b048 100644
--- a/ios/app/img/iTunesArtwork.png
+++ b/platform/ios/app/img/iTunesArtwork.png
Binary files differ
diff --git a/ios/app/img/iTunesArtwork@2x b/platform/ios/app/img/iTunesArtwork@2x
index fae1dad8bf..fae1dad8bf 100644
--- a/ios/app/img/iTunesArtwork@2x
+++ b/platform/ios/app/img/iTunesArtwork@2x
Binary files differ
diff --git a/ios/app/img/iTunesArtwork@2x.png b/platform/ios/app/img/iTunesArtwork@2x.png
index fdee900aa4..fdee900aa4 100644
--- a/ios/app/img/iTunesArtwork@2x.png
+++ b/platform/ios/app/img/iTunesArtwork@2x.png
Binary files differ
diff --git a/ios/app/img/settings.png b/platform/ios/app/img/settings.png
index 5d7643eef5..5d7643eef5 100644
--- a/ios/app/img/settings.png
+++ b/platform/ios/app/img/settings.png
Binary files differ
diff --git a/ios/app/img/settings@2x.png b/platform/ios/app/img/settings@2x.png
index 2bb9f0ebad..2bb9f0ebad 100644
--- a/ios/app/img/settings@2x.png
+++ b/platform/ios/app/img/settings@2x.png
Binary files differ
diff --git a/ios/app/main.m b/platform/ios/app/main.m
index 954584f141..954584f141 100644
--- a/ios/app/main.m
+++ b/platform/ios/app/main.m
diff --git a/ios/app/mapboxgl-app.gypi b/platform/ios/app/mapboxgl-app.gypi
index f154a10e9b..5f9a11873a 100644
--- a/ios/app/mapboxgl-app.gypi
+++ b/platform/ios/app/mapboxgl-app.gypi
@@ -1,6 +1,6 @@
{
'includes': [
- '../../gyp/common.gypi',
+ '../../../gyp/common.gypi',
],
'targets': [
{
@@ -10,7 +10,7 @@
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
- '<!@(find ../ios/app/img -type f)',
+ '<!@(find ../platform/ios/app/img -type f)',
'./points.geojson',
'./polyline.geojson',
'./threestates.geojson',
@@ -36,7 +36,7 @@
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos',
'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
- 'INFOPLIST_FILE': '../ios/app/app-info.plist',
+ 'INFOPLIST_FILE': '../platform/ios/app/app-info.plist',
'TARGETED_DEVICE_FAMILY': '1,2',
'COMBINE_HIDPI_IMAGES': 'NO', # disable combining @2x, @3x images into .tiff files
'COPY_PHASE_STRIP': 'NO',
diff --git a/ios/app/points.geojson b/platform/ios/app/points.geojson
index a34f53bd36..a34f53bd36 100644
--- a/ios/app/points.geojson
+++ b/platform/ios/app/points.geojson
diff --git a/ios/app/polyline.geojson b/platform/ios/app/polyline.geojson
index c104969544..c104969544 100644
--- a/ios/app/polyline.geojson
+++ b/platform/ios/app/polyline.geojson
diff --git a/ios/app/threestates.geojson b/platform/ios/app/threestates.geojson
index 9b70388782..9b70388782 100644
--- a/ios/app/threestates.geojson
+++ b/platform/ios/app/threestates.geojson
diff --git a/ios/benchmark/MBXBenchAppDelegate.h b/platform/ios/benchmark/MBXBenchAppDelegate.h
index b8f6c2e641..b8f6c2e641 100644
--- a/ios/benchmark/MBXBenchAppDelegate.h
+++ b/platform/ios/benchmark/MBXBenchAppDelegate.h
diff --git a/platform/ios/benchmark/MBXBenchAppDelegate.m b/platform/ios/benchmark/MBXBenchAppDelegate.m
new file mode 100644
index 0000000000..5da6ccfcec
--- /dev/null
+++ b/platform/ios/benchmark/MBXBenchAppDelegate.m
@@ -0,0 +1,32 @@
+#import "MBXBenchAppDelegate.h"
+#import "MBXBenchViewController.h"
+#import <Mapbox/Mapbox.h>
+
+@implementation MBXBenchAppDelegate
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ NSString* accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
+ if (accessToken) {
+ // Store to preferences so that we can launch the app later on without having to specify
+ // token.
+ [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"];
+ } else {
+ // Try to retrieve from preferences, maybe we've stored them there previously and can reuse
+ // the token.
+ accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"];
+ }
+ if (!accessToken) {
+ NSLog(@"No access token set. Mapbox vector tiles won't work.");
+ } else {
+ [MGLAccountManager setAccessToken:accessToken];
+ }
+
+ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ self.window.rootViewController = [MBXBenchViewController new];
+ [self.window makeKeyAndVisible];
+
+ return YES;
+}
+
+@end
diff --git a/ios/benchmark/MBXBenchViewController.h b/platform/ios/benchmark/MBXBenchViewController.h
index c4439be5ec..c4439be5ec 100644
--- a/ios/benchmark/MBXBenchViewController.h
+++ b/platform/ios/benchmark/MBXBenchViewController.h
diff --git a/ios/benchmark/MBXBenchViewController.mm b/platform/ios/benchmark/MBXBenchViewController.mm
index 44ca48f436..a381813ffc 100644
--- a/ios/benchmark/MBXBenchViewController.mm
+++ b/platform/ios/benchmark/MBXBenchViewController.mm
@@ -1,6 +1,6 @@
#import "MBXBenchViewController.h"
-#import <mbgl/ios/MGLMapView.h>
+#import <Mapbox/Mapbox.h>
#include "locations.hpp"
@@ -44,7 +44,7 @@
{
[super viewDidLoad];
- NSURL* url = [[NSURL alloc] initWithString:@"mapbox://styles/mapbox/streets-v8.json"];
+ NSURL* url = [[NSURL alloc] initWithString:@"mapbox://styles/mapbox/streets-v8"];
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds styleURL:url];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.mapView.delegate = self;
@@ -62,7 +62,7 @@
size_t idx = 0;
enum class State { None, WaitingForAssets, WarmingUp, Benchmarking } state = State::None;
int frames = 0;
-TimePoint started;
+std::chrono::steady_clock::time_point started;
std::vector<std::pair<std::string, double>> result;
static const int warmupDuration = 20; // frames
@@ -102,7 +102,7 @@ static const int benchmarkDuration = 200; // frames
state = State::None;
// Report FPS
- const auto duration = Microseconds(Clock::now() - started);
+ const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - started).count() ;
const auto fps = double(frames * 1e6) / duration;
result.emplace_back(mbgl::bench::locations[idx].name, fps);
NSLog(@"- FPS: %.1f", fps);
@@ -123,7 +123,7 @@ static const int benchmarkDuration = 200; // frames
{
frames = 0;
state = State::Benchmarking;
- started = Clock::now();
+ started = std::chrono::steady_clock::now();
NSLog(@"- Benchmarking for %d frames...", benchmarkDuration);
}
[mapView setNeedsGLDisplay];
diff --git a/ios/benchmark/app-info.plist b/platform/ios/benchmark/app-info.plist
index 9d0aad09e1..9d0aad09e1 100644
--- a/ios/benchmark/app-info.plist
+++ b/platform/ios/benchmark/app-info.plist
diff --git a/ios/benchmark/assets/glyphs/download.sh b/platform/ios/benchmark/assets/glyphs/download.sh
index 01ca5c63c7..01ca5c63c7 100755
--- a/ios/benchmark/assets/glyphs/download.sh
+++ b/platform/ios/benchmark/assets/glyphs/download.sh
diff --git a/ios/benchmark/assets/sprites/mapbox-streets.json b/platform/ios/benchmark/assets/sprites/mapbox-streets.json
index 488bf335de..488bf335de 100644
--- a/ios/benchmark/assets/sprites/mapbox-streets.json
+++ b/platform/ios/benchmark/assets/sprites/mapbox-streets.json
diff --git a/ios/benchmark/assets/sprites/mapbox-streets.png b/platform/ios/benchmark/assets/sprites/mapbox-streets.png
index 00925f91a2..00925f91a2 100644
--- a/ios/benchmark/assets/sprites/mapbox-streets.png
+++ b/platform/ios/benchmark/assets/sprites/mapbox-streets.png
Binary files differ
diff --git a/ios/benchmark/assets/sprites/mapbox-streets@2x.json b/platform/ios/benchmark/assets/sprites/mapbox-streets@2x.json
index 0a193fb4db..0a193fb4db 100644
--- a/ios/benchmark/assets/sprites/mapbox-streets@2x.json
+++ b/platform/ios/benchmark/assets/sprites/mapbox-streets@2x.json
diff --git a/ios/benchmark/assets/sprites/mapbox-streets@2x.png b/platform/ios/benchmark/assets/sprites/mapbox-streets@2x.png
index 0d5bd533f7..0d5bd533f7 100644
--- a/ios/benchmark/assets/sprites/mapbox-streets@2x.png
+++ b/platform/ios/benchmark/assets/sprites/mapbox-streets@2x.png
Binary files differ
diff --git a/ios/benchmark/assets/styles/streets-v8.json b/platform/ios/benchmark/assets/styles/streets-v8.json
index 4befdc121a..4befdc121a 100644
--- a/ios/benchmark/assets/styles/streets-v8.json
+++ b/platform/ios/benchmark/assets/styles/streets-v8.json
diff --git a/ios/benchmark/assets/tiles/download.sh b/platform/ios/benchmark/assets/tiles/download.sh
index f44dda18fd..f44dda18fd 100755
--- a/ios/benchmark/assets/tiles/download.sh
+++ b/platform/ios/benchmark/assets/tiles/download.sh
diff --git a/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json b/platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json
index 140aa48fa7..140aa48fa7 100644
--- a/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json
+++ b/platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6.json
diff --git a/ios/benchmark/benchmark-ios.gypi b/platform/ios/benchmark/benchmark-ios.gypi
index 4ed3535cad..5962a6b338 100644
--- a/ios/benchmark/benchmark-ios.gypi
+++ b/platform/ios/benchmark/benchmark-ios.gypi
@@ -1,6 +1,6 @@
{
'includes': [
- '../../gyp/common.gypi',
+ '../../../gyp/common.gypi',
],
'targets': [
{ 'target_name': 'ios-bench',
@@ -9,17 +9,14 @@
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
- '<!@(find ../ios/benchmark/img -type f)',
+ '<!@(find ../platform/ios/benchmark/img -type f)',
'assets/glyphs',
'assets/sprites',
'assets/tiles',
],
'dependencies': [
- 'mbgl.gyp:core',
- 'mbgl.gyp:platform-<(platform_lib)',
- 'mbgl.gyp:http-<(http_lib)',
- 'mbgl.gyp:asset-<(asset_lib)',
+ 'iossdk',
],
'sources': [
@@ -35,27 +32,47 @@
'xcode_settings': {
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS': 'iphoneos',
- 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
- 'INFOPLIST_FILE': '../ios/benchmark/app-info.plist',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
+ 'INFOPLIST_FILE': '../platform/ios/benchmark/app-info.plist',
'TARGETED_DEVICE_FAMILY': '1,2',
'COMBINE_HIDPI_IMAGES': 'NO', # don't merge @2x.png images into .tiff files
+ 'COPY_PHASE_STRIP': 'NO',
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CLANG_ENABLE_MODULES': 'YES',
+ 'LD_RUNPATH_SEARCH_PATHS': [
+ '$(inherited)',
+ '@executable_path/Frameworks',
+ ],
+ 'OTHER_LDFLAGS': [
+ '-framework CoreLocation',
+ ],
},
'configurations': {
'Debug': {
'xcode_settings': {
'CODE_SIGN_IDENTITY': 'iPhone Developer',
+ 'COPY_PHASE_STRIP': 'NO',
},
},
'Release': {
'xcode_settings': {
'CODE_SIGN_IDENTITY': 'iPhone Distribution',
- 'ARCHS': [ "arm64" ],
+ 'ARCHS': [ "armv7", "armv7s", "arm64", "i386", "x86_64" ],
+ 'COPY_PHASE_STRIP': 'YES',
},
},
},
+
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/$(FRAMEWORKS_FOLDER_PATH)',
+ 'files': [
+ '<(PRODUCT_DIR)/Mapbox.framework',
+ ],
+ 'xcode_code_sign': 1,
+ },
+ ],
}
]
}
diff --git a/ios/benchmark/img/Icon-40.png b/platform/ios/benchmark/img/Icon-40.png
index 2425133189..2425133189 100644
--- a/ios/benchmark/img/Icon-40.png
+++ b/platform/ios/benchmark/img/Icon-40.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-40@2x.png b/platform/ios/benchmark/img/Icon-40@2x.png
index b827b1e5a1..b827b1e5a1 100644
--- a/ios/benchmark/img/Icon-40@2x.png
+++ b/platform/ios/benchmark/img/Icon-40@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-40@3x.png b/platform/ios/benchmark/img/Icon-40@3x.png
index 89c7119ac6..89c7119ac6 100644
--- a/ios/benchmark/img/Icon-40@3x.png
+++ b/platform/ios/benchmark/img/Icon-40@3x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-60.png b/platform/ios/benchmark/img/Icon-60.png
index 409fad814a..409fad814a 100644
--- a/ios/benchmark/img/Icon-60.png
+++ b/platform/ios/benchmark/img/Icon-60.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-60@2x.png b/platform/ios/benchmark/img/Icon-60@2x.png
index 89c7119ac6..89c7119ac6 100644
--- a/ios/benchmark/img/Icon-60@2x.png
+++ b/platform/ios/benchmark/img/Icon-60@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-60@3x.png b/platform/ios/benchmark/img/Icon-60@3x.png
index 158bcfe27e..158bcfe27e 100644
--- a/ios/benchmark/img/Icon-60@3x.png
+++ b/platform/ios/benchmark/img/Icon-60@3x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-72.png b/platform/ios/benchmark/img/Icon-72.png
index eecd90b5eb..eecd90b5eb 100644
--- a/ios/benchmark/img/Icon-72.png
+++ b/platform/ios/benchmark/img/Icon-72.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-72@2x.png b/platform/ios/benchmark/img/Icon-72@2x.png
index ca28d1fa05..ca28d1fa05 100644
--- a/ios/benchmark/img/Icon-72@2x.png
+++ b/platform/ios/benchmark/img/Icon-72@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-76.png b/platform/ios/benchmark/img/Icon-76.png
index 0ed2a26730..0ed2a26730 100644
--- a/ios/benchmark/img/Icon-76.png
+++ b/platform/ios/benchmark/img/Icon-76.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-76@2x.png b/platform/ios/benchmark/img/Icon-76@2x.png
index 311a1658a8..311a1658a8 100644
--- a/ios/benchmark/img/Icon-76@2x.png
+++ b/platform/ios/benchmark/img/Icon-76@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-Small-50.png b/platform/ios/benchmark/img/Icon-Small-50.png
index a071034743..a071034743 100644
--- a/ios/benchmark/img/Icon-Small-50.png
+++ b/platform/ios/benchmark/img/Icon-Small-50.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-Small-50@2x.png b/platform/ios/benchmark/img/Icon-Small-50@2x.png
index 5d7c76d5e2..5d7c76d5e2 100644
--- a/ios/benchmark/img/Icon-Small-50@2x.png
+++ b/platform/ios/benchmark/img/Icon-Small-50@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-Small.png b/platform/ios/benchmark/img/Icon-Small.png
index 630d7c04c6..630d7c04c6 100644
--- a/ios/benchmark/img/Icon-Small.png
+++ b/platform/ios/benchmark/img/Icon-Small.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-Small@2x.png b/platform/ios/benchmark/img/Icon-Small@2x.png
index c0ee89211a..c0ee89211a 100644
--- a/ios/benchmark/img/Icon-Small@2x.png
+++ b/platform/ios/benchmark/img/Icon-Small@2x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon-Small@3x.png b/platform/ios/benchmark/img/Icon-Small@3x.png
index 436a8b404c..436a8b404c 100644
--- a/ios/benchmark/img/Icon-Small@3x.png
+++ b/platform/ios/benchmark/img/Icon-Small@3x.png
Binary files differ
diff --git a/ios/benchmark/img/Icon.png b/platform/ios/benchmark/img/Icon.png
index 7af0c68a38..7af0c68a38 100644
--- a/ios/benchmark/img/Icon.png
+++ b/platform/ios/benchmark/img/Icon.png
Binary files differ
diff --git a/ios/benchmark/img/Icon.svg b/platform/ios/benchmark/img/Icon.svg
index 28df6f600d..28df6f600d 100644
--- a/ios/benchmark/img/Icon.svg
+++ b/platform/ios/benchmark/img/Icon.svg
diff --git a/ios/benchmark/img/Icon@2x.png b/platform/ios/benchmark/img/Icon@2x.png
index ff5ea0c073..ff5ea0c073 100644
--- a/ios/benchmark/img/Icon@2x.png
+++ b/platform/ios/benchmark/img/Icon@2x.png
Binary files differ
diff --git a/ios/benchmark/img/iTunesArtwork.png b/platform/ios/benchmark/img/iTunesArtwork.png
index f87c8734b5..f87c8734b5 100644
--- a/ios/benchmark/img/iTunesArtwork.png
+++ b/platform/ios/benchmark/img/iTunesArtwork.png
Binary files differ
diff --git a/ios/benchmark/img/iTunesArtwork@2x.png b/platform/ios/benchmark/img/iTunesArtwork@2x.png
index 8d456a126f..8d456a126f 100644
--- a/ios/benchmark/img/iTunesArtwork@2x.png
+++ b/platform/ios/benchmark/img/iTunesArtwork@2x.png
Binary files differ
diff --git a/ios/benchmark/locations.cpp b/platform/ios/benchmark/locations.cpp
index 9f53877e40..9f53877e40 100644
--- a/ios/benchmark/locations.cpp
+++ b/platform/ios/benchmark/locations.cpp
diff --git a/ios/benchmark/locations.hpp b/platform/ios/benchmark/locations.hpp
index 96f9c6025b..96f9c6025b 100644
--- a/ios/benchmark/locations.hpp
+++ b/platform/ios/benchmark/locations.hpp
diff --git a/ios/benchmark/main.m b/platform/ios/benchmark/main.m
index 52bb445552..52bb445552 100644
--- a/ios/benchmark/main.m
+++ b/platform/ios/benchmark/main.m
diff --git a/platform/ios/bitrise.yml b/platform/ios/bitrise.yml
index 25860485a4..556d10a2bb 100644
--- a/platform/ios/bitrise.yml
+++ b/platform/ios/bitrise.yml
@@ -48,7 +48,7 @@ workflows:
title: Run Xcode Tests
run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- - project_path: "./test/ios/ios-tests.xcodeproj"
+ - project_path: "./platform/ios/test/ios-tests.xcodeproj"
- scheme: Mapbox GL Tests
- simulator_device: iPhone 6
opts:
diff --git a/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index d3c4bd5e4a..d3c4bd5e4a 100644
--- a/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
diff --git a/ios/docs/install_docs.sh b/platform/ios/docs/install_docs.sh
index 43af9432b2..c5093cb5e1 100755
--- a/ios/docs/install_docs.sh
+++ b/platform/ios/docs/install_docs.sh
@@ -19,7 +19,7 @@ echo >> ${README}
echo -n "#" >> ${README}
cat ../../CHANGELOG.md | sed -n "/^## iOS ${DOCS_VERSION}/,/^##/p" | sed '$d' >> ${README}
# Copy headers to a temporary location where we can substitute macros that appledoc doesn't understand.
-cp -r ../../include/mbgl/ios /tmp/mbgl
+cp -r ../../platform/ios/include /tmp/mbgl
perl \
-pi \
-e 's/NS_(?:(MUTABLE)_)?(ARRAY|SET|DICTIONARY)_OF\(\s*(.+?)\s*\)/NS\L\u$1\u$2\E <$3>/g' \
diff --git a/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index e2c8ff813a..e2c8ff813a 100644
--- a/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
diff --git a/ios/docs/remove_docs.sh b/platform/ios/docs/remove_docs.sh
index 747ca0a3ae..747ca0a3ae 100755
--- a/ios/docs/remove_docs.sh
+++ b/platform/ios/docs/remove_docs.sh
diff --git a/ios/framework/Info.plist b/platform/ios/framework/Info.plist
index 3bf250da27..3bf250da27 100644
--- a/ios/framework/Info.plist
+++ b/platform/ios/framework/Info.plist
diff --git a/ios/framework/Mapbox.h b/platform/ios/framework/Mapbox.h
index 11f163376a..11f163376a 100644
--- a/ios/framework/Mapbox.h
+++ b/platform/ios/framework/Mapbox.h
diff --git a/ios/framework/Mapbox.m b/platform/ios/framework/Mapbox.m
index a81ca09135..93f58b9be6 100644
--- a/ios/framework/Mapbox.m
+++ b/platform/ios/framework/Mapbox.m
@@ -1,8 +1,8 @@
#import <Mapbox/Mapbox.h>
-#import "../../platform/ios/src/NSBundle+MGLAdditions.h"
-#import "../../platform/ios/src/NSProcessInfo+MGLAdditions.h"
-#import "../../platform/darwin/NSString+MGLAdditions.h"
+#import "../src/NSBundle+MGLAdditions.h"
+#import "../src/NSProcessInfo+MGLAdditions.h"
+#import "../../darwin/src/NSString+MGLAdditions.h"
__attribute__((constructor))
static void InitializeMapbox() {
diff --git a/ios/framework/Settings.bundle/Root.plist b/platform/ios/framework/Settings.bundle/Root.plist
index 889610e152..889610e152 100644
--- a/ios/framework/Settings.bundle/Root.plist
+++ b/platform/ios/framework/Settings.bundle/Root.plist
diff --git a/ios/framework/Settings.bundle/en.lproj/Root.strings b/platform/ios/framework/Settings.bundle/en.lproj/Root.strings
index e7658d692d..e7658d692d 100644
--- a/ios/framework/Settings.bundle/en.lproj/Root.strings
+++ b/platform/ios/framework/Settings.bundle/en.lproj/Root.strings
Binary files differ
diff --git a/ios/framework/framework-ios.gypi b/platform/ios/framework/framework-ios.gypi
index 241b697523..3d733d963a 100644
--- a/ios/framework/framework-ios.gypi
+++ b/platform/ios/framework/framework-ios.gypi
@@ -1,6 +1,6 @@
{
'includes': [
- '../../gyp/common.gypi',
+ '../../../gyp/common.gypi',
],
'targets': [
{
@@ -22,7 +22,7 @@
'CURRENT_PROJECT_VERSION': '0',
'DEFINES_MODULE': 'YES',
'DYLIB_INSTALL_NAME_BASE': '@rpath',
- 'INFOPLIST_FILE': '../ios/framework/Info.plist',
+ 'INFOPLIST_FILE': '../platform/ios/framework/Info.plist',
'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
'LD_RUNPATH_SEARCH_PATHS': [
'$(inherited)',
@@ -42,7 +42,7 @@
'mac_framework_headers': [
'Mapbox.h',
- '<!@(find ../include/mbgl/{darwin,ios} -type f \! -name \'.*\' \! -name Mapbox.h)',
+ '<!@(find ../platform/{darwin,ios}/include -type f \! -name \'.*\' \! -name Mapbox.h)',
],
'sources': [
diff --git a/ios/framework/modulemap b/platform/ios/framework/modulemap
index 122db0c2b1..122db0c2b1 100644
--- a/ios/framework/modulemap
+++ b/platform/ios/framework/modulemap
diff --git a/ios/framework/strip-frameworks.sh b/platform/ios/framework/strip-frameworks.sh
index 9deb404ca1..9deb404ca1 100755
--- a/ios/framework/strip-frameworks.sh
+++ b/platform/ios/framework/strip-frameworks.sh
diff --git a/include/mbgl/ios/MGLAccountManager.h b/platform/ios/include/MGLAccountManager.h
index c52ef08607..c52ef08607 100644
--- a/include/mbgl/ios/MGLAccountManager.h
+++ b/platform/ios/include/MGLAccountManager.h
diff --git a/include/mbgl/ios/MGLAnnotationImage.h b/platform/ios/include/MGLAnnotationImage.h
index f9d9e70566..f9d9e70566 100644
--- a/include/mbgl/ios/MGLAnnotationImage.h
+++ b/platform/ios/include/MGLAnnotationImage.h
diff --git a/include/mbgl/ios/MGLCalloutView.h b/platform/ios/include/MGLCalloutView.h
index 8e72ee9d68..8e72ee9d68 100644
--- a/include/mbgl/ios/MGLCalloutView.h
+++ b/platform/ios/include/MGLCalloutView.h
diff --git a/include/mbgl/ios/MGLMapView+IBAdditions.h b/platform/ios/include/MGLMapView+IBAdditions.h
index f18df56e01..f18df56e01 100644
--- a/include/mbgl/ios/MGLMapView+IBAdditions.h
+++ b/platform/ios/include/MGLMapView+IBAdditions.h
diff --git a/include/mbgl/ios/MGLMapView+MGLCustomStyleLayerAdditions.h b/platform/ios/include/MGLMapView+MGLCustomStyleLayerAdditions.h
index de4dc01f99..de4dc01f99 100644
--- a/include/mbgl/ios/MGLMapView+MGLCustomStyleLayerAdditions.h
+++ b/platform/ios/include/MGLMapView+MGLCustomStyleLayerAdditions.h
diff --git a/include/mbgl/ios/MGLMapView.h b/platform/ios/include/MGLMapView.h
index dc03c13f7b..d974f4673e 100644
--- a/include/mbgl/ios/MGLMapView.h
+++ b/platform/ios/include/MGLMapView.h
@@ -1133,7 +1133,7 @@ IB_DESIGNABLE
- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
/**
- Returns the stroke color to use when rendering a shape annotation. Defaults to black.
+ Returns the stroke color to use when rendering a shape annotation. Defaults to the map view’s tint color.
@param mapView The map view rendering the shape annotation.
@param annotation The annotation being rendered.
@@ -1142,7 +1142,7 @@ IB_DESIGNABLE
- (UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation;
/**
- Returns the fill color to use when rendering a polygon annotation. Defaults to blue.
+ Returns the fill color to use when rendering a polygon annotation. Defaults to the map view’s tint color.
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
diff --git a/include/mbgl/ios/MGLUserLocation.h b/platform/ios/include/MGLUserLocation.h
index 6160413510..6160413510 100644
--- a/include/mbgl/ios/MGLUserLocation.h
+++ b/platform/ios/include/MGLUserLocation.h
diff --git a/include/mbgl/ios/Mapbox.h b/platform/ios/include/Mapbox.h
index fd4f532a40..fd4f532a40 100644
--- a/include/mbgl/ios/Mapbox.h
+++ b/platform/ios/include/Mapbox.h
diff --git a/ios/screenshot.png b/platform/ios/screenshot.png
index 5bea3095a6..5bea3095a6 100644
--- a/ios/screenshot.png
+++ b/platform/ios/screenshot.png
Binary files differ
diff --git a/platform/ios/scripts/benchmark.sh b/platform/ios/scripts/benchmark.sh
index 1c342e6533..cf1950ca90 100755
--- a/platform/ios/scripts/benchmark.sh
+++ b/platform/ios/scripts/benchmark.sh
@@ -8,8 +8,8 @@ if [ -z "$(which ios-deploy)" ] ; then
npm install -g ios-deploy
fi
-(cd ios/benchmark/assets/tiles && ./download.sh)
-(cd ios/benchmark/assets/glyphs && ./download.sh)
+(cd platform/ios/benchmark/assets/tiles && ./download.sh)
+(cd platform/ios/benchmark/assets/glyphs && ./download.sh)
make ibench
diff --git a/platform/ios/scripts/document.sh b/platform/ios/scripts/document.sh
index 345cfdf7ea..c470c59dbd 100755
--- a/platform/ios/scripts/document.sh
+++ b/platform/ios/scripts/document.sh
@@ -22,7 +22,7 @@ RELEASE_VERSION=$( echo ${SHORT_VERSION} | sed -e 's/^ios-v//' -e 's/-.*//' )
rm -rf /tmp/mbgl
mkdir -p /tmp/mbgl/
README=/tmp/mbgl/README.md
-cp ios/docs/doc-README.md "${README}"
+cp platform/ios/docs/doc-README.md "${README}"
# http://stackoverflow.com/a/4858011/4585461
echo "## Changes in version ${RELEASE_VERSION}" >> "${README}"
sed -n -e '/^## iOS/{' -e ':a' -e 'n' -e '/^##/q' -e 'p' -e 'ba' -e '}' CHANGELOG.md >> "${README}"
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index 4a964d4346..4c7ce7573a 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -187,19 +187,19 @@ fi
if [[ ${BUILD_STATIC} == true ]]; then
step "Copying static library headers…"
mkdir -p "${OUTPUT}/static/${NAME}.framework/Headers"
- cp -pv include/mbgl/{darwin,ios}/*.h "${OUTPUT}/static/${NAME}.framework/Headers"
- cat ios/framework/Mapbox-static.h > "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h"
- cat ios/framework/Mapbox.h >> "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h"
+ cp -pv platform/{darwin,ios}/include/*.h "${OUTPUT}/static/${NAME}.framework/Headers"
+ cat platform/ios/framework/Mapbox-static.h > "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h"
+ cat platform/ios/framework/Mapbox.h >> "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h"
fi
step "Copying library resources…"
SEM_VERSION=$( git describe --tags --match=ios-v*.*.* --abbrev=0 | sed 's/^ios-v//' )
SHORT_VERSION=${SEM_VERSION%-*}
cp -pv LICENSE.md "${OUTPUT}"
-cp -rv ios/app/Settings.bundle "${OUTPUT}"
+cp -rv platform/ios/app/Settings.bundle "${OUTPUT}"
if [[ ${BUILD_STATIC} == true ]]; then
cp -pv platform/ios/resources/* "${OUTPUT}/static/${NAME}.framework"
- cp -pv ios/framework/Info.plist "${OUTPUT}/static/${NAME}.framework/Info.plist"
+ cp -pv platform/ios/framework/Info.plist "${OUTPUT}/static/${NAME}.framework/Info.plist"
plutil -replace CFBundleExecutable -string ${NAME} "${OUTPUT}/static/${NAME}.framework/Info.plist"
plutil -replace CFBundleIdentifier -string com.mapbox.sdk.ios "${OUTPUT}/static/${NAME}.framework/Info.plist"
plutil -replace CFBundleName -string ${NAME} "${OUTPUT}/static/${NAME}.framework/Info.plist"
@@ -208,21 +208,21 @@ if [[ ${BUILD_STATIC} == true ]]; then
plutil -replace MGLSemanticVersionString -string "${SEM_VERSION}" "${OUTPUT}/static/${NAME}.framework/Info.plist"
plutil -replace MGLCommitHash -string "${HASH}" "${OUTPUT}/static/${NAME}.framework/Info.plist"
mkdir "${OUTPUT}/static/${NAME}.framework/Modules"
- cp -pv ios/framework/modulemap "${OUTPUT}/static/${NAME}.framework/Modules/module.modulemap"
+ cp -pv platform/ios/framework/modulemap "${OUTPUT}/static/${NAME}.framework/Modules/module.modulemap"
fi
if [[ ${BUILD_DYNAMIC} == true ]]; then
plutil -replace CFBundleShortVersionString -string "${SHORT_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist"
plutil -replace CFBundleVersion -string "${PROJ_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist"
plutil -replace MGLSemanticVersionString -string "${SEM_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist"
plutil -replace MGLCommitHash -string "${HASH}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist"
- cp -pv ios/framework/strip-frameworks.sh "${OUTPUT}/dynamic/${NAME}.framework/strip-frameworks.sh"
+ cp -pv platform/ios/framework/strip-frameworks.sh "${OUTPUT}/dynamic/${NAME}.framework/strip-frameworks.sh"
fi
sed -n -e '/^## iOS/,$p' CHANGELOG.md > "${OUTPUT}/CHANGELOG.md"
rm -rf /tmp/mbgl
mkdir -p /tmp/mbgl/
README=/tmp/mbgl/README.md
-cp ios/docs/pod-README.md "${README}"
+cp platform/ios/docs/pod-README.md "${README}"
if [[ ${BUILD_DYNAMIC} == false ]]; then
sed -i '' -e '/{{DYNAMIC}}/,/{{\/DYNAMIC}}/d' "${README}"
fi
diff --git a/platform/ios/scripts/test.sh b/platform/ios/scripts/test.sh
index 2192ac7f4d..630a99686d 100755
--- a/platform/ios/scripts/test.sh
+++ b/platform/ios/scripts/test.sh
@@ -5,7 +5,7 @@ set -o pipefail
set -u
xcodebuild \
- -project ./test/ios/ios-tests.xcodeproj \
+ -project ./platform/ios/test/ios-tests.xcodeproj \
-scheme 'Mapbox GL Tests' \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' \
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 83904f168f..78ab235332 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -3,7 +3,7 @@
#import "MGLMapView+MGLCustomStyleLayerAdditions.h"
#import <mbgl/platform/log.hpp>
-#import <mbgl/platform/gl.hpp>
+#import <mbgl/gl/gl.hpp>
#import <GLKit/GLKit.h>
#import <OpenGLES/EAGL.h>
@@ -28,8 +28,8 @@
#include <mbgl/util/chrono.hpp>
#import "Mapbox.h"
-#import "../../darwin/MGLGeometry_Private.h"
-#import "../../darwin/MGLMultiPoint_Private.h"
+#import "../../darwin/src/MGLGeometry_Private.h"
+#import "../../darwin/src/MGLMultiPoint_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
@@ -1566,7 +1566,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2)
{
NSString *feedbackURL = [NSString stringWithFormat:@"https://www.mapbox.com/map-feedback/#/%.5f/%.5f/%i",
- self.longitude, self.latitude, (int)round(self.zoomLevel)];
+ self.longitude, self.latitude, (int)round(self.zoomLevel + 1)];
[[UIApplication sharedApplication] openURL:
[NSURL URLWithString:feedbackURL]];
}
@@ -2487,7 +2487,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
UIColor *color = (_delegateHasStrokeColorsForShapeAnnotations
? [self.delegate mapView:self strokeColorForShapeAnnotation:annotation]
- : [UIColor blackColor]);
+ : self.tintColor);
return MGLColorObjectFromUIColor(color);
}
@@ -2495,7 +2495,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
UIColor *color = (_delegateHasFillColorsForShapeAnnotations
? [self.delegate mapView:self fillColorForPolygonAnnotation:annotation]
- : [UIColor blueColor]);
+ : self.tintColor);
return MGLColorObjectFromUIColor(color);
}
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 567b0c3c90..b792a6af39 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -275,11 +275,6 @@ const NSTimeInterval MGLFlushInterval = 60;
MGLMapboxEvents *strongSelf = weakSelf;
[strongSelf validate];
}];
-
- // Turn the Mapbox Turnstile to Count App Users
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
- [self pushTurnstileEvent];
- });
}
return self;
}
@@ -429,38 +424,42 @@ const NSTimeInterval MGLFlushInterval = 60;
}
}
+
- (void) pushTurnstileEvent {
__weak MGLMapboxEvents *weakSelf = self;
-
- dispatch_async(_serialQueue, ^{
-
- MGLMapboxEvents *strongSelf = weakSelf;
-
- if ( ! strongSelf) return;
-
- // Build only IDFV event
- NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
-
- if (!vid) return;
-
- NSDictionary *vevt = @{@"event" : MGLEventTypeAppUserTurnstile,
- @"created" : [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]],
- @"appBundleId" : strongSelf.appBundleId,
- @"vendorId": vid,
- @"version": @(version),
- @"instance": strongSelf.instanceID};
-
- // Add to Queue
- [_eventQueue addObject:vevt];
-
- // Flush
- [strongSelf flush];
-
- if ([strongSelf debugLoggingEnabled]) {
- [strongSelf writeEventToLocalDebugLog:vevt];
- }
-
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ dispatch_async(_serialQueue, ^{
+
+ MGLMapboxEvents *strongSelf = weakSelf;
+
+ if ( ! strongSelf) return;
+
+ // Build only IDFV event
+ NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+
+ if (!vid) return;
+
+ NSDictionary *vevt = @{@"event" : MGLEventTypeAppUserTurnstile,
+ @"created" : [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]],
+ @"appBundleId" : strongSelf.appBundleId,
+ @"vendorId": vid,
+ @"version": @(version),
+ @"instance": strongSelf.instanceID};
+
+ // Add to Queue
+ [_eventQueue addObject:vevt];
+
+ // Flush
+ [strongSelf flush];
+
+ if ([strongSelf debugLoggingEnabled]) {
+ [strongSelf writeEventToLocalDebugLog:vevt];
+ }
+
+ });
});
}
@@ -484,13 +483,18 @@ const NSTimeInterval MGLFlushInterval = 60;
MGLMapboxEvents *strongSelf = weakSelf;
if ( ! strongSelf) return;
+
+ if (!event) return;
+ // If it's a map load event then turn the Mapbox Turnstile to count app users
+ if ([event isEqualToString:MGLEventTypeMapLoad]) {
+ [self pushTurnstileEvent];
+ }
+
// Metrics Collection Has Been Paused
if (_paused) {
return;
}
-
- if (!event) return;
MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:attributeDictionary];
// mapbox-events stock attributes
@@ -520,6 +524,7 @@ const NSTimeInterval MGLFlushInterval = 60;
// Put On The Queue
[_eventQueue addObject:finalEvent];
+
// Has Flush Limit Been Reached?
if (_eventQueue.count >= MGLMaximumEventsPerFlush) {
diff --git a/test/ios/.gitignore b/platform/ios/test/.gitignore
index 516812b72d..516812b72d 100644
--- a/test/ios/.gitignore
+++ b/platform/ios/test/.gitignore
diff --git a/test/ios/App-Info.plist b/platform/ios/test/App-Info.plist
index 8753067af1..8753067af1 100644
--- a/test/ios/App-Info.plist
+++ b/platform/ios/test/App-Info.plist
diff --git a/test/ios/Bundle-Info.plist b/platform/ios/test/Bundle-Info.plist
index 169b6f710e..169b6f710e 100644
--- a/test/ios/Bundle-Info.plist
+++ b/platform/ios/test/Bundle-Info.plist
diff --git a/test/ios/Images.xcassets/AppIcon.appiconset/Contents.json b/platform/ios/test/Images.xcassets/AppIcon.appiconset/Contents.json
index 5008911f9e..5008911f9e 100644
--- a/test/ios/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/platform/ios/test/Images.xcassets/AppIcon.appiconset/Contents.json
diff --git a/test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Contents.json
index 628027f247..628027f247 100644
--- a/test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json
+++ b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Contents.json
diff --git a/test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
index 208eea205a..208eea205a 100644
--- a/test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
+++ b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
Binary files differ
diff --git a/test/ios/Images.xcassets/LaunchImage.launchimage/Default@2x.png b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default@2x.png
index 4438336215..4438336215 100644
--- a/test/ios/Images.xcassets/LaunchImage.launchimage/Default@2x.png
+++ b/platform/ios/test/Images.xcassets/LaunchImage.launchimage/Default@2x.png
Binary files differ
diff --git a/platform/ios/test/KIF b/platform/ios/test/KIF
new file mode 160000
+Subproject 0e56388a71b0fce94e0df58fa33f81287fa27a7
diff --git a/test/ios/KIFTestActor+MapboxGL.h b/platform/ios/test/KIFTestActor+MapboxGL.h
index d16e348486..d16e348486 100644
--- a/test/ios/KIFTestActor+MapboxGL.h
+++ b/platform/ios/test/KIFTestActor+MapboxGL.h
diff --git a/test/ios/KIFTestActor+MapboxGL.m b/platform/ios/test/KIFTestActor+MapboxGL.m
index 6c5e53f40d..6c5e53f40d 100644
--- a/test/ios/KIFTestActor+MapboxGL.m
+++ b/platform/ios/test/KIFTestActor+MapboxGL.m
diff --git a/test/ios/LaunchScreen.xib b/platform/ios/test/LaunchScreen.xib
index 238fb51b50..238fb51b50 100644
--- a/test/ios/LaunchScreen.xib
+++ b/platform/ios/test/LaunchScreen.xib
diff --git a/test/ios/MGLTAppDelegate.h b/platform/ios/test/MGLTAppDelegate.h
index c0025582ee..c0025582ee 100644
--- a/test/ios/MGLTAppDelegate.h
+++ b/platform/ios/test/MGLTAppDelegate.h
diff --git a/test/ios/MGLTAppDelegate.m b/platform/ios/test/MGLTAppDelegate.m
index b79c2f4abb..b79c2f4abb 100644
--- a/test/ios/MGLTAppDelegate.m
+++ b/platform/ios/test/MGLTAppDelegate.m
diff --git a/test/ios/MGLTViewController.h b/platform/ios/test/MGLTViewController.h
index 0be0e1ff2c..0be0e1ff2c 100644
--- a/test/ios/MGLTViewController.h
+++ b/platform/ios/test/MGLTViewController.h
diff --git a/test/ios/MGLTViewController.m b/platform/ios/test/MGLTViewController.m
index 09c60bf614..09c60bf614 100644
--- a/test/ios/MGLTViewController.m
+++ b/platform/ios/test/MGLTViewController.m
diff --git a/test/ios/MapViewTests.m b/platform/ios/test/MapViewTests.m
index 40022a1ee5..40022a1ee5 100644
--- a/test/ios/MapViewTests.m
+++ b/platform/ios/test/MapViewTests.m
diff --git a/test/ios/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h b/platform/ios/test/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h
index c20a9c2b20..c20a9c2b20 100644
--- a/test/ios/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h
+++ b/platform/ios/test/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h
diff --git a/test/ios/OCMock/OCMock/OCMArg.h b/platform/ios/test/OCMock/OCMock/OCMArg.h
index d53437cb7d..d53437cb7d 100644
--- a/test/ios/OCMock/OCMock/OCMArg.h
+++ b/platform/ios/test/OCMock/OCMock/OCMArg.h
diff --git a/test/ios/OCMock/OCMock/OCMConstraint.h b/platform/ios/test/OCMock/OCMock/OCMConstraint.h
index 777966ab7d..777966ab7d 100644
--- a/test/ios/OCMock/OCMock/OCMConstraint.h
+++ b/platform/ios/test/OCMock/OCMock/OCMConstraint.h
diff --git a/test/ios/OCMock/OCMock/OCMLocation.h b/platform/ios/test/OCMock/OCMock/OCMLocation.h
index e510db7aaf..e510db7aaf 100644
--- a/test/ios/OCMock/OCMock/OCMLocation.h
+++ b/platform/ios/test/OCMock/OCMock/OCMLocation.h
diff --git a/test/ios/OCMock/OCMock/OCMMacroState.h b/platform/ios/test/OCMock/OCMock/OCMMacroState.h
index 4b2d635086..4b2d635086 100644
--- a/test/ios/OCMock/OCMock/OCMMacroState.h
+++ b/platform/ios/test/OCMock/OCMock/OCMMacroState.h
diff --git a/test/ios/OCMock/OCMock/OCMRecorder.h b/platform/ios/test/OCMock/OCMock/OCMRecorder.h
index f56d2ca4c0..f56d2ca4c0 100644
--- a/test/ios/OCMock/OCMock/OCMRecorder.h
+++ b/platform/ios/test/OCMock/OCMock/OCMRecorder.h
diff --git a/test/ios/OCMock/OCMock/OCMStubRecorder.h b/platform/ios/test/OCMock/OCMock/OCMStubRecorder.h
index 890c9ef3bc..890c9ef3bc 100644
--- a/test/ios/OCMock/OCMock/OCMStubRecorder.h
+++ b/platform/ios/test/OCMock/OCMock/OCMStubRecorder.h
diff --git a/test/ios/OCMock/OCMock/OCMock.h b/platform/ios/test/OCMock/OCMock/OCMock.h
index f0083b3507..f0083b3507 100644
--- a/test/ios/OCMock/OCMock/OCMock.h
+++ b/platform/ios/test/OCMock/OCMock/OCMock.h
diff --git a/test/ios/OCMock/OCMock/OCMockObject.h b/platform/ios/test/OCMock/OCMock/OCMockObject.h
index 63f2bae2be..63f2bae2be 100644
--- a/test/ios/OCMock/OCMock/OCMockObject.h
+++ b/platform/ios/test/OCMock/OCMock/OCMockObject.h
diff --git a/test/ios/OCMock/libOCMock.a b/platform/ios/test/OCMock/libOCMock.a
index 9bb38e21a3..9bb38e21a3 100644
--- a/test/ios/OCMock/libOCMock.a
+++ b/platform/ios/test/OCMock/libOCMock.a
Binary files differ
diff --git a/test/ios/OHHTTPStubs/.gitignore b/platform/ios/test/OHHTTPStubs/.gitignore
index a27dff4c47..a27dff4c47 100644
--- a/test/ios/OHHTTPStubs/.gitignore
+++ b/platform/ios/test/OHHTTPStubs/.gitignore
diff --git a/test/ios/OHHTTPStubs/.travis.yml b/platform/ios/test/OHHTTPStubs/.travis.yml
index 45bfb794fd..45bfb794fd 100644
--- a/test/ios/OHHTTPStubs/.travis.yml
+++ b/platform/ios/test/OHHTTPStubs/.travis.yml
diff --git a/test/ios/OHHTTPStubs/CHANGELOG.md b/platform/ios/test/OHHTTPStubs/CHANGELOG.md
index 34f2e98990..34f2e98990 100644
--- a/test/ios/OHHTTPStubs/CHANGELOG.md
+++ b/platform/ios/test/OHHTTPStubs/CHANGELOG.md
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.h
index bf1a8f5fce..bf1a8f5fce 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.m b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.m
index 327a4d2d20..327a4d2d20 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.m
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.xib b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.xib
index bab95b860c..bab95b860c 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/MainViewController.xib
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/MainViewController.xib
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj
index d79722eabb..d79722eabb 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 68ace104de..68ace104de 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme
index 41f5f1bbc6..41f5f1bbc6 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Demo.xcscheme
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
index e23833bf24..e23833bf24 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
index cfc0e73f1c..cfc0e73f1c 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Podfile b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile
index 30504595e8..30504595e8 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Podfile
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Podfile.lock b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile.lock
index 0d7e09fc56..0d7e09fc56 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Podfile.lock
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Podfile.lock
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
index 7a6d07a0a9..7a6d07a0a9 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
index e466a30930..e466a30930 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
index 55a0a6a468..55a0a6a468 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
index f976df50d7..f976df50d7 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
index 773f3f322e..773f3f322e 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
index 81aae9624d..81aae9624d 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h
index 7a6d07a0a9..7a6d07a0a9 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/Compatibility.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
index e466a30930..e466a30930 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
index 55a0a6a468..55a0a6a468 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
index f976df50d7..f976df50d7 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
index 773f3f322e..773f3f322e 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
index 81aae9624d..81aae9624d 120000
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json
index a1bed26164..a1bed26164 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Local Podspecs/OHHTTPStubs.podspec.json
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock
index 0d7e09fc56..0d7e09fc56 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Manifest.lock
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj
index cf0b52702f..cf0b52702f 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
index 39df59c3c9..39df59c3c9 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
index b9b8578c7f..b9b8578c7f 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
index 4deafde22c..4deafde22c 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
index aa992a4adb..aa992a4adb 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
index a14c030722..a14c030722 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
index 8fb40d2e94..8fb40d2e94 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
index 6e93a65cc8..6e93a65cc8 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
index 95cf11d9fb..95cf11d9fb 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
index de1d241adc..de1d241adc 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
index 79d3603ad7..79d3603ad7 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
index 756aa4392a..756aa4392a 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m
index ade64bd1a9..ade64bd1a9 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h
index 5918510c4e..5918510c4e 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-environment.h
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh
index ea685a22b1..ea685a22b1 100755
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods-resources.sh
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig
index 722a231f1e..722a231f1e 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig
index 722a231f1e..722a231f1e 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Pods/Target Support Files/Pods/Pods.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg
index c42a21cd74..c42a21cd74 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.jpg
Binary files differ
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt
index e662f91b23..e662f91b23 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Stubs/stub.txt
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png
index 0891b7aabf..0891b7aabf 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/Default-568h@2x.png
Binary files differ
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist
index 25bfd55966..25bfd55966 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Info.plist
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch
index 20ef719789..20ef719789 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/OHHTTPStubsDemo-Prefix.pch
diff --git a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m
index 478bfb3959..478bfb3959 100644
--- a/test/ios/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/ObjC/Supporting Files/main.m
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/AppDelegate.swift b/platform/ios/test/OHHTTPStubs/Examples/Swift/AppDelegate.swift
index 58f489a7d7..58f489a7d7 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/AppDelegate.swift
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/AppDelegate.swift
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Main.storyboard b/platform/ios/test/OHHTTPStubs/Examples/Swift/Main.storyboard
index 438521ca5c..438521ca5c 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Main.storyboard
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Main.storyboard
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/MainViewController.swift b/platform/ios/test/OHHTTPStubs/Examples/Swift/MainViewController.swift
index 9133e20d46..9133e20d46 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/MainViewController.swift
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/MainViewController.swift
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj
index 48a07864e3..48a07864e3 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 919434a625..919434a625 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
index 870383aff8..870383aff8 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcodeproj/xcshareddata/xcschemes/OHHTTPStubsDemo.xcscheme
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
index cfc0e73f1c..cfc0e73f1c 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/OHHTTPStubsDemo.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Podfile b/platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile
index 17dfc0103f..17dfc0103f 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Podfile
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Podfile.lock b/platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile.lock
index 834a7de58b..834a7de58b 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Podfile.lock
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Podfile.lock
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
index 7a6d07a0a9..7a6d07a0a9 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/Compatibility.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
index e466a30930..e466a30930 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubs.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
index 55a0a6a468..55a0a6a468 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
index f976df50d7..f976df50d7 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
index 773f3f322e..773f3f322e 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHHTTPStubsResponse.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
index 81aae9624d..81aae9624d 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Private/OHHTTPStubs/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
index e466a30930..e466a30930 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubs.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
index 55a0a6a468..55a0a6a468 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
index 247257b1d8..247257b1d8 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
index 773f3f322e..773f3f322e 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHHTTPStubsResponse.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
index 6a6273c69c..6a6273c69c 120000
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Headers/Public/OHHTTPStubs/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json
index a1bed26164..a1bed26164 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Local Podspecs/OHHTTPStubs.podspec.json
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock
index 834a7de58b..834a7de58b 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Manifest.lock
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj
index c30d5eaa4d..c30d5eaa4d 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
index 699b998d1c..699b998d1c 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Pods.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs.xcscheme
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist
index cea441462f..cea441462f 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/Info.plist
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
index cf3a26e1ef..cf3a26e1ef 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
index 4deafde22c..4deafde22c 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
index aa992a4adb..aa992a4adb 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h
index d95666a8a9..d95666a8a9 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap
index 268a7c33d4..268a7c33d4 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
index a14c030722..a14c030722 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist
index c10e7eab4f..c10e7eab4f 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Info.plist
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
index 56b72965aa..56b72965aa 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
index 6e93a65cc8..6e93a65cc8 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
index 95cf11d9fb..95cf11d9fb 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-prefix.pch
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h
index 28cfb1c4c0..28cfb1c4c0 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs-umbrella.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap
index efe706e390..efe706e390 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.modulemap
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
index de1d241adc..de1d241adc 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods-OHHTTPStubs/Pods-OHHTTPStubs.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist
index 6974542586..6974542586 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Info.plist
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
index 79d3603ad7..79d3603ad7 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
index 756aa4392a..756aa4392a 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m
index ade64bd1a9..ade64bd1a9 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-dummy.m
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h
index 5918510c4e..5918510c4e 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-environment.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh
index 91e9c70b4d..91e9c70b4d 100755
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-frameworks.sh
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh
index ea685a22b1..ea685a22b1 100755
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-resources.sh
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h
index 21dcfd2c21..21dcfd2c21 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods-umbrella.h
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig
index a5a034c3e4..a5a034c3e4 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap
index 8413413077..8413413077 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.modulemap
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig
index a5a034c3e4..a5a034c3e4 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Pods/Target Support Files/Pods/Pods.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg b/platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg
index c42a21cd74..c42a21cd74 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.jpg
Binary files differ
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.txt b/platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.txt
index e662f91b23..e662f91b23 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Stubs/stub.txt
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Stubs/stub.txt
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png
index 0891b7aabf..0891b7aabf 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Default-568h@2x.png
Binary files differ
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json
index 36d2c80d88..36d2c80d88 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist
index 0ca4d80efa..0ca4d80efa 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/Info.plist
diff --git a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib
index a9be7a994c..a9be7a994c 100644
--- a/test/ios/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib
+++ b/platform/ios/test/OHHTTPStubs/Examples/Swift/Supporting Files/LaunchScreen.xib
diff --git a/test/ios/OHHTTPStubs/LICENSE b/platform/ios/test/OHHTTPStubs/LICENSE
index a83928dd2e..a83928dd2e 100644
--- a/test/ios/OHHTTPStubs/LICENSE
+++ b/platform/ios/test/OHHTTPStubs/LICENSE
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs.podspec b/platform/ios/test/OHHTTPStubs/OHHTTPStubs.podspec
index 7ddbe58e23..7ddbe58e23 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs.podspec
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs.podspec
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj
index 7b1a4fa4db..7b1a4fa4db 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 25fccc6ba4..25fccc6ba4 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme
index f5a14781a1..f5a14781a1 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs Mac Framework.xcscheme
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme
index d82274e7af..d82274e7af 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS Framework.xcscheme
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme
index 998a5b942f..998a5b942f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj/xcshareddata/xcschemes/OHHTTPStubs iOS StaticLib.xcscheme
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata
index 06ceb62b61..06ceb62b61 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
index 08de0be8d3..08de0be8d3 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Podfile b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile
index c20f4c541f..c20f4c541f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Podfile
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Podfile.lock b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile.lock
index 5896b3b3b0..5896b3b3b0 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Podfile.lock
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Podfile.lock
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h
index dfa82f6691..dfa82f6691 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m
index 1de5812ca1..1de5812ca1 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h
index 9f390294e2..9f390294e2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m
index 4ae7275480..4ae7275480 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h
index 8fed5a6891..8fed5a6891 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m
index 6413297d72..6413297d72 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFHTTPSessionManager.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h
index 5e610d887f..5e610d887f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m
index 1da148282d..1da148282d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h
index 68273da58e..68273da58e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h
index a880d75191..a880d75191 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m
index 1f97f914f3..1f97f914f3 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFSecurityPolicy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h
index 85435564c3..85435564c3 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m
index cfe609a2de..cfe609a2de 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h
index aed4549815..aed4549815 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m
index a56e8542e1..a56e8542e1 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLRequestSerialization.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h
index 030e8faed7..030e8faed7 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m
index 083d30c266..083d30c266 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLResponseSerialization.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h
index f475773d02..f475773d02 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m
index d53e6ec2db..d53e6ec2db 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/AFNetworking/AFURLSessionManager.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE
index 0616192d00..0616192d00 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/LICENSE
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md
index 13e080c096..13e080c096 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/README.md
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h
index 312d680e0d..312d680e0d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m
index c2d855a59c..c2d855a59c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h
index 1c1f8dd6f8..1c1f8dd6f8 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m
index 6627dbb1b8..6627dbb1b8 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h
index b94f1cb8e0..b94f1cb8e0 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m
index b7e2a26cb2..b7e2a26cb2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIAlertView+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h
index e6ed6de04c..e6ed6de04c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m
index a225290a25..a225290a25 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h
index 5d523636e8..5d523636e8 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m
index c06aa9ca4c..c06aa9ca4c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h
index 94082f6cb5..94082f6cb5 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIKit+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h
index 3f1bc086f5..3f1bc086f5 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m
index 927f56d843..927f56d843 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h
index 37ce772de0..37ce772de0 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m
index e266451fe5..e266451fe5 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h
index 202e8f4ea2..202e8f4ea2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m
index 525d02aead..525d02aead 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h
index ac762c8238..ac762c8238 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h
index 9dcc623c63..9dcc623c63 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperationManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h
index 56feb9fb85..56feb9fb85 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFHTTPSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h
index 67519d9848..67519d9848 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h
index 68fc7744f2..68fc7744f2 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworkReachabilityManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h
index a5a38da7dc..a5a38da7dc 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h
index fd1322db9c..fd1322db9c 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFSecurityPolicy.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h
index d9b35fb754..d9b35fb754 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h
index ca8209b81f..ca8209b81f 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLRequestSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h
index e36a765d82..e36a765d82 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLResponseSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h
index 835101de7b..835101de7b 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/AFURLSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h
index c534ebfb02..c534ebfb02 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIActivityIndicatorView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h
index f992813385..f992813385 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIAlertView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h
index 8f2e221939..8f2e221939 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIButton+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h
index a95d67380f..a95d67380f 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h
index 95017cce57..95017cce57 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIKit+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h
index 730b167dcd..730b167dcd 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIProgressView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h
index 8efd826209..8efd826209 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIRefreshControl+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h
index c8df6ef17b..c8df6ef17b 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Private/AFNetworking/UIWebView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h
index ac762c8238..ac762c8238 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h
index 9dcc623c63..9dcc623c63 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperationManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h
index 56feb9fb85..56feb9fb85 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFHTTPSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h
index 67519d9848..67519d9848 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h
index 68fc7744f2..68fc7744f2 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworkReachabilityManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h
index a5a38da7dc..a5a38da7dc 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h
index fd1322db9c..fd1322db9c 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFSecurityPolicy.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h
index d9b35fb754..d9b35fb754 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h
index ca8209b81f..ca8209b81f 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLRequestSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h
index e36a765d82..e36a765d82 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLResponseSerialization.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h
index 835101de7b..835101de7b 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/AFURLSessionManager.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h
index c534ebfb02..c534ebfb02 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIActivityIndicatorView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h
index f992813385..f992813385 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIAlertView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h
index 8f2e221939..8f2e221939 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIButton+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h
index a95d67380f..a95d67380f 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h
index 95017cce57..95017cce57 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIKit+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h
index 730b167dcd..730b167dcd 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIProgressView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h
index 8efd826209..8efd826209 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIRefreshControl+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h
index c8df6ef17b..c8df6ef17b 120000
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Headers/Public/AFNetworking/UIWebView+AFNetworking.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock
index 5896b3b3b0..5896b3b3b0 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Manifest.lock
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj
index 7c52607f05..7c52607f05 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Pods.xcodeproj/project.pbxproj
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig
index 3487d75ca9..3487d75ca9 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m
index 2de591a2e2..2de591a2e2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch
index b9c163b498..b9c163b498 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking-prefix.pch
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig
index 1fb0c387d4..1fb0c387d4 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests-AFNetworking/Pods-OHHTTPStubs Mac Tests-AFNetworking.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown
index 59a175087d..59a175087d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist
index 899e8ae43e..899e8ae43e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m
index f124d0bf53..f124d0bf53 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h
index 42c1cb9116..42c1cb9116 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-environment.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh
index ea685a22b1..ea685a22b1 100755
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests-resources.sh
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig
index 6514eaa721..6514eaa721 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig
index 6514eaa721..6514eaa721 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs Mac Tests/Pods-OHHTTPStubs Mac Tests.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig
index 8eb1a3989e..8eb1a3989e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m
index 8fb666b3d8..8fb666b3d8 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch
index aa992a4adb..aa992a4adb 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking-prefix.pch
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig
index 7f67782003..7f67782003 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking/Pods-OHHTTPStubs iOS Fmk Tests-AFNetworking.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown
index 59a175087d..59a175087d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist
index 899e8ae43e..899e8ae43e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m
index dbb179ac46..dbb179ac46 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh
index ea685a22b1..ea685a22b1 100755
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests-resources.sh
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig
index 72ec462315..72ec462315 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig
index 72ec462315..72ec462315 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Fmk Tests/Pods-OHHTTPStubs iOS Fmk Tests.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig
index 927eecdfe5..927eecdfe5 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m
index 174408f7fa..174408f7fa 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch
index aa992a4adb..aa992a4adb 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking-prefix.pch
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig
index 758125c1eb..758125c1eb 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking/Pods-OHHTTPStubs iOS Lib Tests-AFNetworking.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown
index 59a175087d..59a175087d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist
index 899e8ae43e..899e8ae43e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m
index 391f5bc28d..391f5bc28d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh
index ea685a22b1..ea685a22b1 100755
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests-resources.sh
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig
index 19fb024a98..19fb024a98 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig
index 19fb024a98..19fb024a98 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Lib Tests/Pods-OHHTTPStubs iOS Lib Tests.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig
index 6f43611720..6f43611720 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-Private.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m
index 8aa49d1389..8aa49d1389 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch
index 80fbb8dc3c..80fbb8dc3c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking-prefix.pch
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig
index b8aeea85b3..b8aeea85b3 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests-AFNetworking/Pods-OHHTTPStubs iOS Tests-AFNetworking.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown
index 59a175087d..59a175087d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.markdown
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist
index 899e8ae43e..899e8ae43e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-acknowledgements.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m
index 0fb6509a93..0fb6509a93 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-dummy.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h
index e1a5d47d3b..e1a5d47d3b 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-environment.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh
index 43f08523e1..43f08523e1 100755
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests-resources.sh
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig
index 89450f5b6a..89450f5b6a 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.debug.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig
index 89450f5b6a..89450f5b6a 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Pods/Target Support Files/Pods-OHHTTPStubs iOS Tests/Pods-OHHTTPStubs iOS Tests.release.xcconfig
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h
index b41ddda60f..b41ddda60f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h
index 2776a4f3b7..2776a4f3b7 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m
index 06d7363f23..06d7363f23 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/HTTPMessage/OHHTTPStubsResponse+HTTPMessage.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h
index 3069ff32ec..3069ff32ec 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m
index d88fee9bdd..d88fee9bdd 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/JSON/OHHTTPStubsResponse+JSON.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h
index 77fe65e892..77fe65e892 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m
index 4de8996ae0..4de8996ae0 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m
index b0e14a093c..b0e14a093c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs+NSURLSessionConfiguration.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m
index 1184dcad1f..1184dcad1f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs+NSURLSessionConfiguration.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h
index f4c2a07a98..f4c2a07a98 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m
index 4fa31f907b..4fa31f907b 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubs.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h
index 0ac0f6e124..0ac0f6e124 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m
index 03d0e7a6db..03d0e7a6db 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+HTTPMessage.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h
index fc8719df0d..fc8719df0d 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m
index aebcb99080..aebcb99080 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse+JSON.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h
index 27f487f9fa..27f487f9fa 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m
index db8d7efa79..db8d7efa79 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHHTTPStubsResponse.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h
index aa250547b8..aa250547b8 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m
index cac24a636a..cac24a636a 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h
index b3c301acdd..b3c301acdd 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.h
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m
index 18b769e45a..18b769e45a 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/OHPathHelpers/OHPathHelpers.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift
index 5229dcb808..5229dcb808 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Sources/Swift/OHHTTPStubsSwift.swift
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist
index bcee41c04a..bcee41c04a 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs Mac-Info.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist
index d3de8eefb6..d3de8eefb6 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/Supporting Files/OHHTTPStubs iOS-Info.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json
index e69de29bb2..e69de29bb2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/empty.bundle/nothingtoseehere.json
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json
index e69de29bb2..e69de29bb2 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Fixtures/emptyfile.json
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail
index 596a2ecdb4..596a2ecdb4 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/cards.tail
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail
index 1755e71d57..1755e71d57 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/login.tail
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail
index a21bc088c6..a21bc088c6 100755
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/MocktailFolder/logos_ebay.tail
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m
index 98086feeb1..98086feeb1 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/OHPathHelpersTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m
index a4ee670a6e..a4ee670a6e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/AFNetworkingTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m
index db7725703c..db7725703c 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m
index 1321854169..1321854169 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionDelegateTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m
index 1fe6c91e87..1fe6c91e87 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLConnectionTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m
index 2e829ca432..2e829ca432 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m
index ec263d543f..ec263d543f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/NilValuesTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift
index 3d2f1c3577..3d2f1c3577 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/SwiftHelpersTests.swift
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m
index b2e820f80f..b2e820f80f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/TimingTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m
index 0e34aea54f..0e34aea54f 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/Test Suites/WithContentsOfURLTests.m
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist
index 169b6f710e..169b6f710e 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Info.plist
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch
index a0a31a66c6..a0a31a66c6 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/UnitTests-Prefix.pch
diff --git a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail
index 283ca0271b..283ca0271b 100644
--- a/test/ios/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail
+++ b/platform/ios/test/OHHTTPStubs/OHHTTPStubs/UnitTests/login.tail
diff --git a/test/ios/OHHTTPStubs/README.md b/platform/ios/test/OHHTTPStubs/README.md
index 2c9c831393..2c9c831393 100644
--- a/test/ios/OHHTTPStubs/README.md
+++ b/platform/ios/test/OHHTTPStubs/README.md
diff --git a/test/ios/OHHTTPStubs/Rakefile b/platform/ios/test/OHHTTPStubs/Rakefile
index a7c7397fba..a7c7397fba 100644
--- a/test/ios/OHHTTPStubs/Rakefile
+++ b/platform/ios/test/OHHTTPStubs/Rakefile
diff --git a/test/ios/ios-tests.xcodeproj/project.pbxproj b/platform/ios/test/ios-tests.xcodeproj/project.pbxproj
index 282bcc209e..09cc7f3c31 100644
--- a/test/ios/ios-tests.xcodeproj/project.pbxproj
+++ b/platform/ios/test/ios-tests.xcodeproj/project.pbxproj
@@ -82,7 +82,7 @@
/* Begin PBXFileReference section */
96567A221B0E84CD00D78776 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = SOURCE_ROOT; };
96567A301B0E8BB900D78776 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = SOURCE_ROOT; };
- DA482C7F1C12582600772FE3 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Mapbox.framework; path = ../../build/ios/pkg/dynamic/Mapbox.framework; sourceTree = "<group>"; };
+ DA482C7F1C12582600772FE3 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Mapbox.framework; path = ../../../build/ios/pkg/dynamic/Mapbox.framework; sourceTree = "<group>"; };
DACAD7111B08719F009119DC /* MGLMapboxEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLMapboxEvents.h; path = ../../platform/ios/MGLMapboxEvents.h; sourceTree = SOURCE_ROOT; };
DADD9EB51BD16D8B00DA9161 /* Compatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Compatibility.h; path = OHHTTPStubs/OHHTTPStubs/Sources/Compatibility.h; sourceTree = SOURCE_ROOT; };
DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -539,7 +539,7 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
- "$(PROJECT_DIR)/../../build/ios/pkg/dynamic/",
+ "$(PROJECT_DIR)/../../../build/ios/pkg/dynamic/",
);
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist";
@@ -564,7 +564,7 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
- "$(PROJECT_DIR)/../../build/ios/pkg/dynamic/",
+ "$(PROJECT_DIR)/../../../build/ios/pkg/dynamic/",
);
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist";
@@ -588,7 +588,7 @@
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Mapbox GL Tests.app/Mapbox GL Tests";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
- "$(PROJECT_DIR)/../../build/ios/pkg/dynamic/",
+ "$(PROJECT_DIR)/../../../build/ios/pkg/dynamic/",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -625,7 +625,7 @@
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Mapbox GL Tests.app/Mapbox GL Tests";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
- "$(PROJECT_DIR)/../../build/ios/pkg/dynamic/",
+ "$(PROJECT_DIR)/../../../build/ios/pkg/dynamic/",
);
GCC_PREPROCESSOR_DEFINITIONS = "KIF_XCTEST=1";
HEADER_SEARCH_PATHS = (
diff --git a/test/ios/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 4cad7961db..4cad7961db 100644
--- a/test/ios/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout
index 68c68a2234..68c68a2234 100644
--- a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout
+++ b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout
diff --git a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout
index 33408b6083..33408b6083 100644
--- a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout
+++ b/platform/ios/test/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout
diff --git a/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme b/platform/ios/test/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme
index df15849ee0..df15849ee0 100644
--- a/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme
+++ b/platform/ios/test/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme
diff --git a/test/ios/main.m b/platform/ios/test/main.m
index d79750dcdd..d79750dcdd 100644
--- a/test/ios/main.m
+++ b/platform/ios/test/main.m
diff --git a/platform/linux/main.cpp b/platform/linux/main.cpp
index f90b5de849..98fb32075e 100644
--- a/platform/linux/main.cpp
+++ b/platform/linux/main.cpp
@@ -106,8 +106,6 @@ int main(int argc, char *argv[]) {
view = std::make_unique<GLFWView>(fullscreen, benchmark);
mbgl::DefaultFileSource fileSource("/tmp/mbgl-cache.db", ".");
- fileSource.setMaximumCacheEntrySize(1 * 1024 * 1024); // 1 MB
- fileSource.setMaximumCacheSize(50 * 1024 * 1024); // 50 MB
// Set access token if present
const char *token = getenv("MAPBOX_ACCESS_TOKEN");
diff --git a/platform/linux/mapboxgl-app.gypi b/platform/linux/mapboxgl-app.gypi
index 3788efba43..533f0b85d2 100644
--- a/platform/linux/mapboxgl-app.gypi
+++ b/platform/linux/mapboxgl-app.gypi
@@ -28,6 +28,7 @@
'<@(opengl_cflags)',
'<@(boost_cflags)',
'<@(glfw_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(glfw_ldflags)',
@@ -39,20 +40,27 @@
'conditions': [
['OS == "mac"', {
- 'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':'macosx',
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
- 'OTHER_LDFLAGS': [ '<@(ldflags)' ],
- 'SDKROOT': 'macosx',
'MACOSX_DEPLOYMENT_TARGET': '10.10',
- }
+ },
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
- 'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
+
+ 'link_settings': {
+ 'conditions': [
+ ['OS == "mac"', {
+ 'libraries': [ '<@(libraries)' ],
+ 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
+ }, {
+ 'libraries': [ '<@(libraries)', '<@(ldflags)' ],
+ }]
+ ],
+ },
},
],
}
diff --git a/platform/linux/scripts/coveralls.sh b/platform/linux/scripts/coveralls.sh
new file mode 100755
index 0000000000..468fa4774b
--- /dev/null
+++ b/platform/linux/scripts/coveralls.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+source ./platform/linux/scripts/setup.sh
+
+################################################################################
+# Coveralls
+################################################################################
+
+mapbox_time "make_coveralls" \
+make coveralls -j${JOBS}
diff --git a/platform/linux/scripts/run.sh b/platform/linux/scripts/run.sh
index 3e40881ec6..1c0c13968a 100755
--- a/platform/linux/scripts/run.sh
+++ b/platform/linux/scripts/run.sh
@@ -17,6 +17,9 @@ make linux -j${JOBS} BUILDTYPE=${BUILDTYPE}
mapbox_time "compile_render_binary" \
make render -j${JOBS} BUILDTYPE=${BUILDTYPE}
+mapbox_time "compile_offline_binary" \
+make offline -j${JOBS} BUILDTYPE=${BUILDTYPE}
+
mapbox_time "compile_tests" \
make test -j${JOBS} BUILDTYPE=${BUILDTYPE}
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index b8927ea334..5eefe402d6 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -25,6 +25,7 @@ struct NodeMap::RenderOptions {
unsigned int width = 512;
unsigned int height = 512;
std::vector<std::string> classes;
+ mbgl::MapDebugOptions debugOptions = mbgl::MapDebugOptions::NoDebug;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -240,6 +241,30 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
}
}
+ if (Nan::Has(obj, Nan::New("debug").ToLocalChecked()).FromJust()) {
+ auto debug = Nan::Get(obj, Nan::New("debug").ToLocalChecked()).ToLocalChecked()->ToObject().As<v8::Object>();
+ if (Nan::Has(debug, Nan::New("tileBorders").ToLocalChecked()).FromJust()) {
+ if (Nan::Get(debug, Nan::New("tileBorders").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::TileBorders;
+ }
+ }
+ if (Nan::Has(debug, Nan::New("parseStatus").ToLocalChecked()).FromJust()) {
+ if (Nan::Get(debug, Nan::New("parseStatus").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::ParseStatus;
+ }
+ }
+ if (Nan::Has(debug, Nan::New("timestamps").ToLocalChecked()).FromJust()) {
+ if (Nan::Get(debug, Nan::New("timestamps").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::Timestamps;
+ }
+ }
+ if (Nan::Has(debug, Nan::New("collision").ToLocalChecked()).FromJust()) {
+ if (Nan::Get(debug, Nan::New("collision").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::Collision;
+ }
+ }
+ }
+
return options;
}
@@ -302,6 +327,7 @@ void NodeMap::startRender(NodeMap::RenderOptions options) {
map->setLatLngZoom(mbgl::LatLng(options.latitude, options.longitude), options.zoom);
map->setBearing(options.bearing);
map->setPitch(options.pitch);
+ map->setDebug(options.debugOptions);
map->renderStill([this](const std::exception_ptr eptr, mbgl::PremultipliedImage&& result) {
if (eptr) {
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index 1c8b46b838..50d7628a2b 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -48,7 +48,7 @@ NAN_METHOD(NodeRequest::Respond) {
mbgl::Response response;
if (info.Length() < 1) {
- response.error = std::make_unique<Error>(Error::Reason::NotFound);
+ response.noContent = true;
} else if (info[0]->BooleanValue()) {
std::unique_ptr<Nan::Utf8String> message;
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index df7b5f8706..1228900940 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -41,7 +41,8 @@ test('Map', function(t) {
options.request = function() {};
t.doesNotThrow(function() {
- new mbgl.Map(options);
+ var map = new mbgl.Map(options);
+ map.release();
});
t.end();
@@ -59,7 +60,8 @@ test('Map', function(t) {
options.cancel = function() {};
t.doesNotThrow(function() {
- new mbgl.Map(options);
+ var map = new mbgl.Map(options);
+ map.release();
});
t.end();
@@ -78,7 +80,8 @@ test('Map', function(t) {
options.ratio = 1.0;
t.doesNotThrow(function() {
- new mbgl.Map(options);
+ var map = new mbgl.Map(options);
+ map.release();
});
t.end();
@@ -290,4 +293,51 @@ test('Map', function(t) {
t.end();
});
});
+
+ t.test('request callback', function (t) {
+ t.test('returning an error', function(t) {
+ var map = new mbgl.Map({
+ request: function(req, callback) {
+ callback(new Error('request error'));
+ },
+ });
+ map.load(style);
+ map.render({ zoom: 1 }, function(err, data) {
+ map.release();
+ t.ok(err, 'returns error');
+ t.equal(err.message, 'request error');
+ t.end();
+ });
+ });
+
+ t.test('returning no content for a tile', function(t) {
+ var map = new mbgl.Map({
+ request: function(req, callback) {
+ callback();
+ },
+ });
+ map.load(style);
+ map.render({ zoom: 1 }, function(err, data) {
+ map.release();
+ t.ok(data, 'no error');
+ t.end();
+ });
+ });
+
+ t.test('not holding references', function(t) {
+ var options = {
+ request: function() {},
+ ratio: 1
+ };
+
+ // We explicitly don't call release. mbgl.Map should
+ // not hold any reference to the node's main loop and
+ // prevent the test from exit.
+ var map1 = new mbgl.Map(options);
+ var map2 = new mbgl.Map(options);
+ var map3 = new mbgl.Map(options);
+
+ t.end();
+ });
+ });
});
diff --git a/platform/node/test/render.test.js b/platform/node/test/render.test.js
index ae2a55277e..05a6b2ba68 100644
--- a/platform/node/test/render.test.js
+++ b/platform/node/test/render.test.js
@@ -41,6 +41,10 @@ suite.run('native', {tests: tests}, function (style, options, callback) {
options.zoom = style.zoom;
options.bearing = style.bearing;
options.pitch = style.pitch;
+ options.debug = {
+ tileBorders: options.debug,
+ collision: options.collisionDebug
+ };
map.load(style);
map.render(options, function (err, pixels) {
diff --git a/platform/osx/INSTALL.md b/platform/osx/INSTALL.md
index 4016c360c6..e4566625eb 100644
--- a/platform/osx/INSTALL.md
+++ b/platform/osx/INSTALL.md
@@ -23,7 +23,7 @@ The Mapbox OS X SDK requires the OS X 10.10.0 SDK or above.
## Use
-The [Mapbox iOS SDK’s API documentation](https://www.mapbox.com/ios-sdk/api/3.0.1/) applies to the Mapbox OS X SDK with few differences, mostly around unimplemented features like user location tracking.
+The [Mapbox iOS SDK’s API documentation](https://www.mapbox.com/ios-sdk/api/) applies to the Mapbox OS X SDK with few differences, mostly around unimplemented features like user location tracking.
## Troubleshooting
diff --git a/platform/osx/README.md b/platform/osx/README.md
index 8a21897f64..3f9a5cd62e 100644
--- a/platform/osx/README.md
+++ b/platform/osx/README.md
@@ -4,7 +4,7 @@
A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on OS X 10.10.0 and above using Objective-C, Swift, or Interface Builder.
-This SDK is analogous to the Mapbox iOS SDK, and much of the iOS SDK documentation applies here. Mapbox does not officially support the OS X to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome.
+This SDK is analogous to the Mapbox iOS SDK, and much of the iOS SDK documentation applies here. Mapbox does not officially support the OS X SDK to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome.
* [Integrating the Mapbox OS X SDK into your application](INSTALL.md)
* [Contributing to the Mapbox OS X SDK](DEVELOPING.md)
diff --git a/platform/osx/app/MainMenu.xib b/platform/osx/app/MainMenu.xib
index 844af08f3e..64ff4e550d 100644
--- a/platform/osx/app/MainMenu.xib
+++ b/platform/osx/app/MainMenu.xib
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10109" systemVersion="15E39d" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10109"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -473,10 +473,16 @@
<action selector="dropManyPins:" target="-1" id="Rtv-8N-3Z8"/>
</connections>
</menuItem>
- <menuItem title="Remove All Pins" id="6rC-68-vk0">
+ <menuItem title="Add Polygon and Polyline" id="DVr-vT-lpe">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
- <action selector="removeAllPins:" target="-1" id="NRM-y5-Wul"/>
+ <action selector="drawPolygonAndPolyLineAnnotations:" target="-1" id="EhT-CB-gee"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Remove All Annotations" id="6rC-68-vk0">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="removeAllAnnotations:" target="-1" id="6v3-0E-LsR"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wQq-Mx-QY0"/>
@@ -545,7 +551,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="109" y="131" width="350" height="62"/>
- <rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1050"/>
<view key="contentView" id="eA4-n3-qPe">
<rect key="frame" x="0.0" y="0.0" width="350" height="62"/>
<autoresizingMask key="autoresizingMask"/>
diff --git a/platform/osx/app/MapDocument.m b/platform/osx/app/MapDocument.m
index 6881f6bd5b..7c42bc9802 100644
--- a/platform/osx/app/MapDocument.m
+++ b/platform/osx/app/MapDocument.m
@@ -33,6 +33,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
BOOL _showsToolTipsOnDroppedPins;
BOOL _randomizesCursorsOnDroppedPins;
BOOL _isTouringWorld;
+ BOOL _isShowingPolygonAndPolylineAnnotations;
}
#pragma mark Lifecycle
@@ -241,7 +242,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
}
- (IBAction)dropManyPins:(id)sender {
- [self.mapView removeAnnotations:self.mapView.annotations];
+ [self removeAllAnnotations:sender];
NSRect bounds = self.mapView.bounds;
NSMutableArray *annotations = [NSMutableArray array];
@@ -273,14 +274,15 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
}
}
-- (IBAction)removeAllPins:(id)sender {
+- (IBAction)removeAllAnnotations:(id)sender {
[self.mapView removeAnnotations:self.mapView.annotations];
+ _isShowingPolygonAndPolylineAnnotations = NO;
}
- (IBAction)startWorldTour:(id)sender {
_isTouringWorld = YES;
- [self removeAllPins:sender];
+ [self removeAllAnnotations:sender];
NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]);
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations];
for (NSUInteger i = 0; i < numberOfAnnotations; i++) {
@@ -319,6 +321,35 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
self.mapView.camera = self.mapView.camera;
}
+- (IBAction)drawPolygonAndPolyLineAnnotations:(id)sender {
+
+ if (_isShowingPolygonAndPolylineAnnotations) {
+ [self removeAllAnnotations:sender];
+ return;
+ }
+
+ _isShowingPolygonAndPolylineAnnotations = YES;
+
+ // Pacific Northwest triangle
+ CLLocationCoordinate2D triangleCoordinates[3] = {
+ CLLocationCoordinate2DMake(44, -122),
+ CLLocationCoordinate2DMake(46, -122),
+ CLLocationCoordinate2DMake(46, -121)
+ };
+ MGLPolygon *triangle = [MGLPolygon polygonWithCoordinates:triangleCoordinates count:3];
+ [self.mapView addAnnotation:triangle];
+
+ // West coast line
+ CLLocationCoordinate2D lineCoordinates[4] = {
+ CLLocationCoordinate2DMake(47.6025, -122.3327),
+ CLLocationCoordinate2DMake(45.5189, -122.6726),
+ CLLocationCoordinate2DMake(37.7790, -122.4177),
+ CLLocationCoordinate2DMake(34.0532, -118.2349)
+ };
+ MGLPolyline *line = [MGLPolyline polylineWithCoordinates:lineCoordinates count:4];
+ [self.mapView addAnnotation:line];
+}
+
#pragma mark Help methods
- (IBAction)giveFeedback:(id)sender {
@@ -457,8 +488,8 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
if (menuItem.action == @selector(dropManyPins:)) {
return YES;
}
- if (menuItem.action == @selector(removeAllPins:)) {
- return self.mapView.annotations.count;
+ if (menuItem.action == @selector(removeAllAnnotations:)) {
+ return self.mapView.annotations.count > 0;
}
if (menuItem.action == @selector(startWorldTour:)) {
return !_isTouringWorld;
@@ -466,6 +497,9 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
if (menuItem.action == @selector(stopWorldTour:)) {
return _isTouringWorld;
}
+ if (menuItem.action == @selector(drawPolygonAndPolyLineAnnotations:)) {
+ return !_isShowingPolygonAndPolylineAnnotations;
+ }
if (menuItem.action == @selector(giveFeedback:)) {
return YES;
}
diff --git a/include/mbgl/osx/MGLAccountManager.h b/platform/osx/include/MGLAccountManager.h
index efcec5419c..efcec5419c 100644
--- a/include/mbgl/osx/MGLAccountManager.h
+++ b/platform/osx/include/MGLAccountManager.h
diff --git a/include/mbgl/osx/MGLAnnotationImage.h b/platform/osx/include/MGLAnnotationImage.h
index a33ea75a5e..a33ea75a5e 100644
--- a/include/mbgl/osx/MGLAnnotationImage.h
+++ b/platform/osx/include/MGLAnnotationImage.h
diff --git a/include/mbgl/osx/MGLMapView+IBAdditions.h b/platform/osx/include/MGLMapView+IBAdditions.h
index 81f4506a57..81f4506a57 100644
--- a/include/mbgl/osx/MGLMapView+IBAdditions.h
+++ b/platform/osx/include/MGLMapView+IBAdditions.h
diff --git a/include/mbgl/osx/MGLMapView.h b/platform/osx/include/MGLMapView.h
index ca55ba7cd5..ca55ba7cd5 100644
--- a/include/mbgl/osx/MGLMapView.h
+++ b/platform/osx/include/MGLMapView.h
diff --git a/include/mbgl/osx/MGLMapViewDelegate.h b/platform/osx/include/MGLMapViewDelegate.h
index eece606c39..fcd013284d 100644
--- a/include/mbgl/osx/MGLMapViewDelegate.h
+++ b/platform/osx/include/MGLMapViewDelegate.h
@@ -104,8 +104,8 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns the color to use when rendering the outline of a shape annotation.
- The default stroke color is black. If a pattern color is specified, the
- result is undefined.
+ The default stroke color is the selected menu item color. If a pattern
+ color is specified, the result is undefined.
@param mapView The map view rendering the shape annotation.
@param annotation The annotation being rendered.
@@ -114,8 +114,8 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns the color to use when rendering the fill of a polygon annotation.
- The default fill color is blue. If a pattern color is specified, the result
- is undefined.
+ The default fill color is selected menu item color. If a pattern color
+ is specified, the result is undefined.
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
diff --git a/platform/osx/scripts/run.sh b/platform/osx/scripts/run.sh
index 6969863afd..6d00d1b977 100755
--- a/platform/osx/scripts/run.sh
+++ b/platform/osx/scripts/run.sh
@@ -12,7 +12,10 @@ BUILDTYPE=${BUILDTYPE:-Release}
################################################################################
mapbox_time "compile_render_binary" \
-make xrender -j${JOBS} BUILDTYPE=${BUILDTYPE}
+make render -j${JOBS} BUILDTYPE=${BUILDTYPE}
+
+mapbox_time "compile_offline_binary" \
+make offline -j${JOBS} BUILDTYPE=${BUILDTYPE}
mapbox_time "compile_tests" \
make xtest -j${JOBS} BUILDTYPE=${BUILDTYPE}
diff --git a/platform/osx/sdk/Mapbox.m b/platform/osx/sdk/Mapbox.m
index a96ec6df2d..58ebb408e0 100644
--- a/platform/osx/sdk/Mapbox.m
+++ b/platform/osx/sdk/Mapbox.m
@@ -3,7 +3,7 @@
#import "../src/MGLMapView_Private.h"
#import "../src/NSBundle+MGLAdditions.h"
#import "../src/NSProcessInfo+MGLAdditions.h"
-#import "../../darwin/NSString+MGLAdditions.h"
+#import "../../darwin/src/NSString+MGLAdditions.h"
__attribute__((constructor))
static void InitializeMapbox() {
diff --git a/platform/osx/sdk/framework-osx.gypi b/platform/osx/sdk/framework-osx.gypi
index 3f03f9edaf..259066f702 100644
--- a/platform/osx/sdk/framework-osx.gypi
+++ b/platform/osx/sdk/framework-osx.gypi
@@ -37,7 +37,7 @@
'mac_framework_headers': [
'./Mapbox.h',
- '<!@(find ../include/mbgl/{darwin,osx} -type f \! -name \'.*\')',
+ '<!@(find ../platform/{darwin,osx}/include -type f \! -name \'.*\')',
],
'sources': [
diff --git a/platform/osx/src/MGLAccountManager.m b/platform/osx/src/MGLAccountManager.m
index f3a2fce7cf..8458248357 100644
--- a/platform/osx/src/MGLAccountManager.m
+++ b/platform/osx/src/MGLAccountManager.m
@@ -1,6 +1,6 @@
#import "MGLAccountManager_Private.h"
-#import <mbgl/osx/MGLMapView.h>
+#import <MGLMapView.h>
@interface MGLAccountManager ()
diff --git a/platform/osx/src/MGLAccountManager_Private.h b/platform/osx/src/MGLAccountManager_Private.h
index a918f2b2d3..5088c8dfd2 100644
--- a/platform/osx/src/MGLAccountManager_Private.h
+++ b/platform/osx/src/MGLAccountManager_Private.h
@@ -1,4 +1,4 @@
-#import <mbgl/osx/MGLAccountManager.h>
+#import <MGLAccountManager.h>
@interface MGLAccountManager (Private)
diff --git a/platform/osx/src/MGLAnnotationImage.m b/platform/osx/src/MGLAnnotationImage.m
index 855105fded..e65a6d15cf 100644
--- a/platform/osx/src/MGLAnnotationImage.m
+++ b/platform/osx/src/MGLAnnotationImage.m
@@ -1,4 +1,4 @@
-#import <mbgl/osx/MGLAnnotationImage.h>
+#import <MGLAnnotationImage.h>
@interface MGLAnnotationImage ()
diff --git a/platform/osx/src/MGLMapView+IBAdditions.m b/platform/osx/src/MGLMapView+IBAdditions.m
index 2d37d29037..cafd4511f1 100644
--- a/platform/osx/src/MGLMapView+IBAdditions.m
+++ b/platform/osx/src/MGLMapView+IBAdditions.m
@@ -1,4 +1,4 @@
-#import <mbgl/osx/MGLMapView+IBAdditions.h>
+#import <MGLMapView+IBAdditions.h>
#import "MGLMapView_Private.h"
diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm
index ca282facdb..cd8cd45265 100644
--- a/platform/osx/src/MGLMapView.mm
+++ b/platform/osx/src/MGLMapView.mm
@@ -5,20 +5,20 @@
#import "MGLOpenGLLayer.h"
#import "MGLStyle.h"
-#import "../../darwin/MGLGeometry_Private.h"
-#import "../../darwin/MGLMultiPoint_Private.h"
+#import "../../darwin/src/MGLGeometry_Private.h"
+#import "../../darwin/src/MGLMultiPoint_Private.h"
-#import <mbgl/darwin/MGLMapCamera.h>
-#import <mbgl/darwin/MGLPolygon.h>
-#import <mbgl/darwin/MGLPolyline.h>
-#import <mbgl/osx/MGLAnnotationImage.h>
-#import <mbgl/osx/MGLMapViewDelegate.h>
+#import <MGLMapCamera.h>
+#import <MGLPolygon.h>
+#import <MGLPolyline.h>
+#import <MGLAnnotationImage.h>
+#import <MGLMapViewDelegate.h>
#import <mbgl/mbgl.hpp>
#import <mbgl/annotation/point_annotation.hpp>
#import <mbgl/map/camera.hpp>
#import <mbgl/platform/darwin/reachability.h>
-#import <mbgl/platform/gl.hpp>
+#import <mbgl/gl/gl.hpp>
#import <mbgl/sprite/sprite_image.hpp>
#import <mbgl/storage/default_file_source.hpp>
#import <mbgl/storage/network_status.hpp>
@@ -32,8 +32,8 @@
#import "NSBundle+MGLAdditions.h"
#import "NSProcessInfo+MGLAdditions.h"
-#import "../../darwin/NSException+MGLAdditions.h"
-#import "../../darwin/NSString+MGLAdditions.h"
+#import "../../darwin/src/NSException+MGLAdditions.h"
+#import "../../darwin/src/NSString+MGLAdditions.h"
#import <QuartzCore/QuartzCore.h>
@@ -1999,14 +1999,14 @@ public:
- (mbgl::Color)strokeColorForShapeAnnotation:(MGLShape *)annotation {
NSColor *color = (_delegateHasStrokeColorsForShapeAnnotations
? [self.delegate mapView:self strokeColorForShapeAnnotation:annotation]
- : [NSColor blackColor]);
+ : [NSColor selectedMenuItemColor]);
return MGLColorObjectFromNSColor(color);
}
- (mbgl::Color)fillColorForPolygonAnnotation:(MGLPolygon *)annotation {
NSColor *color = (_delegateHasFillColorsForShapeAnnotations
? [self.delegate mapView:self fillColorForPolygonAnnotation:annotation]
- : [NSColor blueColor]);
+ : [NSColor selectedMenuItemColor]);
return MGLColorObjectFromNSColor(color);
}
diff --git a/platform/osx/src/MGLMapView_Private.h b/platform/osx/src/MGLMapView_Private.h
index 77f2aab323..a162beca61 100644
--- a/platform/osx/src/MGLMapView_Private.h
+++ b/platform/osx/src/MGLMapView_Private.h
@@ -1,4 +1,4 @@
-#import <mbgl/osx/MGLMapView.h>
+#import <MGLMapView.h>
void mgl_linkMapViewIBCategory();
diff --git a/platform/osx/src/MGLOpenGLLayer.mm b/platform/osx/src/MGLOpenGLLayer.mm
index 06a7be961c..e8fa521351 100644
--- a/platform/osx/src/MGLOpenGLLayer.mm
+++ b/platform/osx/src/MGLOpenGLLayer.mm
@@ -2,7 +2,7 @@
#import "MGLMapView_Private.h"
-#import <mbgl/platform/gl.hpp>
+#import <mbgl/gl/gl.hpp>
@implementation MGLOpenGLLayer
diff --git a/platform/osx/test/MGLGeometryTests.mm b/platform/osx/test/MGLGeometryTests.mm
index be3c7cb2da..e6e7c4b45c 100644
--- a/platform/osx/test/MGLGeometryTests.mm
+++ b/platform/osx/test/MGLGeometryTests.mm
@@ -1,4 +1,4 @@
-#import "../../darwin/MGLGeometry_Private.h"
+#import "../../darwin/src/MGLGeometry_Private.h"
#pragma clang diagnostic ignored "-Wgnu-statement-expression"
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
diff --git a/platform/osx/test/osxtest.gypi b/platform/osx/test/osxtest.gypi
index d5d54f3c22..30bced31c4 100644
--- a/platform/osx/test/osxtest.gypi
+++ b/platform/osx/test/osxtest.gypi
@@ -48,8 +48,8 @@
],
'include_dirs': [
- '../../../include/mbgl/osx',
- '../../../include/mbgl/darwin',
+ '../../../platform/osx/include',
+ '../../../platform/darwin/include',
'../../../include',
'../../../src',
],
diff --git a/scripts/build-shaders.py b/scripts/build-shaders.py
index 226c1a2ecc..4cfb3cb384 100755
--- a/scripts/build-shaders.py
+++ b/scripts/build-shaders.py
@@ -23,7 +23,7 @@ content = """// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
#ifndef MBGL_SHADER_{NAME}_{TYPE}
#define MBGL_SHADER_{NAME}_{TYPE}
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
namespace mbgl {{
namespace shaders {{
diff --git a/scripts/collect-coverage.sh b/scripts/collect-coverage.sh
new file mode 100755
index 0000000000..0007eebd5b
--- /dev/null
+++ b/scripts/collect-coverage.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [ -z ${ENABLE_COVERAGE} ] ; then
+ echo "ENABLE_COVERAGE environment variable is not set, aborting."
+ exit 1
+fi
+
+function usage() {
+ echo "Error: LCOV and genhtml are required for generating coverage reports."
+ if [ `uname -s` = 'Linux' ]; then
+ echo "On Debian-based distros, you can install them via 'apt-get install lcov'"
+ elif [ `uname -s` = 'Darwin' ]; then
+ echo "On OS X, you can install them via 'brew install lcov'"
+ fi
+ exit 1
+}
+
+command -v lcov >/dev/null 2>&1 || usage
+command -v genhtml >/dev/null 2>&1 || usage
+
+# Zero coverage counters
+lcov \
+ --quiet \
+ --zerocounters \
+ --directory "build/${HOST_SLUG}/${BUILDTYPE}" \
+ --output-file "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info" \
+ >/dev/null 2>&1
+
+# Run all unit tests
+./scripts/run_tests.sh "build/${HOST_SLUG}/${BUILDTYPE}/test"
+
+# Collect coverage data and save it into coverage.info
+echo "Collecting coverage data..."
+lcov \
+ --quiet \
+ --capture \
+ --no-external \
+ --directory "src/mbgl" \
+ --directory "platform" \
+ --directory "include/mbgl" \
+ --directory "build/${HOST_SLUG}/${BUILDTYPE}" \
+ --base-directory "build/${HOST_SLUG}/${BUILDTYPE}" \
+ --output-file "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info" \
+ >/dev/null 2>&1
+
+# Generate HTML report based on coverage.info
+echo "Generating HTML report..."
+genhtml \
+ --quiet \
+ --show-details \
+ --keep-descriptions \
+ --function-coverage \
+ --no-branch-coverage \
+ --title "Mapbox GL Native" \
+ --num-spaces 4 \
+ --sort \
+ --demangle-cpp \
+ --prefix $(pwd -P) \
+ --output-directory "build/${HOST_SLUG}/${BUILDTYPE}/coverage" \
+ "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info" \
+ >/dev/null 2>&1
+
+echo "Coverage report is now available in build/${HOST_SLUG}/${BUILDTYPE}/coverage/index.html"
diff --git a/scripts/coveralls.sh b/scripts/coveralls.sh
new file mode 100755
index 0000000000..79e398dc1f
--- /dev/null
+++ b/scripts/coveralls.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
+
+mapbox_time "install_lcov" \
+mason install lcov 1.12
+
+LCOV="`mason prefix lcov 1.12`/usr/bin/lcov"
+
+mapbox_time "check_mason_lcov" \
+command -v $LCOV > /dev/null 2>&1 || exit 1
+
+mapbox_time "remove_coverage_info" \
+rm -f "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info"
+
+# Run all unit tests
+./scripts/run_tests.sh "build/${HOST_SLUG}/${BUILDTYPE}/test"
+
+# Collect coverage data and save it into coverage.info
+mapbox_time "lcov_capture" \
+$LCOV \
+ --quiet \
+ --capture \
+ --no-external \
+ --gcov-tool "gcov-4.9" \
+ --directory "src/mbgl" \
+ --directory "platform" \
+ --directory "include/mbgl" \
+ --directory "build/${HOST_SLUG}/${BUILDTYPE}" \
+ --base-directory "build/${HOST_SLUG}/${BUILDTYPE}" \
+ --output-file "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info"
+
+mapbox_time "coveralls_upload" \
+coveralls-lcov "build/${HOST_SLUG}/${BUILDTYPE}/coverage.info"
diff --git a/scripts/main.mk b/scripts/main.mk
index b2ba014984..0891734543 100644
--- a/scripts/main.mk
+++ b/scripts/main.mk
@@ -53,9 +53,9 @@ SUBMODULES += platform/ios/vendor/SMCalloutView/SMCalloutView.h
platform/ios/vendor/SMCalloutView/SMCalloutView.h:
./scripts/flock.py .git/Submodule.lock git submodule update --init platform/ios/vendor/SMCalloutView
-SUBMODULES += test/ios/KIF/KIF.xcodeproj
-test/ios/KIF/KIF.xcodeproj:
- ./scripts/flock.py .git/Submodule.lock git submodule update --init test/ios/KIF
+SUBMODULES += platform/ios/test/KIF/KIF.xcodeproj
+platform/ios/test/KIF/KIF.xcodeproj:
+ ./scripts/flock.py .git/Submodule.lock git submodule update --init platform/ios/test/KIF
endif
endif
@@ -78,6 +78,8 @@ GYP_FLAGS += -Dasset_lib=$(ASSET)
GYP_FLAGS += -Dheadless_lib=$(HEADLESS)
GYP_FLAGS += -Dtest=$(BUILD_TEST)
GYP_FLAGS += -Drender=$(BUILD_RENDER)
+GYP_FLAGS += -Doffline=$(BUILD_OFFLINE)
+GYP_FLAGS += -Dcoverage=$(ENABLE_COVERAGE)
GYP_FLAGS += -Dcxx_host=$(CXX_HOST)
GYP_FLAGS += --depth=.
GYP_FLAGS += -Goutput_dir=.
@@ -165,6 +167,12 @@ tidy: Ninja/compdb
test-%: Makefile/test
./scripts/run_tests.sh "build/$(HOST_SLUG)/$(BUILDTYPE)/test" --gtest_filter=$*
+check: Makefile/test
+ ./scripts/collect-coverage.sh
+
+coveralls: Makefile/test
+ ./scripts/coveralls.sh
+
#### Helper targets ############################################################
.PHONY: print-env
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index 52f8b08ad3..5f5feb456a 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -48,6 +48,16 @@ AnnotationManager::addShapeAnnotations(const std::vector<ShapeAnnotation>& shape
return annotationIDs;
}
+void AnnotationManager::updatePointAnnotation(const AnnotationID& id, const PointAnnotation& point, const uint8_t) {
+ auto foundAnnotation = pointAnnotations.find(id);
+ if (foundAnnotation != pointAnnotations.end()) {
+ auto updatedAnnotation = std::make_shared<PointAnnotationImpl>(id, point);
+ pointTree.remove(foundAnnotation->second);
+ pointTree.insert(updatedAnnotation);
+ foundAnnotation->second = updatedAnnotation;
+ }
+}
+
void AnnotationManager::removeAnnotations(const AnnotationIDs& ids) {
for (const auto& id : ids) {
if (pointAnnotations.find(id) != pointAnnotations.end()) {
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index 163c7129c7..11860047c2 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -28,6 +28,7 @@ public:
AnnotationIDs addPointAnnotations(const std::vector<PointAnnotation>&, const uint8_t maxZoom);
AnnotationIDs addShapeAnnotations(const std::vector<ShapeAnnotation>&, const uint8_t maxZoom);
+ void updatePointAnnotation(const AnnotationID&, const PointAnnotation&, const uint8_t maxZoom);
void removeAnnotations(const AnnotationIDs&);
AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const;
diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp
index a4590ffe30..3a038cc6eb 100644
--- a/src/mbgl/annotation/annotation_tile.cpp
+++ b/src/mbgl/annotation/annotation_tile.cpp
@@ -10,7 +10,7 @@ AnnotationTileFeature::AnnotationTileFeature(FeatureType type_, GeometryCollecti
std::unordered_map<std::string, std::string> properties_)
: type(type_),
properties(std::move(properties_)),
- geometries(geometries_) {}
+ geometries(std::move(geometries_)) {}
optional<Value> AnnotationTileFeature::getValue(const std::string& key) const {
auto it = properties.find(key);
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index 742a4114a8..b2d98c6a3b 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_ANNOTATION_TILE
#define MBGL_ANNOTATION_TILE
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/map/tile_id.hpp>
#include <map>
diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp
index c7278a1036..143597ed0a 100644
--- a/src/mbgl/geometry/buffer.hpp
+++ b/src/mbgl/geometry/buffer.hpp
@@ -1,12 +1,13 @@
#ifndef MBGL_GEOMETRY_BUFFER
#define MBGL_GEOMETRY_BUFFER
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/platform/log.hpp>
-#include <mbgl/util/gl_object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/thread_context.hpp>
+#include <memory>
#include <cstdlib>
#include <cassert>
#include <stdexcept>
@@ -23,10 +24,6 @@ class Buffer : private util::noncopyable {
public:
~Buffer() {
cleanup();
- if (buffer != 0) {
- util::ThreadContext::getGLObjectStore()->abandonBuffer(buffer);
- buffer = 0;
- }
}
// Returns the number of elements in this buffer. This is not the number of
@@ -40,12 +37,12 @@ public:
}
// Transfers this buffer to the GPU and binds the buffer to the GL context.
- void bind() {
+ void bind(gl::GLObjectStore& glObjectStore) {
if (buffer) {
- MBGL_CHECK_ERROR(glBindBuffer(bufferType, buffer));
+ MBGL_CHECK_ERROR(glBindBuffer(bufferType, getID()));
} else {
- MBGL_CHECK_ERROR(glGenBuffers(1, &buffer));
- MBGL_CHECK_ERROR(glBindBuffer(bufferType, buffer));
+ buffer.create(glObjectStore);
+ MBGL_CHECK_ERROR(glBindBuffer(bufferType, getID()));
if (array == nullptr) {
Log::Debug(Event::OpenGL, "Buffer doesn't contain elements");
pos = 0;
@@ -64,21 +61,21 @@ public:
}
}
- inline GLuint getID() const {
- return buffer;
+ GLuint getID() const {
+ return buffer.getID();
}
// Uploads the buffer to the GPU to be available when we need it.
- inline void upload() {
+ inline void upload(gl::GLObjectStore& glObjectStore) {
if (!buffer) {
- bind();
+ bind(glObjectStore);
}
}
protected:
// increase the buffer size by at least /required/ bytes.
inline void *addElement() {
- if (buffer != 0) {
+ if (buffer) {
throw std::runtime_error("Can't add elements after buffer was bound to GPU");
}
if (length < pos + itemSize) {
@@ -118,8 +115,8 @@ private:
// Number of bytes that are valid in this buffer.
size_t length = 0;
- // GL buffer ID
- GLuint buffer = 0;
+ // GL buffer object handle.
+ gl::BufferHolder buffer;
};
} // namespace mbgl
diff --git a/src/mbgl/geometry/circle_buffer.cpp b/src/mbgl/geometry/circle_buffer.cpp
index f4b0cddec3..74ccfa8267 100644
--- a/src/mbgl/geometry/circle_buffer.cpp
+++ b/src/mbgl/geometry/circle_buffer.cpp
@@ -1,6 +1,6 @@
#include <mbgl/geometry/circle_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <climits>
diff --git a/src/mbgl/geometry/collision_box_buffer.cpp b/src/mbgl/geometry/collision_box_buffer.cpp
index f4f8075e10..a47267d566 100644
--- a/src/mbgl/geometry/collision_box_buffer.cpp
+++ b/src/mbgl/geometry/collision_box_buffer.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/collision_box_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/math.hpp>
#include <cmath>
diff --git a/src/mbgl/geometry/debug_font_buffer.cpp b/src/mbgl/geometry/debug_font_buffer.cpp
index e4af707660..5df67accd6 100644
--- a/src/mbgl/geometry/debug_font_buffer.cpp
+++ b/src/mbgl/geometry/debug_font_buffer.cpp
@@ -1,7 +1,7 @@
#include <mbgl/geometry/debug_font_buffer.hpp>
#include <mbgl/geometry/debug_font_data.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cmath>
#include <cstring>
diff --git a/src/mbgl/geometry/fill_buffer.cpp b/src/mbgl/geometry/fill_buffer.cpp
index 3392699431..ee70dfc53b 100644
--- a/src/mbgl/geometry/fill_buffer.cpp
+++ b/src/mbgl/geometry/fill_buffer.cpp
@@ -1,6 +1,6 @@
#include <mbgl/geometry/fill_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <climits>
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index b90444e582..24c1b8c8db 100644
--- a/src/mbgl/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -2,10 +2,10 @@
#include <mbgl/text/font_stack.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/gl_object_store.hpp>
#include <mbgl/util/thread_context.hpp>
#include <cassert>
@@ -24,11 +24,6 @@ GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_)
GlyphAtlas::~GlyphAtlas() {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
-
- if (texture) {
- mbgl::util::ThreadContext::getGLObjectStore()->abandonTexture(texture);
- texture = 0;
- }
}
void GlyphAtlas::addGlyphs(uintptr_t tileUID,
@@ -151,10 +146,10 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
}
}
-void GlyphAtlas::upload() {
+void GlyphAtlas::upload(gl::GLObjectStore& glObjectStore) {
if (dirty) {
const bool first = !texture;
- bind();
+ bind(glObjectStore);
std::lock_guard<std::mutex> lock(mtx);
@@ -192,10 +187,10 @@ void GlyphAtlas::upload() {
}
}
-void GlyphAtlas::bind() {
+void GlyphAtlas::bind(gl::GLObjectStore& glObjectStore) {
if (!texture) {
- MBGL_CHECK_ERROR(glGenTextures(1, &texture));
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ texture.create(glObjectStore);
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
@@ -204,6 +199,6 @@ void GlyphAtlas::bind() {
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
} else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
}
};
diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp
index 5b4ae1fc6b..2758ac7cee 100644
--- a/src/mbgl/geometry/glyph_atlas.hpp
+++ b/src/mbgl/geometry/glyph_atlas.hpp
@@ -4,7 +4,8 @@
#include <mbgl/geometry/binpack.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <string>
#include <set>
@@ -27,11 +28,11 @@ public:
void removeGlyphs(uintptr_t tileUID);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind();
+ void bind(gl::GLObjectStore&);
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload();
+ void upload(gl::GLObjectStore&);
const GLsizei width;
const GLsizei height;
@@ -53,7 +54,7 @@ private:
std::map<std::string, std::map<uint32_t, GlyphValue>> index;
const std::unique_ptr<uint8_t[]> data;
std::atomic<bool> dirty;
- GLuint texture = 0;
+ gl::TextureHolder texture;
};
} // namespace mbgl
diff --git a/src/mbgl/geometry/icon_buffer.cpp b/src/mbgl/geometry/icon_buffer.cpp
index 4e6a1c52e7..101132ddbc 100644
--- a/src/mbgl/geometry/icon_buffer.cpp
+++ b/src/mbgl/geometry/icon_buffer.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/icon_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/math.hpp>
#include <cmath>
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index bbda2dce6f..9b133319dc 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -1,8 +1,8 @@
#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/gl_object_store.hpp>
#include <mbgl/util/thread_context.hpp>
#include <boost/functional/hash.hpp>
@@ -21,14 +21,9 @@ LineAtlas::LineAtlas(GLsizei w, GLsizei h)
LineAtlas::~LineAtlas() {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
-
- if (texture) {
- mbgl::util::ThreadContext::getGLObjectStore()->abandonTexture(texture);
- texture = 0;
- }
}
-LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round) {
+LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round, gl::GLObjectStore& glObjectStore) {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
size_t key = round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max();
@@ -39,7 +34,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b
// Note: We're not handling hash collisions here.
const auto it = positions.find(key);
if (it == positions.end()) {
- auto inserted = positions.emplace(key, addDash(dasharray, round));
+ auto inserted = positions.emplace(key, addDash(dasharray, round, glObjectStore));
assert(inserted.second);
return inserted.first->second;
} else {
@@ -47,7 +42,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b
}
}
-LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool round) {
+LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool round, gl::GLObjectStore& glObjectStore) {
int n = round ? 7 : 0;
int dashheight = 2 * n + 1;
@@ -125,31 +120,31 @@ LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool roun
nextRow += dashheight;
dirty = true;
- bind();
+ bind(glObjectStore);
return position;
};
-void LineAtlas::upload() {
+void LineAtlas::upload(gl::GLObjectStore& glObjectStore) {
if (dirty) {
- bind();
+ bind(glObjectStore);
}
}
-void LineAtlas::bind() {
+void LineAtlas::bind(gl::GLObjectStore& glObjectStore) {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
bool first = false;
if (!texture) {
- MBGL_CHECK_ERROR(glGenTextures(1, &texture));
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ texture.create(glObjectStore);
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
first = true;
} else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
}
if (dirty) {
diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp
index e76a91b61d..e94b399457 100644
--- a/src/mbgl/geometry/line_atlas.hpp
+++ b/src/mbgl/geometry/line_atlas.hpp
@@ -1,11 +1,11 @@
#ifndef MBGL_GEOMETRY_LINE_ATLAS
#define MBGL_GEOMETRY_LINE_ATLAS
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <vector>
#include <map>
-#include <memory>
namespace mbgl {
@@ -21,14 +21,14 @@ public:
~LineAtlas();
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind();
+ void bind(gl::GLObjectStore&);
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload();
+ void upload(gl::GLObjectStore&);
- LinePatternPos getDashPosition(const std::vector<float>&, bool);
- LinePatternPos addDash(const std::vector<float> &dasharray, bool round);
+ LinePatternPos getDashPosition(const std::vector<float>&, bool, gl::GLObjectStore&);
+ LinePatternPos addDash(const std::vector<float> &dasharray, bool round, gl::GLObjectStore&);
const GLsizei width;
const GLsizei height;
@@ -36,7 +36,7 @@ public:
private:
const std::unique_ptr<GLbyte[]> data;
bool dirty;
- GLuint texture = 0;
+ gl::TextureHolder texture;
int nextRow = 0;
std::map<size_t, LinePatternPos> positions;
};
diff --git a/src/mbgl/geometry/line_buffer.cpp b/src/mbgl/geometry/line_buffer.cpp
index f775a4589f..b35d3e8f47 100644
--- a/src/mbgl/geometry/line_buffer.cpp
+++ b/src/mbgl/geometry/line_buffer.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/line_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cmath>
diff --git a/src/mbgl/geometry/static_vertex_buffer.cpp b/src/mbgl/geometry/static_vertex_buffer.cpp
index e8dad0ba9b..254b01b6b6 100644
--- a/src/mbgl/geometry/static_vertex_buffer.cpp
+++ b/src/mbgl/geometry/static_vertex_buffer.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/static_vertex_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
namespace mbgl {
diff --git a/src/mbgl/geometry/text_buffer.cpp b/src/mbgl/geometry/text_buffer.cpp
index 530048a6dd..1aa65146a4 100644
--- a/src/mbgl/geometry/text_buffer.cpp
+++ b/src/mbgl/geometry/text_buffer.cpp
@@ -1,5 +1,5 @@
#include <mbgl/geometry/text_buffer.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/math.hpp>
#include <cmath>
diff --git a/src/mbgl/geometry/vao.cpp b/src/mbgl/geometry/vao.cpp
index d3ad16e64f..8239604264 100644
--- a/src/mbgl/geometry/vao.cpp
+++ b/src/mbgl/geometry/vao.cpp
@@ -1,59 +1,23 @@
#include <mbgl/geometry/vao.hpp>
#include <mbgl/platform/log.hpp>
-#include <mbgl/util/gl_object_store.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/util/thread_context.hpp>
namespace mbgl {
-static gl::ExtensionFunction<
- void (GLuint array)>
- BindVertexArray({
- {"GL_ARB_vertex_array_object", "glBindVertexArray"},
- {"GL_OES_vertex_array_object", "glBindVertexArrayOES"},
- {"GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE"}
- });
-
-static gl::ExtensionFunction<
- void (GLsizei n,
- const GLuint* arrays)>
- DeleteVertexArrays({
- {"GL_ARB_vertex_array_object", "glDeleteVertexArrays"},
- {"GL_OES_vertex_array_object", "glDeleteVertexArraysOES"},
- {"GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE"}
- });
-
-static gl::ExtensionFunction<
- void (GLsizei n,
- GLuint* arrays)>
- GenVertexArrays({
- {"GL_ARB_vertex_array_object", "glGenVertexArrays"},
- {"GL_OES_vertex_array_object", "glGenVertexArraysOES"},
- {"GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE"}
- });
-
void VertexArrayObject::Unbind() {
- if (!BindVertexArray) return;
- MBGL_CHECK_ERROR(BindVertexArray(0));
-}
-
-void VertexArrayObject::Delete(GLsizei n, const GLuint* arrays) {
- MBGL_CHECK_ERROR(DeleteVertexArrays(n, arrays));
+ if (!gl::BindVertexArray) return;
+ MBGL_CHECK_ERROR(gl::BindVertexArray(0));
}
VertexArrayObject::VertexArrayObject() {
}
VertexArrayObject::~VertexArrayObject() {
- if (!DeleteVertexArrays) return;
-
- if (vao) {
- util::ThreadContext::getGLObjectStore()->abandonVAO(vao);
- }
}
-void VertexArrayObject::bindVertexArrayObject() {
- if (!GenVertexArrays || !BindVertexArray) {
+void VertexArrayObject::bindVertexArrayObject(gl::GLObjectStore& glObjectStore) {
+ if (!gl::GenVertexArrays || !gl::BindVertexArray) {
static bool reported = false;
if (!reported) {
Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
@@ -62,10 +26,8 @@ void VertexArrayObject::bindVertexArrayObject() {
return;
}
- if (!vao) {
- MBGL_CHECK_ERROR(GenVertexArrays(1, &vao));
- }
- MBGL_CHECK_ERROR(BindVertexArray(vao));
+ if (!vao) vao.create(glObjectStore);
+ MBGL_CHECK_ERROR(gl::BindVertexArray(vao.getID()));
}
void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer,
diff --git a/src/mbgl/geometry/vao.hpp b/src/mbgl/geometry/vao.hpp
index 2dcc02c76b..dcb66dd41d 100644
--- a/src/mbgl/geometry/vao.hpp
+++ b/src/mbgl/geometry/vao.hpp
@@ -2,26 +2,28 @@
#define MBGL_GEOMETRY_VAO
#include <mbgl/shader/shader.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <stdexcept>
namespace mbgl {
+class Shader;
+
class VertexArrayObject : public util::noncopyable {
public:
static void Unbind();
- static void Delete(GLsizei n, const GLuint* arrays);
VertexArrayObject();
~VertexArrayObject();
template <typename Shader, typename VertexBuffer>
- inline void bind(Shader& shader, VertexBuffer &vertexBuffer, GLbyte *offset) {
- bindVertexArrayObject();
+ inline void bind(Shader& shader, VertexBuffer &vertexBuffer, GLbyte *offset, gl::GLObjectStore& glObjectStore) {
+ bindVertexArrayObject(glObjectStore);
if (bound_shader == 0) {
- vertexBuffer.bind();
+ vertexBuffer.bind(glObjectStore);
shader.bind(offset);
if (vao) {
storeBinding(shader, vertexBuffer.getID(), 0, offset);
@@ -32,11 +34,11 @@ public:
}
template <typename Shader, typename VertexBuffer, typename ElementsBuffer>
- inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, GLbyte *offset) {
- bindVertexArrayObject();
+ inline void bind(Shader& shader, VertexBuffer &vertexBuffer, ElementsBuffer &elementsBuffer, GLbyte *offset, gl::GLObjectStore& glObjectStore) {
+ bindVertexArrayObject(glObjectStore);
if (bound_shader == 0) {
- vertexBuffer.bind();
- elementsBuffer.bind();
+ vertexBuffer.bind(glObjectStore);
+ elementsBuffer.bind(glObjectStore);
shader.bind(offset);
if (vao) {
storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
@@ -46,16 +48,16 @@ public:
}
}
- inline GLuint getID() const {
- return vao;
+ GLuint getID() const {
+ return vao.getID();
}
private:
- void bindVertexArrayObject();
+ void bindVertexArrayObject(gl::GLObjectStore&);
void storeBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, GLbyte *offset);
void verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, GLbyte *offset);
- GLuint vao = 0;
+ gl::VAOHolder vao;
// For debug reasons, we're storing the bind information so that we can
// detect errors and report
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index fb9e037714..e61de42bc3 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -1,5 +1,5 @@
#include <mbgl/gl/debugging.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/platform/event.hpp>
#include <mbgl/platform/log.hpp>
diff --git a/src/mbgl/platform/gl.cpp b/src/mbgl/gl/gl.cpp
index e5495c80dc..c57717aa87 100644
--- a/src/mbgl/platform/gl.cpp
+++ b/src/mbgl/gl/gl.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/platform/log.hpp>
diff --git a/src/mbgl/renderer/gl_config.cpp b/src/mbgl/gl/gl_config.cpp
index 4160ae100e..4160ae100e 100644
--- a/src/mbgl/renderer/gl_config.cpp
+++ b/src/mbgl/gl/gl_config.cpp
diff --git a/src/mbgl/gl/gl_config.hpp b/src/mbgl/gl/gl_config.hpp
new file mode 100644
index 0000000000..af373fc3f8
--- /dev/null
+++ b/src/mbgl/gl/gl_config.hpp
@@ -0,0 +1,100 @@
+#ifndef MBGL_GL_GL_CONFIG
+#define MBGL_GL_GL_CONFIG
+
+#include <cstdint>
+#include <tuple>
+#include <array>
+
+#include <mbgl/gl/gl_values.hpp>
+
+namespace mbgl {
+namespace gl {
+
+template <typename T>
+class Value {
+public:
+ inline void operator=(const typename T::Type& value) {
+ if (dirty || current != value) {
+ dirty = false;
+ current = value;
+ T::Set(current);
+ }
+ }
+
+ inline void reset() {
+ dirty = true;
+ current = T::Default;
+ T::Set(current);
+ }
+
+ inline void setDirty() {
+ dirty = true;
+ }
+
+private:
+ typename T::Type current = T::Default;
+ bool dirty = false;
+};
+
+class Config {
+public:
+ void reset() {
+ stencilFunc.reset();
+ stencilMask.reset();
+ stencilTest.reset();
+ stencilOp.reset();
+ depthRange.reset();
+ depthMask.reset();
+ depthTest.reset();
+ depthFunc.reset();
+ blend.reset();
+ blendFunc.reset();
+ colorMask.reset();
+ clearDepth.reset();
+ clearColor.reset();
+ clearStencil.reset();
+ program.reset();
+ lineWidth.reset();
+ }
+
+ void setDirty() {
+ stencilFunc.setDirty();
+ stencilMask.setDirty();
+ stencilTest.setDirty();
+ stencilOp.setDirty();
+ depthRange.setDirty();
+ depthMask.setDirty();
+ depthTest.setDirty();
+ depthFunc.setDirty();
+ blend.setDirty();
+ blendFunc.setDirty();
+ colorMask.setDirty();
+ clearDepth.setDirty();
+ clearColor.setDirty();
+ clearStencil.setDirty();
+ program.setDirty();
+ lineWidth.setDirty();
+ }
+
+ Value<StencilFunc> stencilFunc;
+ Value<StencilMask> stencilMask;
+ Value<StencilTest> stencilTest;
+ Value<StencilOp> stencilOp;
+ Value<DepthRange> depthRange;
+ Value<DepthMask> depthMask;
+ Value<DepthTest> depthTest;
+ Value<DepthFunc> depthFunc;
+ Value<Blend> blend;
+ Value<BlendFunc> blendFunc;
+ Value<ColorMask> colorMask;
+ Value<ClearDepth> clearDepth;
+ Value<ClearColor> clearColor;
+ Value<ClearStencil> clearStencil;
+ Value<Program> program;
+ Value<LineWidth> lineWidth;
+};
+
+} // namespace gl
+} // namespace mbgl
+
+#endif // MBGL_RENDERER_GL_CONFIG
diff --git a/src/mbgl/gl/gl_object_store.cpp b/src/mbgl/gl/gl_object_store.cpp
new file mode 100644
index 0000000000..4948e20694
--- /dev/null
+++ b/src/mbgl/gl/gl_object_store.cpp
@@ -0,0 +1,120 @@
+#include <mbgl/gl/gl_object_store.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+namespace gl {
+
+void ProgramHolder::create(GLObjectStore& objectStore_) {
+ if (id) return;
+ objectStore = &objectStore_;
+ id = MBGL_CHECK_ERROR(glCreateProgram());
+}
+
+void ProgramHolder::reset() {
+ if (!id) return;
+ objectStore->abandonedPrograms.push_back(id);
+ id = 0;
+}
+
+void ShaderHolder::create(GLObjectStore& objectStore_) {
+ if (id) return;
+ objectStore = &objectStore_;
+ id = MBGL_CHECK_ERROR(glCreateShader(type));
+}
+
+void ShaderHolder::reset() {
+ if (!id) return;
+ objectStore->abandonedShaders.push_back(id);
+ id = 0;
+}
+
+void BufferHolder::create(GLObjectStore& objectStore_) {
+ if (id) return;
+ objectStore = &objectStore_;
+ MBGL_CHECK_ERROR(glGenBuffers(1, &id));
+}
+
+void BufferHolder::reset() {
+ if (!id) return;
+ objectStore->abandonedBuffers.push_back(id);
+ id = 0;
+}
+
+void TextureHolder::create(GLObjectStore& objectStore_) {
+ if (id) return;
+ objectStore = &objectStore_;
+ MBGL_CHECK_ERROR(glGenTextures(1, &id));
+}
+
+void TextureHolder::reset() {
+ if (!id) return;
+ objectStore->abandonedTextures.push_back(id);
+ id = 0;
+}
+
+void TexturePoolHolder::create(GLObjectStore& objectStore_) {
+ if (bool()) return;
+ objectStore = &objectStore_;
+ MBGL_CHECK_ERROR(glGenTextures(TextureMax, ids.data()));
+}
+
+void TexturePoolHolder::reset() {
+ if (!bool()) return;
+ for (GLuint id : ids) {
+ if (id) {
+ objectStore->abandonedTextures.push_back(id);
+ }
+ }
+ ids.fill(0);
+}
+
+void VAOHolder::create(GLObjectStore& objectStore_) {
+ if (id) return;
+ objectStore = &objectStore_;
+ MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
+}
+
+void VAOHolder::reset() {
+ if (!id) return;
+ objectStore->abandonedVAOs.push_back(id);
+ id = 0;
+}
+
+GLObjectStore::~GLObjectStore() {
+ assert(abandonedPrograms.empty());
+ assert(abandonedShaders.empty());
+ assert(abandonedBuffers.empty());
+ assert(abandonedTextures.empty());
+ assert(abandonedVAOs.empty());
+}
+
+void GLObjectStore::performCleanup() {
+ for (GLuint id : abandonedPrograms) {
+ MBGL_CHECK_ERROR(glDeleteProgram(id));
+ }
+ abandonedPrograms.clear();
+
+ for (GLuint id : abandonedShaders) {
+ MBGL_CHECK_ERROR(glDeleteShader(id));
+ }
+ abandonedShaders.clear();
+
+ if (!abandonedBuffers.empty()) {
+ MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data()));
+ abandonedBuffers.clear();
+ }
+
+ if (!abandonedTextures.empty()) {
+ MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data()));
+ abandonedTextures.clear();
+ }
+
+ if (!abandonedVAOs.empty()) {
+ MBGL_CHECK_ERROR(gl::DeleteVertexArrays(int(abandonedVAOs.size()), abandonedVAOs.data()));
+ abandonedVAOs.clear();
+ }
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/gl_object_store.hpp b/src/mbgl/gl/gl_object_store.hpp
new file mode 100644
index 0000000000..832f1d09b3
--- /dev/null
+++ b/src/mbgl/gl/gl_object_store.hpp
@@ -0,0 +1,141 @@
+#ifndef MBGL_MAP_UTIL_GL_OBJECT_STORE
+#define MBGL_MAP_UTIL_GL_OBJECT_STORE
+
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <array>
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+namespace mbgl {
+namespace gl {
+
+class GLObjectStore : private util::noncopyable {
+public:
+ ~GLObjectStore();
+
+ // Actually remove the objects we marked as abandoned with the above methods.
+ // Only call this while the OpenGL context is exclusive to this thread.
+ void performCleanup();
+
+private:
+ friend class ProgramHolder;
+ friend class ShaderHolder;
+ friend class BufferHolder;
+ friend class TextureHolder;
+ friend class TexturePoolHolder;
+ friend class VAOHolder;
+
+ std::vector<GLuint> abandonedPrograms;
+ std::vector<GLuint> abandonedShaders;
+ std::vector<GLuint> abandonedBuffers;
+ std::vector<GLuint> abandonedTextures;
+ std::vector<GLuint> abandonedVAOs;
+};
+
+class GLHolder : private util::noncopyable {
+public:
+ GLHolder() {}
+
+ GLHolder(GLHolder&& o) noexcept : id(o.id) { o.id = 0; }
+ GLHolder& operator=(GLHolder&& o) noexcept { id = o.id; o.id = 0; return *this; }
+
+ explicit operator bool() const { return id; }
+ GLuint getID() const { return id; }
+
+protected:
+ GLuint id = 0;
+ GLObjectStore* objectStore = nullptr;
+};
+
+class ProgramHolder : public GLHolder {
+public:
+ ProgramHolder() = default;
+ ~ProgramHolder() { reset(); }
+
+ ProgramHolder(ProgramHolder&& o) noexcept : GLHolder(std::move(o)) {}
+ ProgramHolder& operator=(ProgramHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; }
+
+ void create(GLObjectStore&);
+ void reset();
+};
+
+class ShaderHolder : public GLHolder {
+public:
+ ShaderHolder(GLenum type_) : type(type_) {}
+ ~ShaderHolder() { reset(); }
+
+ ShaderHolder(ShaderHolder&& o) noexcept : GLHolder(std::move(o)), type(o.type) {}
+ ShaderHolder& operator=(ShaderHolder&& o) noexcept { GLHolder::operator=(std::move(o)); type = o.type; return *this; }
+
+ void create(GLObjectStore&);
+ void reset();
+
+private:
+ GLenum type = 0;
+};
+
+class BufferHolder : public GLHolder {
+public:
+ BufferHolder() = default;
+ ~BufferHolder() { reset(); }
+
+ BufferHolder(BufferHolder&& o) noexcept : GLHolder(std::move(o)) {}
+ BufferHolder& operator=(BufferHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; }
+
+ void create(GLObjectStore&);
+ void reset();
+};
+
+class TextureHolder : public GLHolder {
+public:
+ TextureHolder() = default;
+ ~TextureHolder() { reset(); }
+
+ TextureHolder(TextureHolder&& o) noexcept : GLHolder(std::move(o)) {}
+ TextureHolder& operator=(TextureHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; }
+
+ void create(GLObjectStore&);
+ void reset();
+};
+
+class TexturePoolHolder : private util::noncopyable {
+public:
+ static const GLsizei TextureMax = 64;
+
+ TexturePoolHolder() { ids.fill(0); }
+ ~TexturePoolHolder() { reset(); }
+
+ TexturePoolHolder(TexturePoolHolder&& o) noexcept : ids(std::move(o.ids)) {}
+ TexturePoolHolder& operator=(TexturePoolHolder&& o) noexcept { ids = std::move(o.ids); return *this; }
+
+ explicit operator bool() { return std::none_of(ids.begin(), ids.end(), [](int id) { return id == 0; }); }
+ const std::array<GLuint, TextureMax>& getIDs() const { return ids; }
+ const GLuint& operator[](size_t pos) { return ids[pos]; }
+
+ void create(GLObjectStore&);
+ void reset();
+
+private:
+ std::array<GLuint, TextureMax> ids;
+ GLObjectStore* objectStore = nullptr;
+};
+
+class VAOHolder : public GLHolder {
+public:
+ VAOHolder() = default;
+ ~VAOHolder() { reset(); }
+
+ VAOHolder(VAOHolder&& o) noexcept : GLHolder(std::move(o)) {}
+ VAOHolder& operator=(VAOHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; }
+
+ void create(GLObjectStore&);
+ void reset();
+};
+
+} // namespace gl
+} // namespace mbgl
+
+#endif
diff --git a/src/mbgl/gl/texture_pool.cpp b/src/mbgl/gl/texture_pool.cpp
new file mode 100644
index 0000000000..a875f4d579
--- /dev/null
+++ b/src/mbgl/gl/texture_pool.cpp
@@ -0,0 +1,41 @@
+#include <mbgl/gl/texture_pool.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
+
+#include <vector>
+
+namespace mbgl {
+namespace gl {
+
+GLuint TexturePool::getTextureID(gl::GLObjectStore& glObjectStore) {
+ for (auto& impl : pools) {
+ if (impl.ids.empty()) continue;
+ auto it = impl.ids.begin();
+ GLuint id = *it;
+ impl.ids.erase(it);
+ return id;
+ }
+
+ // All texture IDs are in use.
+ pools.emplace_back(Impl(glObjectStore));
+ auto it = pools.back().ids.begin();
+ GLuint id = *it;
+ pools.back().ids.erase(it);
+ return id;
+}
+
+void TexturePool::releaseTextureID(GLuint id) {
+ for (auto it = pools.begin(); it != pools.end(); ++it) {
+ for (GLsizei i = 0; i < gl::TexturePoolHolder::TextureMax; ++i) {
+ if (it->pool[i] == id) {
+ it->ids.push_back(id);
+ if (GLsizei(it->ids.size()) == gl::TexturePoolHolder::TextureMax) {
+ pools.erase(it);
+ }
+ return;
+ }
+ }
+ }
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/texture_pool.hpp b/src/mbgl/gl/texture_pool.hpp
new file mode 100644
index 0000000000..10f63bfac9
--- /dev/null
+++ b/src/mbgl/gl/texture_pool.hpp
@@ -0,0 +1,41 @@
+#ifndef MBGL_UTIL_TEXTUREPOOL
+#define MBGL_UTIL_TEXTUREPOOL
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+namespace mbgl {
+namespace gl {
+
+class TexturePool : private util::noncopyable {
+public:
+ GLuint getTextureID(gl::GLObjectStore&);
+ void releaseTextureID(GLuint);
+
+private:
+ class Impl : private util::noncopyable {
+ public:
+ Impl(gl::GLObjectStore& glObjectStore) : ids(gl::TexturePoolHolder::TextureMax) {
+ pool.create(glObjectStore);
+ std::copy(pool.getIDs().begin(), pool.getIDs().end(), ids.begin());
+ }
+
+ Impl(Impl&& o) : pool(std::move(o.pool)), ids(std::move(o.ids)) {}
+ Impl& operator=(Impl&& o) { pool = std::move(o.pool); ids = std::move(o.ids); return *this; }
+
+ gl::TexturePoolHolder pool;
+ std::vector<GLuint> ids;
+ };
+
+ std::vector<Impl> pools;
+};
+
+} // namespace gl
+} // namespace mbgl
+
+#endif
diff --git a/src/mbgl/layer/background_layer.hpp b/src/mbgl/layer/background_layer.hpp
index 063331fade..118bb19053 100644
--- a/src/mbgl/layer/background_layer.hpp
+++ b/src/mbgl/layer/background_layer.hpp
@@ -15,6 +15,7 @@ public:
class BackgroundLayer : public StyleLayer {
public:
+ BackgroundLayer() : StyleLayer(Type::Background) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override {};
@@ -28,6 +29,11 @@ public:
BackgroundPaintProperties paint;
};
+template <>
+inline bool StyleLayer::is<BackgroundLayer>() const {
+ return type == Type::Background;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/circle_layer.hpp b/src/mbgl/layer/circle_layer.hpp
index 03169ca065..036bf79991 100644
--- a/src/mbgl/layer/circle_layer.hpp
+++ b/src/mbgl/layer/circle_layer.hpp
@@ -22,6 +22,7 @@ public:
class CircleLayer : public StyleLayer {
public:
+ CircleLayer() : StyleLayer(Type::Circle) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override {};
@@ -35,6 +36,11 @@ public:
CirclePaintProperties paint;
};
+template <>
+inline bool StyleLayer::is<CircleLayer>() const {
+ return type == Type::Circle;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/custom_layer.cpp b/src/mbgl/layer/custom_layer.cpp
index 39742ecad8..0b6de51e67 100644
--- a/src/mbgl/layer/custom_layer.cpp
+++ b/src/mbgl/layer/custom_layer.cpp
@@ -8,7 +8,8 @@ CustomLayer::CustomLayer(const std::string& id_,
CustomLayerInitializeFunction initializeFn_,
CustomLayerRenderFunction renderFn_,
CustomLayerDeinitializeFunction deinitializeFn_,
- void * context_) {
+ void* context_)
+ : StyleLayer(Type::Custom) {
id = id_;
initializeFn = initializeFn_;
renderFn = renderFn_;
diff --git a/src/mbgl/layer/custom_layer.hpp b/src/mbgl/layer/custom_layer.hpp
index 315d158802..b54ac7481e 100644
--- a/src/mbgl/layer/custom_layer.hpp
+++ b/src/mbgl/layer/custom_layer.hpp
@@ -38,6 +38,11 @@ private:
void* context = nullptr;
};
+template <>
+inline bool StyleLayer::is<CustomLayer>() const {
+ return type == Type::Custom;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/fill_layer.hpp b/src/mbgl/layer/fill_layer.hpp
index ee079a5c8a..3b1c5a84fe 100644
--- a/src/mbgl/layer/fill_layer.hpp
+++ b/src/mbgl/layer/fill_layer.hpp
@@ -19,6 +19,7 @@ public:
class FillLayer : public StyleLayer {
public:
+ FillLayer() : StyleLayer(Type::Fill) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override {};
@@ -32,6 +33,11 @@ public:
FillPaintProperties paint;
};
+template <>
+inline bool StyleLayer::is<FillLayer>() const {
+ return type == Type::Fill;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/line_layer.cpp b/src/mbgl/layer/line_layer.cpp
index 8454eb2664..edf128fd35 100644
--- a/src/mbgl/layer/line_layer.cpp
+++ b/src/mbgl/layer/line_layer.cpp
@@ -69,7 +69,7 @@ bool LineLayer::recalculate(const StyleCalculationParameters& parameters) {
}
std::unique_ptr<Bucket> LineLayer::createBucket(StyleBucketParameters& parameters) const {
- auto bucket = std::make_unique<LineBucket>();
+ auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaling);
bucket->layout = layout;
diff --git a/src/mbgl/layer/line_layer.hpp b/src/mbgl/layer/line_layer.hpp
index 027f7a9c06..200541c620 100644
--- a/src/mbgl/layer/line_layer.hpp
+++ b/src/mbgl/layer/line_layer.hpp
@@ -38,6 +38,7 @@ public:
class LineLayer : public StyleLayer {
public:
+ LineLayer() : StyleLayer(Type::Line) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override;
@@ -52,6 +53,11 @@ public:
LinePaintProperties paint;
};
+template <>
+inline bool StyleLayer::is<LineLayer>() const {
+ return type == Type::Line;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/raster_layer.hpp b/src/mbgl/layer/raster_layer.hpp
index bf912bad4a..52c0f0a7ae 100644
--- a/src/mbgl/layer/raster_layer.hpp
+++ b/src/mbgl/layer/raster_layer.hpp
@@ -19,6 +19,7 @@ public:
class RasterLayer : public StyleLayer {
public:
+ RasterLayer() : StyleLayer(Type::Raster) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override {};
@@ -32,6 +33,11 @@ public:
RasterPaintProperties paint;
};
+template <>
+inline bool StyleLayer::is<RasterLayer>() const {
+ return type == Type::Raster;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/layer/symbol_layer.hpp b/src/mbgl/layer/symbol_layer.hpp
index 730bd2ad4a..a2b3b0acf9 100644
--- a/src/mbgl/layer/symbol_layer.hpp
+++ b/src/mbgl/layer/symbol_layer.hpp
@@ -84,6 +84,7 @@ public:
class SymbolLayer : public StyleLayer {
public:
+ SymbolLayer() : StyleLayer(Type::Symbol) {}
std::unique_ptr<StyleLayer> clone() const override;
void parseLayout(const JSValue&) override;
@@ -97,9 +98,14 @@ public:
SymbolLayoutProperties layout;
SymbolPaintProperties paint;
- SpriteAtlas* spriteAtlas;
+ SpriteAtlas* spriteAtlas = nullptr;
};
+template <>
+inline bool StyleLayer::is<SymbolLayer>() const {
+ return type == Type::Symbol;
+}
+
} // namespace mbgl
#endif
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 7e0fdd29fe..c3123fb3be 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -462,6 +462,11 @@ AnnotationIDs Map::addShapeAnnotations(const std::vector<ShapeAnnotation>& annot
return result;
}
+void Map::updatePointAnnotation(AnnotationID annotationId, const PointAnnotation& annotation) {
+ data->getAnnotationManager()->updatePointAnnotation(annotationId, annotation, getMaxZoom());
+ update(Update::Annotations);
+}
+
void Map::removeAnnotation(AnnotationID annotation) {
removeAnnotations({ annotation });
}
diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp
index 03da5ee321..f9397d4f78 100644
--- a/src/mbgl/map/map_context.cpp
+++ b/src/mbgl/map/map_context.cpp
@@ -16,9 +16,10 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_store.hpp>
-#include <mbgl/util/gl_object_store.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
+#include <mbgl/gl/texture_pool.hpp>
+
#include <mbgl/util/worker.hpp>
-#include <mbgl/util/texture_pool.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/mapbox.hpp>
@@ -27,18 +28,16 @@
namespace mbgl {
-MapContext::MapContext(View& view_, FileSource& fileSource, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_)
+MapContext::MapContext(View& view_, FileSource& fileSource_, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_)
: view(view_),
+ fileSource(fileSource_),
dataPtr(std::make_unique<MapData>(mode_, contextMode_, pixelRatio_)),
data(*dataPtr),
asyncUpdate([this] { update(); }),
asyncInvalidate([&view_] { view_.invalidate(); }),
- texturePool(std::make_unique<TexturePool>()) {
+ texturePool(std::make_unique<gl::TexturePool>()) {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
- util::ThreadContext::setFileSource(&fileSource);
- util::ThreadContext::setGLObjectStore(&glObjectStore);
-
view.activate();
}
@@ -95,7 +94,7 @@ void MapContext::setStyleURL(const std::string& url) {
styleURL = url;
styleJSON.clear();
- style = std::make_unique<Style>(data);
+ style = std::make_unique<Style>(data, fileSource);
const size_t pos = styleURL.rfind('/');
std::string base = "";
@@ -103,8 +102,7 @@ void MapContext::setStyleURL(const std::string& url) {
base = styleURL.substr(0, pos + 1);
}
- FileSource* fs = util::ThreadContext::getFileSource();
- styleRequest = fs->request(Resource::style(styleURL), [this, base](Response res) {
+ styleRequest = fileSource.request(Resource::style(styleURL), [this, base](Response res) {
if (res.error) {
if (res.error->reason == Response::Error::Reason::NotFound &&
util::mapbox::isMapboxURL(styleURL)) {
@@ -113,14 +111,11 @@ void MapContext::setStyleURL(const std::string& url) {
Log::Error(Event::Setup, "loading style failed: %s", res.error->message.c_str());
data.loading = false;
}
+ } else if (res.notModified || res.noContent) {
return;
+ } else {
+ loadStyleJSON(*res.data, base);
}
-
- if (res.notModified) {
- return;
- }
-
- loadStyleJSON(*res.data, base);
});
}
@@ -132,7 +127,7 @@ void MapContext::setStyleJSON(const std::string& json, const std::string& base)
styleURL.clear();
styleJSON.clear();
- style = std::make_unique<Style>(data);
+ style = std::make_unique<Style>(data, fileSource);
loadStyleJSON(json, base);
}
@@ -241,7 +236,7 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame)
// Cleanup OpenGL objects that we abandoned since the last render call.
glObjectStore.performCleanup();
- if (!painter) painter = std::make_unique<Painter>(data, transformState);
+ if (!painter) painter = std::make_unique<Painter>(data, transformState, glObjectStore);
painter->render(*style, frame, data.getAnnotationManager()->getSpriteAtlas());
if (data.mode == MapMode::Still) {
diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp
index dd0c2de465..83ab71c86e 100644
--- a/src/mbgl/map/map_context.hpp
+++ b/src/mbgl/map/map_context.hpp
@@ -8,9 +8,9 @@
#include <mbgl/map/map_data.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/util/async_task.hpp>
-#include <mbgl/util/gl_object_store.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <vector>
@@ -18,11 +18,12 @@ namespace mbgl {
class View;
class MapData;
-class TexturePool;
class Painter;
class SpriteImage;
class FileRequest;
+namespace gl { class TexturePool; }
+
struct FrameData {
std::array<uint16_t, 2> framebufferSize;
};
@@ -77,16 +78,17 @@ private:
void loadStyleJSON(const std::string& json, const std::string& base);
View& view;
+ FileSource& fileSource;
std::unique_ptr<MapData> dataPtr;
MapData& data;
- util::GLObjectStore glObjectStore;
+ gl::GLObjectStore glObjectStore;
Update updateFlags = Update::Nothing;
util::AsyncTask asyncUpdate;
util::AsyncTask asyncInvalidate;
- std::unique_ptr<TexturePool> texturePool;
+ std::unique_ptr<gl::TexturePool> texturePool;
std::unique_ptr<Painter> painter;
std::unique_ptr<Style> style;
diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp
deleted file mode 100644
index f9f5480197..0000000000
--- a/src/mbgl/map/raster_tile_data.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <mbgl/map/raster_tile_data.hpp>
-#include <mbgl/map/source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/worker.hpp>
-#include <mbgl/util/work_request.hpp>
-
-using namespace mbgl;
-
-RasterTileData::RasterTileData(const TileID& id_,
- float pixelRatio,
- const std::string& urlTemplate,
- TexturePool &texturePool_,
- Worker& worker_,
- const std::function<void(std::exception_ptr)>& callback)
- : TileData(id_),
- texturePool(texturePool_),
- worker(worker_) {
- state = State::loading;
-
- const Resource resource = Resource::tile(urlTemplate, pixelRatio, id.x, id.y, id.sourceZ);
- req = util::ThreadContext::getFileSource()->request(resource, [callback, this](Response res) {
- if (res.error) {
- std::exception_ptr error;
- if (res.error->reason == Response::Error::Reason::NotFound) {
- // This is a 404 response. We're treating these as empty tiles.
- workRequest.reset();
- state = State::parsed;
- bucket.reset();
- } else {
- // This is a different error, e.g. a connection or server error.
- error = std::make_exception_ptr(std::runtime_error(res.error->message));
- }
- callback(error);
- return;
- }
-
- modified = res.modified;
- expires = res.expires;
-
- if (res.notModified) {
- // We got the same data again. Abort early.
- return;
- }
-
- if (state == State::loading) {
- // Only overwrite the state when we didn't have a previous tile.
- state = State::loaded;
- }
-
- workRequest.reset();
- workRequest = worker.parseRasterTile(std::make_unique<RasterBucket>(texturePool), res.data, [this, callback] (RasterTileParseResult result) {
- workRequest.reset();
- if (state != State::loaded) {
- return;
- }
-
- std::exception_ptr error;
- if (result.is<std::unique_ptr<Bucket>>()) {
- state = State::parsed;
- bucket = std::move(result.get<std::unique_ptr<Bucket>>());
- } else {
- error = result.get<std::exception_ptr>();
- state = State::obsolete;
- bucket.reset();
- }
-
- callback(error);
- });
- });
-}
-
-RasterTileData::~RasterTileData() {
- cancel();
-}
-
-Bucket* RasterTileData::getBucket(StyleLayer const&) {
- return bucket.get();
-}
-
-void RasterTileData::cancel() {
- if (state != State::obsolete) {
- state = State::obsolete;
- }
- req = nullptr;
- workRequest.reset();
-}
diff --git a/src/mbgl/map/tile.cpp b/src/mbgl/map/tile.cpp
deleted file mode 100644
index 408cdfaec5..0000000000
--- a/src/mbgl/map/tile.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <mbgl/map/tile.hpp>
-
-using namespace mbgl;
diff --git a/src/mbgl/map/tile_id.hpp b/src/mbgl/map/tile_id.hpp
index dddbce3bb7..a193b63392 100644
--- a/src/mbgl/map/tile_id.hpp
+++ b/src/mbgl/map/tile_id.hpp
@@ -6,6 +6,7 @@
#include <string>
#include <functional>
#include <forward_list>
+#include <limits>
namespace mbgl {
@@ -25,12 +26,6 @@ public:
return ((std::pow(2, z) * y + x) * 32) + z;
}
- struct Hash {
- std::size_t operator()(const TileID& id) const {
- return std::hash<uint64_t>()(id.to_uint64());
- }
- };
-
inline bool operator==(const TileID& rhs) const {
return w == rhs.w && z == rhs.z && x == rhs.x && y == rhs.y;
}
@@ -48,12 +43,24 @@ public:
TileID parent(int8_t z, int8_t sourceMaxZoom) const;
TileID normalized() const;
- std::forward_list<TileID> children(int8_t sourceMaxZoom) const;
+ std::forward_list<TileID>
+ children(int8_t sourceMaxZoom = std::numeric_limits<int8_t>::max()) const;
bool isChildOf(const TileID&) const;
operator std::string() const;
-
};
} // namespace mbgl
+namespace std {
+template <>
+struct hash<mbgl::TileID> {
+ typedef mbgl::TileID argument_type;
+ typedef std::size_t result_type;
+
+ result_type operator()(const mbgl::TileID& id) const {
+ return std::hash<uint64_t>()(id.to_uint64());
+ }
+};
+} // namespace std
+
#endif
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 009534fc8b..087defabda 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -1,7 +1,6 @@
#include <mbgl/map/transform_state.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/box.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/math.hpp>
@@ -54,18 +53,6 @@ void TransformState::getProjMatrix(mat4& projMatrix) const {
pixel_y() - getHeight() / 2.0f, 0);
}
-box TransformState::cornersToBox(uint32_t z) const {
- double w = width;
- double h = height;
- box b(
- pointToCoordinate({ 0, 0 }).zoomTo(z),
- pointToCoordinate({ w, 0 }).zoomTo(z),
- pointToCoordinate({ w, h }).zoomTo(z),
- pointToCoordinate({ 0, h }).zoomTo(z));
- return b;
-}
-
-
#pragma mark - Dimensions
uint16_t TransformState::getWidth() const {
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index dfcc1ed1a0..0fb1f2304b 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -15,8 +15,7 @@
namespace mbgl {
class TileID;
-struct box;
-struct TileCoordinate;
+class TileCoordinate;
class TransformState {
friend class Transform;
@@ -27,7 +26,6 @@ public:
// Matrix
void matrixFor(mat4& matrix, const TileID& id, const int8_t z) const;
void getProjMatrix(mat4& matrix) const;
- box cornersToBox(uint32_t z) const;
// Dimensions
uint16_t getWidth() const;
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index b7cbfdf0fe..85f97688dd 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_RENDERER_BUCKET
#define MBGL_RENDERER_BUCKET
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/mat4.hpp>
@@ -18,13 +18,17 @@ class StyleLayer;
class TileID;
class CollisionTile;
+namespace gl {
+class GLObjectStore;
+}
+
class Bucket : private util::noncopyable {
public:
Bucket() : uploaded(false) {}
// As long as this bucket has a Prepare render pass, this function is getting called. Typically,
// this only happens once when the bucket is being rendered for the first time.
- virtual void upload() = 0;
+ virtual void upload(gl::GLObjectStore&) = 0;
// Every time this bucket is getting rendered, this function is called. This happens either
// once or twice (for Opaque and Transparent render passes).
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index 1ebe8ffaf3..fcead38c33 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -14,9 +14,9 @@ CircleBucket::~CircleBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
-void CircleBucket::upload() {
- vertexBuffer_.upload();
- elementsBuffer_.upload();
+void CircleBucket::upload(gl::GLObjectStore& glObjectStore) {
+ vertexBuffer_.upload(glObjectStore);
+ elementsBuffer_.upload(glObjectStore);
uploaded = true;
}
@@ -73,7 +73,7 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
}
}
-void CircleBucket::drawCircles(CircleShader& shader) {
+void CircleBucket::drawCircles(CircleShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertexIndex = BUFFER_OFFSET(0);
GLbyte* elementsIndex = BUFFER_OFFSET(0);
@@ -82,7 +82,7 @@ void CircleBucket::drawCircles(CircleShader& shader) {
if (!group->elements_length) continue;
- group->array[0].bind(shader, vertexBuffer_, elementsBuffer_, vertexIndex);
+ group->array[0].bind(shader, vertexBuffer_, elementsBuffer_, vertexIndex, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elementsIndex));
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp
index f85c9267d3..875e5bb4a9 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/circle_bucket.hpp
@@ -3,7 +3,7 @@
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/circle_buffer.hpp>
@@ -20,13 +20,13 @@ public:
CircleBucket();
~CircleBucket() override;
- void upload() override;
+ void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const override;
void addGeometry(const GeometryCollection&);
- void drawCircles(CircleShader& shader);
+ void drawCircles(CircleShader&, gl::GLObjectStore&);
private:
CircleVertexBuffer vertexBuffer_;
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 2d0590c56b..947783ddb8 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -2,7 +2,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/shader/plain_shader.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cassert>
#include <string>
@@ -11,8 +11,8 @@ using namespace mbgl;
DebugBucket::DebugBucket(const TileID id, const TileData::State state_, optional<SystemTimePoint> modified_, optional<SystemTimePoint> expires_, MapDebugOptions debugMode_)
: state(state_),
- modified(modified_),
- expires(expires_),
+ modified(std::move(modified_)),
+ expires(std::move(expires_)),
debugMode(debugMode_) {
double baseline = 200;
if (debugMode & MapDebugOptions::ParseStatus) {
@@ -30,12 +30,12 @@ DebugBucket::DebugBucket(const TileID id, const TileData::State state_, optional
}
}
-void DebugBucket::drawLines(PlainShader& shader) {
- array.bind(shader, fontBuffer, BUFFER_OFFSET_0);
+void DebugBucket::drawLines(PlainShader& shader, gl::GLObjectStore& glObjectStore) {
+ array.bind(shader, fontBuffer, BUFFER_OFFSET_0, glObjectStore);
MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, (GLsizei)(fontBuffer.index())));
}
-void DebugBucket::drawPoints(PlainShader& shader) {
- array.bind(shader, fontBuffer, BUFFER_OFFSET_0);
+void DebugBucket::drawPoints(PlainShader& shader, gl::GLObjectStore& glObjectStore) {
+ array.bind(shader, fontBuffer, BUFFER_OFFSET_0, glObjectStore);
MBGL_CHECK_ERROR(glDrawArrays(GL_POINTS, 0, (GLsizei)(fontBuffer.index())));
}
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
index 5c7511ce87..f12452751c 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_RENDERER_DEBUGBUCKET
#define MBGL_RENDERER_DEBUGBUCKET
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/debug_font_buffer.hpp>
#include <mbgl/geometry/vao.hpp>
@@ -11,6 +11,10 @@ namespace mbgl {
class PlainShader;
+namespace util {
+class GLObjectStore;
+}
+
class DebugBucket : private util::noncopyable {
public:
DebugBucket(TileID id, TileData::State,
@@ -18,8 +22,8 @@ public:
optional<SystemTimePoint> expires,
MapDebugOptions);
- void drawLines(PlainShader& shader);
- void drawPoints(PlainShader& shader);
+ void drawLines(PlainShader&, gl::GLObjectStore&);
+ void drawPoints(PlainShader&, gl::GLObjectStore&);
const TileData::State state;
const optional<SystemTimePoint> modified;
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index ff976c2450..d3a4bc2b57 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -6,7 +6,7 @@
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/outline_shader.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <cassert>
@@ -186,10 +186,10 @@ void FillBucket::tessellate() {
lineGroup.vertex_length += total_vertex_count;
}
-void FillBucket::upload() {
- vertexBuffer.upload();
- triangleElementsBuffer.upload();
- lineElementsBuffer.upload();
+void FillBucket::upload(gl::GLObjectStore& glObjectStore) {
+ vertexBuffer.upload(glObjectStore);
+ triangleElementsBuffer.upload(glObjectStore);
+ lineElementsBuffer.upload(glObjectStore);
// From now on, we're going to render during the opaque and translucent pass.
uploaded = true;
@@ -206,36 +206,36 @@ bool FillBucket::hasData() const {
return !triangleGroups.empty() || !lineGroups.empty();
}
-void FillBucket::drawElements(PlainShader& shader) {
+void FillBucket::drawElements(PlainShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
- group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
+ group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
-void FillBucket::drawElements(PatternShader& shader) {
+void FillBucket::drawElements(PatternShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
- group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
+ group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
-void FillBucket::drawVertices(OutlineShader& shader) {
+void FillBucket::drawVertices(OutlineShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : lineGroups) {
assert(group);
- group->array[0].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index);
+ group->array[0].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_LINES, group->elements_length * 2, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * lineElementsBuffer.itemSize;
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
index 674c41f7d1..b3b46f030b 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -2,7 +2,7 @@
#define MBGL_RENDERER_FILLBUCKET
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/fill_buffer.hpp>
@@ -32,16 +32,16 @@ public:
FillBucket();
~FillBucket() override;
- void upload() override;
+ void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const override;
void addGeometry(const GeometryCollection&);
void tessellate();
- void drawElements(PlainShader& shader);
- void drawElements(PatternShader& shader);
- void drawVertices(OutlineShader& shader);
+ void drawElements(PlainShader&, gl::GLObjectStore&);
+ void drawElements(PatternShader&, gl::GLObjectStore&);
+ void drawVertices(OutlineShader&, gl::GLObjectStore&);
private:
TESSalloc *allocator;
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 83c5b43776..ba50e6b1f0 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -6,13 +6,14 @@
#include <mbgl/shader/linesdf_shader.hpp>
#include <mbgl/shader/linepattern_shader.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cassert>
using namespace mbgl;
-LineBucket::LineBucket() {
+LineBucket::LineBucket(float overscaling_) : overscaling(overscaling_) {
}
LineBucket::~LineBucket() {
@@ -25,6 +26,21 @@ void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
}
}
+
+/*
+ * Sharp corners cause dashed lines to tilt because the distance along the line
+ * is the same at both the inner and outer corners. To improve the appearance of
+ * dashed lines we add extra points near sharp corners so that a smaller part
+ * of the line is tilted.
+ *
+ * COS_HALF_SHARP_CORNER controls how sharp a corner has to be for us to add an
+ * extra vertex. The default is 75 degrees.
+ *
+ * The newly created vertices are placed SHARP_CORNER_OFFSET pixels from the corner.
+ */
+const float COS_HALF_SHARP_CORNER = std::cos(75.0 / 2.0 * (M_PI / 180.0));
+const float SHARP_CORNER_OFFSET = 15.0f;
+
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const GLsizei len = [&vertices] {
GLsizei l = static_cast<GLsizei>(vertices.size());
@@ -42,6 +58,8 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const float miterLimit = layout.join == JoinType::Bevel ? 1.05f : float(layout.miterLimit);
+ const double sharpCornerOffset = SHARP_CORNER_OFFSET * (util::EXTENT / (512.0 * overscaling));
+
const Coordinate firstVertex = vertices.front();
const Coordinate lastVertex = vertices[len - 1];
const bool closed = firstVertex == lastVertex;
@@ -98,10 +116,6 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
currentVertex = vertices[i];
- // Calculate how far along the line the currentVertex is
- if (prevVertex)
- distance += util::dist<double>(currentVertex, prevVertex);
-
// Calculate the normal towards the next vertex in this line. In case
// there is no next vertex, pretend that the line is continuing straight,
// meaning that we are just using the previous normal.
@@ -134,6 +148,18 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const float cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y;
const float miterLength = cosHalfAngle != 0 ? 1 / cosHalfAngle: 1;
+ const bool isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevVertex && nextVertex;
+
+ if (isSharpCorner && i > 0) {
+ const double prevSegmentLength = util::dist<double>(currentVertex, prevVertex);
+ if (prevSegmentLength > 2.0 * sharpCornerOffset) {
+ Coordinate newPrevVertex = currentVertex - (util::round(vec2<double>(currentVertex - prevVertex) * (sharpCornerOffset / prevSegmentLength)));
+ distance += util::dist<double>(newPrevVertex, prevVertex);
+ addCurrentVertex(newPrevVertex, flip, distance, prevNormal, 0, 0, false, startVertex, triangleStore);
+ prevVertex = newPrevVertex;
+ }
+ }
+
// The join if a middle vertex, otherwise the cap
const bool middleVertex = prevVertex && nextVertex;
JoinType currentJoin = layout.join;
@@ -167,6 +193,10 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
}
}
+ // Calculate how far along the line the currentVertex is
+ if (prevVertex)
+ distance += util::dist<double>(currentVertex, prevVertex);
+
if (middleVertex && currentJoin == JoinType::Miter) {
joinNormal = joinNormal * miterLength;
addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex,
@@ -295,6 +325,16 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
}
}
+ if (isSharpCorner && i < len - 1) {
+ const double nextSegmentLength = util::dist<double>(currentVertex, nextVertex);
+ if (nextSegmentLength > 2 * sharpCornerOffset) {
+ Coordinate newCurrentVertex = currentVertex + util::round(vec2<double>(nextVertex - currentVertex) * (sharpCornerOffset / nextSegmentLength));
+ distance += util::dist<double>(newCurrentVertex, currentVertex);
+ addCurrentVertex(newCurrentVertex, flip, distance, nextNormal, 0, 0, false, startVertex, triangleStore);
+ currentVertex = newCurrentVertex;
+ }
+ }
+
startOfLine = false;
}
@@ -378,9 +418,9 @@ void LineBucket::addPieSliceVertex(const Coordinate& currentVertex,
}
}
-void LineBucket::upload() {
- vertexBuffer.upload();
- triangleElementsBuffer.upload();
+void LineBucket::upload(gl::GLObjectStore& glObjectStore) {
+ vertexBuffer.upload(glObjectStore);
+ triangleElementsBuffer.upload(glObjectStore);
// From now on, we're only going to render during the translucent pass.
uploaded = true;
@@ -397,7 +437,7 @@ bool LineBucket::hasData() const {
return !triangleGroups.empty();
}
-void LineBucket::drawLines(LineShader& shader) {
+void LineBucket::drawLines(LineShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -405,7 +445,7 @@ void LineBucket::drawLines(LineShader& shader) {
if (!group->elements_length) {
continue;
}
- group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
+ group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
@@ -413,7 +453,7 @@ void LineBucket::drawLines(LineShader& shader) {
}
}
-void LineBucket::drawLineSDF(LineSDFShader& shader) {
+void LineBucket::drawLineSDF(LineSDFShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -421,7 +461,7 @@ void LineBucket::drawLineSDF(LineSDFShader& shader) {
if (!group->elements_length) {
continue;
}
- group->array[2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
+ group->array[2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
@@ -429,7 +469,7 @@ void LineBucket::drawLineSDF(LineSDFShader& shader) {
}
}
-void LineBucket::drawLinePatterns(LinepatternShader& shader) {
+void LineBucket::drawLinePatterns(LinepatternShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
@@ -437,7 +477,7 @@ void LineBucket::drawLinePatterns(LinepatternShader& shader) {
if (!group->elements_length) {
continue;
}
- group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
+ group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT,
elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index 7d662aac02..dd0ce4ff29 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -2,7 +2,7 @@
#define MBGL_RENDERER_LINEBUCKET
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/line_buffer.hpp>
@@ -24,19 +24,19 @@ class LineBucket : public Bucket {
using TriangleGroup = ElementGroup<3>;
public:
- LineBucket();
+ LineBucket(float overscaling);
~LineBucket() override;
- void upload() override;
+ void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const override;
void addGeometry(const GeometryCollection&);
void addGeometry(const std::vector<Coordinate>& line);
- void drawLines(LineShader& shader);
- void drawLineSDF(LineSDFShader& shader);
- void drawLinePatterns(LinepatternShader& shader);
+ void drawLines(LineShader&, gl::GLObjectStore&);
+ void drawLineSDF(LineSDFShader&, gl::GLObjectStore&);
+ void drawLinePatterns(LinepatternShader&, gl::GLObjectStore&);
private:
struct TriangleElement {
@@ -62,6 +62,8 @@ private:
GLint e3;
std::vector<std::unique_ptr<TriangleGroup>> triangleGroups;
+
+ const float overscaling;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 0fd76314dc..da3551aa74 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -1,7 +1,7 @@
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/map/source.hpp>
-#include <mbgl/map/tile.hpp>
+#include <mbgl/source/source.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/map/map_context.hpp>
#include <mbgl/map/map_data.hpp>
@@ -46,23 +46,25 @@
using namespace mbgl;
-Painter::Painter(MapData& data_, TransformState& state_)
- : data(data_), state(state_) {
+Painter::Painter(MapData& data_, TransformState& state_, gl::GLObjectStore& glObjectStore_)
+ : data(data_),
+ state(state_),
+ glObjectStore(glObjectStore_) {
gl::debugging::enable();
- plainShader = std::make_unique<PlainShader>();
- outlineShader = std::make_unique<OutlineShader>();
- lineShader = std::make_unique<LineShader>();
- linesdfShader = std::make_unique<LineSDFShader>();
- linepatternShader = std::make_unique<LinepatternShader>();
- patternShader = std::make_unique<PatternShader>();
- iconShader = std::make_unique<IconShader>();
- rasterShader = std::make_unique<RasterShader>();
- sdfGlyphShader = std::make_unique<SDFGlyphShader>();
- sdfIconShader = std::make_unique<SDFIconShader>();
- dotShader = std::make_unique<DotShader>();
- collisionBoxShader = std::make_unique<CollisionBoxShader>();
- circleShader = std::make_unique<CircleShader>();
+ plainShader = std::make_unique<PlainShader>(glObjectStore);
+ outlineShader = std::make_unique<OutlineShader>(glObjectStore);
+ lineShader = std::make_unique<LineShader>(glObjectStore);
+ linesdfShader = std::make_unique<LineSDFShader>(glObjectStore);
+ linepatternShader = std::make_unique<LinepatternShader>(glObjectStore);
+ patternShader = std::make_unique<PatternShader>(glObjectStore);
+ iconShader = std::make_unique<IconShader>(glObjectStore);
+ rasterShader = std::make_unique<RasterShader>(glObjectStore);
+ sdfGlyphShader = std::make_unique<SDFGlyphShader>(glObjectStore);
+ sdfIconShader = std::make_unique<SDFIconShader>(glObjectStore);
+ dotShader = std::make_unique<DotShader>(glObjectStore);
+ collisionBoxShader = std::make_unique<CollisionBoxShader>(glObjectStore);
+ circleShader = std::make_unique<CircleShader>(glObjectStore);
// Reset GL values
config.reset();
@@ -108,16 +110,16 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
{
MBGL_DEBUG_GROUP("upload");
- tileStencilBuffer.upload();
- tileBorderBuffer.upload();
- spriteAtlas->upload();
- lineAtlas->upload();
- glyphAtlas->upload();
- annotationSpriteAtlas.upload();
+ tileStencilBuffer.upload(glObjectStore);
+ tileBorderBuffer.upload(glObjectStore);
+ spriteAtlas->upload(glObjectStore);
+ lineAtlas->upload(glObjectStore);
+ glyphAtlas->upload(glObjectStore);
+ annotationSpriteAtlas.upload(glObjectStore);
for (const auto& item : order) {
if (item.bucket && item.bucket->needsUpload()) {
- item.bucket->upload();
+ item.bucket->upload(glObjectStore);
}
}
}
@@ -151,7 +153,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
source->updateMatrices(projMatrix, state);
}
- drawClippingMasks(sources);
+ drawClippingMasks(generator.getStencils());
}
frameHistory.record(data.getAnimationTime(), state.getZoom());
@@ -270,7 +272,7 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
float zoomFraction = state.getZoomFraction();
- config.program = patternShader->program;
+ config.program = patternShader->getID();
patternShader->u_matrix = identityMatrix;
patternShader->u_pattern_tl_a = (*imagePosA).tl;
patternShader->u_pattern_br_a = (*imagePosA).br;
@@ -315,9 +317,9 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
patternShader->u_patternmatrix_b = matrixB;
VertexArrayObject::Unbind();
- backgroundBuffer.bind();
+ backgroundBuffer.bind(glObjectStore);
patternShader->bind(0);
- spriteAtlas->bind(true);
+ spriteAtlas->bind(true, glObjectStore);
} else {
Color color = properties.color;
color[0] *= properties.opacity;
@@ -325,10 +327,10 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
color[2] *= properties.opacity;
color[3] *= properties.opacity;
- config.program = plainShader->program;
+ config.program = plainShader->getID();
plainShader->u_matrix = identityMatrix;
plainShader->u_color = color;
- backgroundArray.bind(*plainShader, backgroundBuffer, BUFFER_OFFSET(0));
+ backgroundArray.bind(*plainShader, backgroundBuffer, BUFFER_OFFSET(0), glObjectStore);
}
config.stencilTest = GL_FALSE;
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index 092c164033..83d051359b 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -10,11 +10,11 @@
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/static_vertex_buffer.hpp>
-#include <mbgl/renderer/gl_config.hpp>
+#include <mbgl/gl/gl_config.hpp>
#include <mbgl/style/types.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/chrono.hpp>
@@ -66,9 +66,13 @@ class CollisionBoxShader;
struct ClipID;
+namespace util {
+class GLObjectStore;
+}
+
class Painter : private util::noncopyable {
public:
- Painter(MapData&, TransformState&);
+ Painter(MapData&, TransformState&, gl::GLObjectStore&);
~Painter();
void render(const Style& style,
@@ -93,8 +97,7 @@ public:
float contrastFactor(float contrast);
std::array<float, 3> spinWeights(float spin_value);
- void drawClippingMasks(const std::set<Source*>&);
- void drawClippingMask(const mat4& matrix, const ClipID& clip);
+ void drawClippingMasks(const std::map<TileID, ClipID>&);
bool needsAnimation() const;
@@ -119,7 +122,7 @@ private:
float scaleDivisor,
std::array<float, 2> texsize,
SDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SDFShader&));
+ void (SymbolBucket::*drawSDF)(SDFShader&, gl::GLObjectStore&));
void setDepthSublayer(int n);
@@ -143,6 +146,8 @@ private:
MapData& data;
TransformState& state;
+ gl::GLObjectStore& glObjectStore;
+
FrameData frame;
int indent = 0;
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
index 9518cf9e39..4ae562d674 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painter_circle.cpp
@@ -38,7 +38,7 @@ void Painter::renderCircle(CircleBucket& bucket,
// are inversely related.
float antialiasing = 1 / data.pixelRatio / properties.radius;
- config.program = circleShader->program;
+ config.program = circleShader->getID();
circleShader->u_matrix = vtxMatrix;
circleShader->u_exmatrix = extrudeMatrix;
@@ -46,5 +46,5 @@ void Painter::renderCircle(CircleBucket& bucket,
circleShader->u_blur = std::max<float>(properties.blur, antialiasing);
circleShader->u_size = properties.radius;
- bucket.drawCircles(*circleShader);
+ bucket.drawCircles(*circleShader, glObjectStore);
}
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index 6994650412..aed4c45869 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
@@ -1,36 +1,39 @@
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/map/source.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/clip_id.hpp>
#include <mbgl/gl/debugging.hpp>
using namespace mbgl;
-void Painter::drawClippingMasks(const std::set<Source*>& sources) {
+
+void Painter::drawClippingMasks(const std::map<TileID, ClipID>& stencils) {
MBGL_DEBUG_GROUP("clipping masks");
- config.program = plainShader->program;
+ mat4 matrix;
+ const GLuint mask = 0b11111111;
+
+ config.program = plainShader->getID();
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
- config.depthFunc.reset();
- config.depthTest = GL_TRUE;
+ config.depthTest = GL_FALSE;
config.depthMask = GL_FALSE;
config.colorMask = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE };
- config.depthRange = { 1.0f, 1.0f };
+ config.stencilMask = mask;
- coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET_0);
+ coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET_0, glObjectStore);
- for (const auto& source : sources) {
- source->drawClippingMasks(*this);
- }
-}
+ for (const auto& stencil : stencils) {
+ const auto& id = stencil.first;
+ const auto& clip = stencil.second;
-void Painter::drawClippingMask(const mat4& matrix, const ClipID &clip) {
- plainShader->u_matrix = matrix;
+ MBGL_DEBUG_GROUP(std::string{ "mask: " } + std::string(id));
+ state.matrixFor(matrix, id, id.z);
+ matrix::multiply(matrix, projMatrix, matrix);
+ plainShader->u_matrix = matrix;
- const GLint ref = (GLint)(clip.reference.to_ulong());
- const GLuint mask = (GLuint)(clip.mask.to_ulong());
- config.stencilFunc = { GL_ALWAYS, ref, mask };
- config.stencilMask = mask;
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()));
+ const GLint ref = (GLint)(clip.reference.to_ulong());
+ config.stencilFunc = { GL_ALWAYS, ref, mask };
+ MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()));
+ }
}
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index d6b1aec73c..575bffe53f 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -1,7 +1,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
-#include <mbgl/map/tile.hpp>
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/string.hpp>
@@ -15,7 +15,9 @@ void Painter::renderTileDebug(const Tile& tile) {
if (data.getDebug() != MapDebugOptions::NoDebug) {
prepareTile(tile);
renderDebugText(*tile.data, tile.matrix);
- renderDebugFrame(tile.matrix);
+ if (data.getDebug() & MapDebugOptions::TileBorders) {
+ renderDebugFrame(tile.matrix);
+ }
}
}
@@ -31,24 +33,24 @@ void Painter::renderDebugText(TileData& tileData, const mat4 &matrix) {
tileData.debugBucket = std::make_unique<DebugBucket>(tileData.id, tileData.getState(), tileData.modified, tileData.expires, data.getDebug());
}
- config.program = plainShader->program;
+ config.program = plainShader->getID();
plainShader->u_matrix = matrix;
// Draw white outline
plainShader->u_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
config.lineWidth = 4.0f * data.pixelRatio;
- tileData.debugBucket->drawLines(*plainShader);
+ tileData.debugBucket->drawLines(*plainShader, glObjectStore);
#ifndef GL_ES_VERSION_2_0
// Draw line "end caps"
MBGL_CHECK_ERROR(glPointSize(2));
- tileData.debugBucket->drawPoints(*plainShader);
+ tileData.debugBucket->drawPoints(*plainShader, glObjectStore);
#endif
// Draw black text.
plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
config.lineWidth = 2.0f * data.pixelRatio;
- tileData.debugBucket->drawLines(*plainShader);
+ tileData.debugBucket->drawLines(*plainShader, glObjectStore);
config.depthFunc.reset();
config.depthTest = GL_TRUE;
@@ -64,11 +66,11 @@ void Painter::renderDebugFrame(const mat4 &matrix) {
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
- config.program = plainShader->program;
+ config.program = plainShader->getID();
plainShader->u_matrix = matrix;
// draw tile outline
- tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET_0);
+ tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET_0, glObjectStore);
plainShader->u_color = {{ 1.0f, 0.0f, 0.0f, 1.0f }};
config.lineWidth = 4.0f * data.pixelRatio;
MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)tileBorderBuffer.index()));
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 44ae1919a0..cd54645c2b 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -44,7 +44,7 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
// Because we're drawing top-to-bottom, and we update the stencil mask
// befrom, we have to draw the outline first (!)
if (outline && pass == RenderPass::Translucent) {
- config.program = outlineShader->program;
+ config.program = outlineShader->getID();
outlineShader->u_matrix = vtxMatrix;
config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
@@ -56,7 +56,7 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
static_cast<float>(frame.framebufferSize[1])
}};
setDepthSublayer(0);
- bucket.drawVertices(*outlineShader);
+ bucket.drawVertices(*outlineShader, glObjectStore);
}
if (pattern) {
@@ -78,7 +78,7 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
1.0f / ((*posB).size[0] * factor * properties.pattern.value.toScale),
1.0f / ((*posB).size[1] * factor * properties.pattern.value.toScale));
- config.program = patternShader->program;
+ config.program = patternShader->getID();
patternShader->u_matrix = vtxMatrix;
patternShader->u_pattern_tl_a = (*posA).tl;
patternShader->u_pattern_br_a = (*posA).br;
@@ -111,11 +111,11 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
- spriteAtlas->bind(true);
+ spriteAtlas->bind(true, glObjectStore);
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(0);
- bucket.drawElements(*patternShader);
+ bucket.drawElements(*patternShader, glObjectStore);
}
}
else {
@@ -125,20 +125,20 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
// fragments or when it's translucent and we're drawing translucent
// fragments
// Draw filling rectangle.
- config.program = plainShader->program;
+ config.program = plainShader->getID();
plainShader->u_matrix = vtxMatrix;
plainShader->u_color = fill_color;
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(1);
- bucket.drawElements(*plainShader);
+ bucket.drawElements(*plainShader, glObjectStore);
}
}
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
if (fringeline && pass == RenderPass::Translucent) {
- config.program = outlineShader->program;
+ config.program = outlineShader->getID();
outlineShader->u_matrix = vtxMatrix;
config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
@@ -151,6 +151,6 @@ void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileI
}};
setDepthSublayer(2);
- bucket.drawVertices(*outlineShader);
+ bucket.drawVertices(*outlineShader, glObjectStore);
}
}
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index dd2833b117..5fc5ee0221 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -70,7 +70,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
if (!properties.dasharray.value.from.empty()) {
- config.program = linesdfShader->program;
+ config.program = linesdfShader->getID();
linesdfShader->u_matrix = vtxMatrix;
linesdfShader->u_exmatrix = extrudeMatrix;
@@ -79,9 +79,9 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
linesdfShader->u_blur = blur;
linesdfShader->u_color = color;
- LinePatternPos posA = lineAtlas->getDashPosition(properties.dasharray.value.from, layout.cap == CapType::Round);
- LinePatternPos posB = lineAtlas->getDashPosition(properties.dasharray.value.to, layout.cap == CapType::Round);
- lineAtlas->bind();
+ LinePatternPos posA = lineAtlas->getDashPosition(properties.dasharray.value.from, layout.cap == CapType::Round, glObjectStore);
+ LinePatternPos posB = lineAtlas->getDashPosition(properties.dasharray.value.to, layout.cap == CapType::Round, glObjectStore);
+ lineAtlas->bind(glObjectStore);
const float widthA = posA.width * properties.dasharray.value.fromScale;
const float widthB = posB.width * properties.dasharray.value.toScale;
@@ -102,7 +102,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
linesdfShader->u_offset = -properties.offset;
linesdfShader->u_antialiasingmatrix = antialiasingMatrix;
- bucket.drawLineSDF(*linesdfShader);
+ bucket.drawLineSDF(*linesdfShader, glObjectStore);
} else if (!properties.pattern.value.from.empty()) {
optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.pattern.value.from, true);
@@ -113,7 +113,7 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
float factor = util::EXTENT / (512 * id.overscaling) / std::pow(2, state.getIntegerZoom() - id.z);
- config.program = linepatternShader->program;
+ config.program = linepatternShader->getID();
linepatternShader->u_matrix = vtxMatrix;
linepatternShader->u_exmatrix = extrudeMatrix;
@@ -134,12 +134,12 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
linepatternShader->u_antialiasingmatrix = antialiasingMatrix;
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
- spriteAtlas->bind(true);
+ spriteAtlas->bind(true, glObjectStore);
- bucket.drawLinePatterns(*linepatternShader);
+ bucket.drawLinePatterns(*linepatternShader, glObjectStore);
} else {
- config.program = lineShader->program;
+ config.program = lineShader->getID();
lineShader->u_matrix = vtxMatrix;
lineShader->u_exmatrix = extrudeMatrix;
@@ -152,6 +152,6 @@ void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileI
lineShader->u_color = color;
- bucket.drawLines(*lineShader);
+ bucket.drawLines(*lineShader, glObjectStore);
}
}
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index 3fd953fcd6..377b2c005c 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -1,5 +1,5 @@
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/layer/raster_layer.hpp>
#include <mbgl/shader/raster_shader.hpp>
@@ -12,7 +12,7 @@ void Painter::renderRaster(RasterBucket& bucket, const RasterLayer& layer, const
const RasterPaintProperties& properties = layer.paint;
if (bucket.hasData()) {
- config.program = rasterShader->program;
+ config.program = rasterShader->getID();
rasterShader->u_matrix = matrix;
rasterShader->u_buffer = 0;
rasterShader->u_opacity = properties.opacity;
@@ -28,7 +28,7 @@ void Painter::renderRaster(RasterBucket& bucket, const RasterLayer& layer, const
config.depthTest = GL_TRUE;
config.depthMask = GL_FALSE;
setDepthSublayer(0);
- bucket.drawRaster(*rasterShader, tileStencilBuffer, coveringRasterArray);
+ bucket.drawRaster(*rasterShader, tileStencilBuffer, coveringRasterArray, glObjectStore);
}
}
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 0538485824..5f59d6a8a6 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -23,7 +23,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
float sdfFontSize,
std::array<float, 2> texsize,
SDFShader& sdfShader,
- void (SymbolBucket::*drawSDF)(SDFShader&))
+ void (SymbolBucket::*drawSDF)(SDFShader&, gl::GLObjectStore&))
{
mat4 vtxMatrix = translatedMatrix(matrix, styleProperties.translate, id, styleProperties.translateAnchor);
@@ -49,7 +49,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
float fontScale = fontSize / sdfFontSize;
matrix::scale(exMatrix, exMatrix, fontScale, fontScale, 1.0f);
- config.program = sdfShader.program;
+ config.program = sdfShader.getID();
sdfShader.u_matrix = vtxMatrix;
sdfShader.u_exmatrix = exMatrix;
sdfShader.u_texsize = texsize;
@@ -101,7 +101,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
sdfShader.u_buffer = (haloOffset - styleProperties.haloWidth / fontScale) / sdfPx;
setDepthSublayer(0);
- (bucket.*drawSDF)(sdfShader);
+ (bucket.*drawSDF)(sdfShader, glObjectStore);
}
// Then, we draw the text/icon over the halo
@@ -122,7 +122,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
sdfShader.u_buffer = (256.0f - 64.0f) / 256.0f;
setDepthSublayer(1);
- (bucket.*drawSDF)(sdfShader);
+ (bucket.*drawSDF)(sdfShader, glObjectStore);
}
}
@@ -137,22 +137,6 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
config.depthMask = GL_FALSE;
- if (bucket.hasCollisionBoxData()) {
- config.stencilOp.reset();
- config.stencilTest = GL_TRUE;
-
- config.program = collisionBoxShader->program;
- collisionBoxShader->u_matrix = matrix;
- collisionBoxShader->u_scale = std::pow(2, state.getZoom() - id.z);
- collisionBoxShader->u_zoom = state.getZoom() * 10;
- collisionBoxShader->u_maxzoom = (id.z + 1) * 10;
- config.lineWidth = 1.0f;
-
- setDepthSublayer(0);
- bucket.drawCollisionBoxes(*collisionBoxShader);
-
- }
-
// TODO remove the `true ||` when #1673 is implemented
const bool drawAcrossEdges = (data.mode == MapMode::Continuous) && (true || !(layout.text.allowOverlap || layout.icon.allowOverlap ||
layout.text.ignorePlacement || layout.icon.ignorePlacement));
@@ -190,7 +174,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
SpriteAtlas* activeSpriteAtlas = layer.spriteAtlas;
const bool iconScaled = fontScale != 1 || data.pixelRatio != activeSpriteAtlas->getPixelRatio() || bucket.iconsNeedLinear;
const bool iconTransformed = layout.icon.rotationAlignment == RotationAlignmentType::Map || angleOffset != 0 || state.getPitch() != 0;
- activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed);
+ activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, glObjectStore);
if (sdf) {
renderSDF(bucket,
@@ -227,7 +211,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
float extra = (topedgelength + x) / topedgelength - 1;
- config.program = iconShader->program;
+ config.program = iconShader->getID();
iconShader->u_matrix = vtxMatrix;
iconShader->u_exmatrix = exMatrix;
iconShader->u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }};
@@ -246,7 +230,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
iconShader->u_opacity = properties.icon.opacity;
setDepthSublayer(0);
- bucket.drawIcons(*iconShader);
+ bucket.drawIcons(*iconShader, glObjectStore);
}
}
@@ -258,7 +242,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
config.depthTest = GL_FALSE;
}
- glyphAtlas->bind();
+ glyphAtlas->bind(glObjectStore);
renderSDF(bucket,
id,
@@ -271,4 +255,20 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
&SymbolBucket::drawGlyphs);
}
+ if (bucket.hasCollisionBoxData()) {
+ config.stencilOp.reset();
+ config.stencilTest = GL_TRUE;
+
+ config.program = collisionBoxShader->getID();
+ collisionBoxShader->u_matrix = matrix;
+ collisionBoxShader->u_scale = std::pow(2, state.getZoom() - id.z);
+ collisionBoxShader->u_zoom = state.getZoom() * 10;
+ collisionBoxShader->u_maxzoom = (id.z + 1) * 10;
+ config.lineWidth = 1.0f;
+
+ setDepthSublayer(0);
+ bucket.drawCollisionBoxes(*collisionBoxShader, glObjectStore);
+
+ }
+
}
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
index 4dbbf18697..137574b731 100644
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ b/src/mbgl/renderer/raster_bucket.cpp
@@ -5,13 +5,13 @@
using namespace mbgl;
-RasterBucket::RasterBucket(TexturePool& texturePool)
+RasterBucket::RasterBucket(gl::TexturePool& texturePool)
: raster(texturePool) {
}
-void RasterBucket::upload() {
+void RasterBucket::upload(gl::GLObjectStore& glObjectStore) {
if (hasData()) {
- raster.upload();
+ raster.upload(glObjectStore);
uploaded = true;
}
}
@@ -27,10 +27,10 @@ void RasterBucket::setImage(PremultipliedImage image) {
raster.load(std::move(image));
}
-void RasterBucket::drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array) {
- raster.bind(true);
+void RasterBucket::drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array, gl::GLObjectStore& glObjectStore) {
+ raster.bind(true, glObjectStore);
shader.u_image = 0;
- array.bind(shader, vertices, BUFFER_OFFSET_0);
+ array.bind(shader, vertices, BUFFER_OFFSET_0, glObjectStore);
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices.index()));
}
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
index 0f6237969a..466a7602ed 100644
--- a/src/mbgl/renderer/raster_bucket.hpp
+++ b/src/mbgl/renderer/raster_bucket.hpp
@@ -12,15 +12,15 @@ class VertexArrayObject;
class RasterBucket : public Bucket {
public:
- RasterBucket(TexturePool&);
+ RasterBucket(gl::TexturePool&);
- void upload() override;
+ void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const override;
void setImage(PremultipliedImage);
- void drawRaster(RasterShader& shader, StaticVertexBuffer &vertices, VertexArrayObject &array);
+ void drawRaster(RasterShader&, StaticVertexBuffer&, VertexArrayObject&, gl::GLObjectStore&);
Raster raster;
};
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index e4fccc22e9..683a6f4b11 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -1,6 +1,6 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/layer/symbol_layer.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
@@ -64,14 +64,14 @@ SymbolBucket::~SymbolBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
-void SymbolBucket::upload() {
+void SymbolBucket::upload(gl::GLObjectStore& glObjectStore) {
if (hasTextData()) {
- renderData->text.vertices.upload();
- renderData->text.triangles.upload();
+ renderData->text.vertices.upload(glObjectStore);
+ renderData->text.triangles.upload(glObjectStore);
}
if (hasIconData()) {
- renderData->icon.vertices.upload();
- renderData->icon.triangles.upload();
+ renderData->icon.vertices.upload(glObjectStore);
+ renderData->icon.triangles.upload(glObjectStore);
}
uploaded = true;
@@ -572,50 +572,50 @@ void SymbolBucket::swapRenderData() {
}
}
-void SymbolBucket::drawGlyphs(SDFShader &shader) {
+void SymbolBucket::drawGlyphs(SDFShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& text = renderData->text;
for (auto &group : text.groups) {
assert(group);
- group->array[0].bind(shader, text.vertices, text.triangles, vertex_index);
+ group->array[0].bind(shader, text.vertices, text.triangles, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * text.vertices.itemSize;
elements_index += group->elements_length * text.triangles.itemSize;
}
}
-void SymbolBucket::drawIcons(SDFShader &shader) {
+void SymbolBucket::drawIcons(SDFShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& icon = renderData->icon;
for (auto &group : icon.groups) {
assert(group);
- group->array[0].bind(shader, icon.vertices, icon.triangles, vertex_index);
+ group->array[0].bind(shader, icon.vertices, icon.triangles, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * icon.vertices.itemSize;
elements_index += group->elements_length * icon.triangles.itemSize;
}
}
-void SymbolBucket::drawIcons(IconShader &shader) {
+void SymbolBucket::drawIcons(IconShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
GLbyte *elements_index = BUFFER_OFFSET_0;
auto& icon = renderData->icon;
for (auto &group : icon.groups) {
assert(group);
- group->array[1].bind(shader, icon.vertices, icon.triangles, vertex_index);
+ group->array[1].bind(shader, icon.vertices, icon.triangles, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * icon.vertices.itemSize;
elements_index += group->elements_length * icon.triangles.itemSize;
}
}
-void SymbolBucket::drawCollisionBoxes(CollisionBoxShader &shader) {
+void SymbolBucket::drawCollisionBoxes(CollisionBoxShader& shader, gl::GLObjectStore& glObjectStore) {
GLbyte *vertex_index = BUFFER_OFFSET_0;
auto& collisionBox = renderData->collisionBox;
for (auto &group : collisionBox.groups) {
- group->array[0].bind(shader, collisionBox.vertices, vertex_index);
+ group->array[0].bind(shader, collisionBox.vertices, vertex_index, glObjectStore);
MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, group->vertex_length));
}
}
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index 5728cfa28c..cebb7e5dbe 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -2,7 +2,7 @@
#define MBGL_RENDERER_SYMBOLBUCKET
#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
@@ -70,7 +70,7 @@ public:
SymbolBucket(float overscaling, float zoom, const MapMode);
~SymbolBucket() override;
- void upload() override;
+ void upload(gl::GLObjectStore&) override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const override;
bool hasTextData() const;
@@ -82,10 +82,10 @@ public:
GlyphAtlas&,
GlyphStore&);
- void drawGlyphs(SDFShader& shader);
- void drawIcons(SDFShader& shader);
- void drawIcons(IconShader& shader);
- void drawCollisionBoxes(CollisionBoxShader& shader);
+ void drawGlyphs(SDFShader&, gl::GLObjectStore&);
+ void drawIcons(SDFShader&, gl::GLObjectStore&);
+ void drawIcons(IconShader&, gl::GLObjectStore&);
+ void drawCollisionBoxes(CollisionBoxShader&, gl::GLObjectStore&);
void parseFeatures(const GeometryTileLayer&,
const FilterExpression&);
diff --git a/src/mbgl/shader/box_shader.cpp b/src/mbgl/shader/box_shader.cpp
index d9845ec36f..63f800ea69 100644
--- a/src/mbgl/shader/box_shader.cpp
+++ b/src/mbgl/shader/box_shader.cpp
@@ -1,16 +1,16 @@
#include <mbgl/shader/box_shader.hpp>
#include <mbgl/shader/box.vertex.hpp>
#include <mbgl/shader/box.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-CollisionBoxShader::CollisionBoxShader()
- : Shader("collisionbox", shaders::box::vertex, shaders::box::fragment) {
- a_extrude = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_extrude"));
- a_data = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data"));
+CollisionBoxShader::CollisionBoxShader(gl::GLObjectStore& glObjectStore)
+ : Shader("collisionbox", shaders::box::vertex, shaders::box::fragment, glObjectStore) {
+ a_extrude = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_extrude"));
+ a_data = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"));
}
void CollisionBoxShader::bind(GLbyte *offset) {
diff --git a/src/mbgl/shader/box_shader.hpp b/src/mbgl/shader/box_shader.hpp
index 19df2ca825..f3015b73a7 100644
--- a/src/mbgl/shader/box_shader.hpp
+++ b/src/mbgl/shader/box_shader.hpp
@@ -3,13 +3,13 @@
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
namespace mbgl {
class CollisionBoxShader : public Shader {
public:
- CollisionBoxShader();
+ CollisionBoxShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/circle_shader.cpp b/src/mbgl/shader/circle_shader.cpp
index 0af5bcf604..3ec822747f 100644
--- a/src/mbgl/shader/circle_shader.cpp
+++ b/src/mbgl/shader/circle_shader.cpp
@@ -1,14 +1,14 @@
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/shader/circle.vertex.hpp>
#include <mbgl/shader/circle.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-CircleShader::CircleShader()
- : Shader("circle", shaders::circle::vertex, shaders::circle::fragment) {
+CircleShader::CircleShader(gl::GLObjectStore& glObjectStore)
+ : Shader("circle", shaders::circle::vertex, shaders::circle::fragment, glObjectStore) {
}
void CircleShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/circle_shader.hpp b/src/mbgl/shader/circle_shader.hpp
index 7c1212c275..a28bf3c6ae 100644
--- a/src/mbgl/shader/circle_shader.hpp
+++ b/src/mbgl/shader/circle_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class CircleShader : public Shader {
public:
- CircleShader();
+ CircleShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/dot_shader.cpp b/src/mbgl/shader/dot_shader.cpp
index 2eba489b66..9d60306da2 100644
--- a/src/mbgl/shader/dot_shader.cpp
+++ b/src/mbgl/shader/dot_shader.cpp
@@ -1,13 +1,14 @@
#include <mbgl/shader/dot_shader.hpp>
#include <mbgl/shader/dot.vertex.hpp>
#include <mbgl/shader/dot.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-DotShader::DotShader() : Shader("dot", shaders::dot::vertex, shaders::dot::fragment) {
+DotShader::DotShader(gl::GLObjectStore& glObjectStore)
+ : Shader("dot", shaders::dot::vertex, shaders::dot::fragment, glObjectStore) {
}
void DotShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/dot_shader.hpp b/src/mbgl/shader/dot_shader.hpp
index 606764c2d6..a015310a62 100644
--- a/src/mbgl/shader/dot_shader.hpp
+++ b/src/mbgl/shader/dot_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class DotShader : public Shader {
public:
- DotShader();
+ DotShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/icon_shader.cpp b/src/mbgl/shader/icon_shader.cpp
index bb43cb3e4a..2ff653a87c 100644
--- a/src/mbgl/shader/icon_shader.cpp
+++ b/src/mbgl/shader/icon_shader.cpp
@@ -1,16 +1,17 @@
#include <mbgl/shader/icon_shader.hpp>
#include <mbgl/shader/icon.vertex.hpp>
#include <mbgl/shader/icon.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-IconShader::IconShader() : Shader("icon", shaders::icon::vertex, shaders::icon::fragment) {
- a_offset = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_offset"));
- a_data1 = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data1"));
- a_data2 = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data2"));
+IconShader::IconShader(gl::GLObjectStore& glObjectStore)
+ : Shader("icon", shaders::icon::vertex, shaders::icon::fragment, glObjectStore) {
+ a_offset = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_offset"));
+ a_data1 = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data1"));
+ a_data2 = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data2"));
}
void IconShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/icon_shader.hpp b/src/mbgl/shader/icon_shader.hpp
index 8a25b635fe..ec6311ea80 100644
--- a/src/mbgl/shader/icon_shader.hpp
+++ b/src/mbgl/shader/icon_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class IconShader : public Shader {
public:
- IconShader();
+ IconShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/line_shader.cpp b/src/mbgl/shader/line_shader.cpp
index 54bc6c1148..e4df0531d8 100644
--- a/src/mbgl/shader/line_shader.cpp
+++ b/src/mbgl/shader/line_shader.cpp
@@ -1,14 +1,15 @@
#include <mbgl/shader/line_shader.hpp>
#include <mbgl/shader/line.vertex.hpp>
#include <mbgl/shader/line.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-LineShader::LineShader() : Shader("line", shaders::line::vertex, shaders::line::fragment) {
- a_data = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data"));
+LineShader::LineShader(gl::GLObjectStore& glObjectStore)
+ : Shader("line", shaders::line::vertex, shaders::line::fragment, glObjectStore) {
+ a_data = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"));
}
void LineShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/line_shader.hpp b/src/mbgl/shader/line_shader.hpp
index 14e03c2eaf..1a9598f925 100644
--- a/src/mbgl/shader/line_shader.hpp
+++ b/src/mbgl/shader/line_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class LineShader : public Shader {
public:
- LineShader();
+ LineShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/linepattern_shader.cpp b/src/mbgl/shader/linepattern_shader.cpp
index 9e71d0a9d9..7acd42f727 100644
--- a/src/mbgl/shader/linepattern_shader.cpp
+++ b/src/mbgl/shader/linepattern_shader.cpp
@@ -1,15 +1,15 @@
#include <mbgl/shader/linepattern_shader.hpp>
#include <mbgl/shader/linepattern.vertex.hpp>
#include <mbgl/shader/linepattern.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-LinepatternShader::LinepatternShader()
- : Shader("linepattern", shaders::linepattern::vertex, shaders::linepattern::fragment) {
- a_data = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data"));
+LinepatternShader::LinepatternShader(gl::GLObjectStore& glObjectStore)
+ : Shader("linepattern", shaders::linepattern::vertex, shaders::linepattern::fragment, glObjectStore) {
+ a_data = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"));
}
void LinepatternShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/linepattern_shader.hpp b/src/mbgl/shader/linepattern_shader.hpp
index 6c83cb0cc3..0d3e98c834 100644
--- a/src/mbgl/shader/linepattern_shader.hpp
+++ b/src/mbgl/shader/linepattern_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class LinepatternShader : public Shader {
public:
- LinepatternShader();
+ LinepatternShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/linesdf_shader.cpp b/src/mbgl/shader/linesdf_shader.cpp
index df988bb337..00adaf0c86 100644
--- a/src/mbgl/shader/linesdf_shader.cpp
+++ b/src/mbgl/shader/linesdf_shader.cpp
@@ -1,15 +1,15 @@
#include <mbgl/shader/linesdf_shader.hpp>
#include <mbgl/shader/linesdf.vertex.hpp>
#include <mbgl/shader/linesdf.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-LineSDFShader::LineSDFShader()
- : Shader("line", shaders::linesdf::vertex, shaders::linesdf::fragment) {
- a_data = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data"));
+LineSDFShader::LineSDFShader(gl::GLObjectStore& glObjectStore)
+ : Shader("line", shaders::linesdf::vertex, shaders::linesdf::fragment, glObjectStore) {
+ a_data = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data"));
}
void LineSDFShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/linesdf_shader.hpp b/src/mbgl/shader/linesdf_shader.hpp
index 2a8bdc6629..8ac0aa5793 100644
--- a/src/mbgl/shader/linesdf_shader.hpp
+++ b/src/mbgl/shader/linesdf_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class LineSDFShader : public Shader {
public:
- LineSDFShader();
+ LineSDFShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/outline_shader.cpp b/src/mbgl/shader/outline_shader.cpp
index 9cda1a1108..8c7458327f 100644
--- a/src/mbgl/shader/outline_shader.cpp
+++ b/src/mbgl/shader/outline_shader.cpp
@@ -1,14 +1,14 @@
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/outline.vertex.hpp>
#include <mbgl/shader/outline.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-OutlineShader::OutlineShader()
- : Shader("outline", shaders::outline::vertex, shaders::outline::fragment) {
+OutlineShader::OutlineShader(gl::GLObjectStore& glObjectStore)
+ : Shader("outline", shaders::outline::vertex, shaders::outline::fragment, glObjectStore) {
}
void OutlineShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/outline_shader.hpp b/src/mbgl/shader/outline_shader.hpp
index 3af9b8349f..800461bf06 100644
--- a/src/mbgl/shader/outline_shader.hpp
+++ b/src/mbgl/shader/outline_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class OutlineShader : public Shader {
public:
- OutlineShader();
+ OutlineShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/pattern_shader.cpp b/src/mbgl/shader/pattern_shader.cpp
index ef3f35c356..4f52df59fb 100644
--- a/src/mbgl/shader/pattern_shader.cpp
+++ b/src/mbgl/shader/pattern_shader.cpp
@@ -1,16 +1,17 @@
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/pattern.vertex.hpp>
#include <mbgl/shader/pattern.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-PatternShader::PatternShader()
+PatternShader::PatternShader(gl::GLObjectStore& glObjectStore)
: Shader(
"pattern",
- shaders::pattern::vertex, shaders::pattern::fragment
+ shaders::pattern::vertex, shaders::pattern::fragment,
+ glObjectStore
) {
}
diff --git a/src/mbgl/shader/pattern_shader.hpp b/src/mbgl/shader/pattern_shader.hpp
index db7901c578..8692f6ed39 100644
--- a/src/mbgl/shader/pattern_shader.hpp
+++ b/src/mbgl/shader/pattern_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class PatternShader : public Shader {
public:
- PatternShader();
+ PatternShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/plain_shader.cpp b/src/mbgl/shader/plain_shader.cpp
index 1817ffbc3d..1b5a7819b3 100644
--- a/src/mbgl/shader/plain_shader.cpp
+++ b/src/mbgl/shader/plain_shader.cpp
@@ -1,13 +1,14 @@
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/shader/plain.vertex.hpp>
#include <mbgl/shader/plain.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-PlainShader::PlainShader() : Shader("plain", shaders::plain::vertex, shaders::plain::fragment) {
+PlainShader::PlainShader(gl::GLObjectStore& glObjectStore)
+ : Shader("plain", shaders::plain::vertex, shaders::plain::fragment, glObjectStore) {
}
void PlainShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/plain_shader.hpp b/src/mbgl/shader/plain_shader.hpp
index f9b8c41a63..34ee4dcdf7 100644
--- a/src/mbgl/shader/plain_shader.hpp
+++ b/src/mbgl/shader/plain_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class PlainShader : public Shader {
public:
- PlainShader();
+ PlainShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/raster_shader.cpp b/src/mbgl/shader/raster_shader.cpp
index aaf0bfd2a5..77bcf40008 100644
--- a/src/mbgl/shader/raster_shader.cpp
+++ b/src/mbgl/shader/raster_shader.cpp
@@ -1,14 +1,14 @@
#include <mbgl/shader/raster_shader.hpp>
#include <mbgl/shader/raster.vertex.hpp>
#include <mbgl/shader/raster.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-RasterShader::RasterShader()
- : Shader("raster", shaders::raster::vertex, shaders::raster::fragment) {
+RasterShader::RasterShader(gl::GLObjectStore& glObjectStore)
+ : Shader("raster", shaders::raster::vertex, shaders::raster::fragment, glObjectStore) {
}
void RasterShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/raster_shader.hpp b/src/mbgl/shader/raster_shader.hpp
index 60b283fc2a..6a2e2ecf3e 100644
--- a/src/mbgl/shader/raster_shader.hpp
+++ b/src/mbgl/shader/raster_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class RasterShader : public Shader {
public:
- RasterShader();
+ RasterShader(gl::GLObjectStore&);
void bind(GLbyte *offset) final;
diff --git a/src/mbgl/shader/sdf_shader.cpp b/src/mbgl/shader/sdf_shader.cpp
index 97297a7baf..a972849d3d 100644
--- a/src/mbgl/shader/sdf_shader.cpp
+++ b/src/mbgl/shader/sdf_shader.cpp
@@ -1,16 +1,17 @@
#include <mbgl/shader/sdf_shader.hpp>
#include <mbgl/shader/sdf.vertex.hpp>
#include <mbgl/shader/sdf.fragment.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <cstdio>
using namespace mbgl;
-SDFShader::SDFShader() : Shader("sdf", shaders::sdf::vertex, shaders::sdf::fragment) {
- a_offset = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_offset"));
- a_data1 = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data1"));
- a_data2 = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_data2"));
+SDFShader::SDFShader(gl::GLObjectStore& glObjectStore)
+ : Shader("sdf", shaders::sdf::vertex, shaders::sdf::fragment, glObjectStore) {
+ a_offset = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_offset"));
+ a_data1 = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data1"));
+ a_data2 = MBGL_CHECK_ERROR(glGetAttribLocation(getID(), "a_data2"));
}
void SDFGlyphShader::bind(GLbyte* offset) {
diff --git a/src/mbgl/shader/sdf_shader.hpp b/src/mbgl/shader/sdf_shader.hpp
index 29dbfea047..402168de0c 100644
--- a/src/mbgl/shader/sdf_shader.hpp
+++ b/src/mbgl/shader/sdf_shader.hpp
@@ -8,7 +8,7 @@ namespace mbgl {
class SDFShader : public Shader {
public:
- SDFShader();
+ SDFShader(gl::GLObjectStore&);
UniformMatrix<4> u_matrix = {"u_matrix", *this};
UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
@@ -32,11 +32,13 @@ protected:
class SDFGlyphShader : public SDFShader {
public:
+ SDFGlyphShader(gl::GLObjectStore& glObjectStore) : SDFShader(glObjectStore) {}
void bind(GLbyte *offset) final;
};
class SDFIconShader : public SDFShader {
public:
+ SDFIconShader(gl::GLObjectStore& glObjectStore) : SDFShader(glObjectStore) {}
void bind(GLbyte *offset) final;
};
diff --git a/src/mbgl/shader/shader.cpp b/src/mbgl/shader/shader.cpp
index e8deefc8ff..8216de5b4d 100644
--- a/src/mbgl/shader/shader.cpp
+++ b/src/mbgl/shader/shader.cpp
@@ -1,5 +1,5 @@
#include <mbgl/shader/shader.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/util/stopwatch.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/platform/log.hpp>
@@ -11,94 +11,74 @@
#include <fstream>
#include <cstdio>
-using namespace mbgl;
+namespace mbgl {
-Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSource)
+Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSource, gl::GLObjectStore& glObjectStore)
: name(name_)
- , program(0)
{
util::stopwatch stopwatch("shader compilation", Event::Shader);
- program = MBGL_CHECK_ERROR(glCreateProgram());
-
- if (!compileShader(&vertShader, GL_VERTEX_SHADER, &vertSource)) {
+ program.create(glObjectStore);
+ vertexShader.create(glObjectStore);
+ if (!compileShader(vertexShader, &vertSource)) {
Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertSource);
- MBGL_CHECK_ERROR(glDeleteProgram(program));
- program = 0;
throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
}
- if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, &fragSource)) {
+ fragmentShader.create(glObjectStore);
+ if (!compileShader(fragmentShader, &fragSource)) {
Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragSource);
- MBGL_CHECK_ERROR(glDeleteShader(vertShader));
- vertShader = 0;
- MBGL_CHECK_ERROR(glDeleteProgram(program));
- program = 0;
throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
}
// Attach shaders
- MBGL_CHECK_ERROR(glAttachShader(program, vertShader));
- MBGL_CHECK_ERROR(glAttachShader(program, fragShader));
+ MBGL_CHECK_ERROR(glAttachShader(program.getID(), vertexShader.getID()));
+ MBGL_CHECK_ERROR(glAttachShader(program.getID(), fragmentShader.getID()));
{
// Link program
GLint status;
- MBGL_CHECK_ERROR(glLinkProgram(program));
+ MBGL_CHECK_ERROR(glLinkProgram(program.getID()));
- MBGL_CHECK_ERROR(glGetProgramiv(program, GL_LINK_STATUS, &status));
+ MBGL_CHECK_ERROR(glGetProgramiv(program.getID(), GL_LINK_STATUS, &status));
if (status == 0) {
GLint logLength;
- MBGL_CHECK_ERROR(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength));
+ MBGL_CHECK_ERROR(glGetProgramiv(program.getID(), GL_INFO_LOG_LENGTH, &logLength));
const auto log = std::make_unique<GLchar[]>(logLength);
if (logLength > 0) {
- MBGL_CHECK_ERROR(glGetProgramInfoLog(program, logLength, &logLength, log.get()));
+ MBGL_CHECK_ERROR(glGetProgramInfoLog(program.getID(), logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
}
-
- MBGL_CHECK_ERROR(glDeleteShader(vertShader));
- vertShader = 0;
- MBGL_CHECK_ERROR(glDeleteShader(fragShader));
- fragShader = 0;
- MBGL_CHECK_ERROR(glDeleteProgram(program));
- program = 0;
throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
}
}
- a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
+ a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program.getID(), "a_pos"));
}
+bool Shader::compileShader(gl::ShaderHolder& shader, const GLchar *source[]) {
+ GLint status = 0;
-bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source[]) {
- GLint status;
-
- *shader = MBGL_CHECK_ERROR(glCreateShader(type));
const GLsizei lengths = static_cast<GLsizei>(std::strlen(*source));
- MBGL_CHECK_ERROR(glShaderSource(*shader, 1, source, &lengths));
+ MBGL_CHECK_ERROR(glShaderSource(shader.getID(), 1, source, &lengths));
- MBGL_CHECK_ERROR(glCompileShader(*shader));
+ MBGL_CHECK_ERROR(glCompileShader(shader.getID()));
- MBGL_CHECK_ERROR(glGetShaderiv(*shader, GL_COMPILE_STATUS, &status));
+ MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_COMPILE_STATUS, &status));
if (status == 0) {
GLint logLength;
- MBGL_CHECK_ERROR(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength));
+ MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_INFO_LOG_LENGTH, &logLength));
if (logLength > 0) {
const auto log = std::make_unique<GLchar[]>(logLength);
- MBGL_CHECK_ERROR(glGetShaderInfoLog(*shader, logLength, &logLength, log.get()));
+ MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.getID(), logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
}
-
- MBGL_CHECK_ERROR(glDeleteShader(*shader));
- *shader = 0;
return false;
}
- MBGL_CHECK_ERROR(glGetShaderiv(*shader, GL_COMPILE_STATUS, &status));
+ MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_COMPILE_STATUS, &status));
if (status == GL_FALSE) {
Log::Error(Event::Shader, "Shader %s failed to compile.", name);
- MBGL_CHECK_ERROR(glDeleteShader(*shader));
- *shader = 0;
return false;
}
@@ -107,13 +87,9 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source[])
Shader::~Shader() {
if (program) {
- MBGL_CHECK_ERROR(glDetachShader(program, vertShader));
- MBGL_CHECK_ERROR(glDetachShader(program, fragShader));
- MBGL_CHECK_ERROR(glDeleteProgram(program));
- program = 0;
- MBGL_CHECK_ERROR(glDeleteShader(vertShader));
- vertShader = 0;
- MBGL_CHECK_ERROR(glDeleteShader(fragShader));
- fragShader = 0;
+ MBGL_CHECK_ERROR(glDetachShader(program.getID(), vertexShader.getID()));
+ MBGL_CHECK_ERROR(glDetachShader(program.getID(), fragmentShader.getID()));
}
}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/shader.hpp b/src/mbgl/shader/shader.hpp
index 927fdf0b0b..b543f73a6f 100644
--- a/src/mbgl/shader/shader.hpp
+++ b/src/mbgl/shader/shader.hpp
@@ -1,25 +1,21 @@
#ifndef MBGL_RENDERER_SHADER
#define MBGL_RENDERER_SHADER
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <cstdint>
-#include <array>
-#include <string>
-
namespace mbgl {
class Shader : private util::noncopyable {
public:
- Shader(const GLchar *name, const GLchar *vertex, const GLchar *fragment);
+ Shader(const GLchar *name, const GLchar *vertex, const GLchar *fragment, gl::GLObjectStore&);
~Shader();
const GLchar *name;
- GLuint program;
- inline GLuint getID() const {
- return program;
+ GLuint getID() const {
+ return program.getID();
}
virtual void bind(GLbyte *offset) = 0;
@@ -28,10 +24,11 @@ protected:
GLint a_pos = -1;
private:
- bool compileShader(GLuint *shader, GLenum type, const GLchar *source[]);
+ bool compileShader(gl::ShaderHolder&, const GLchar *source[]);
- GLuint vertShader = 0;
- GLuint fragShader = 0;
+ gl::ProgramHolder program;
+ gl::ShaderHolder vertexShader = { GL_VERTEX_SHADER };
+ gl::ShaderHolder fragmentShader = { GL_FRAGMENT_SHADER };
};
} // namespace mbgl
diff --git a/src/mbgl/shader/uniform.hpp b/src/mbgl/shader/uniform.hpp
index 0b6d574d09..5c4a2b14c4 100644
--- a/src/mbgl/shader/uniform.hpp
+++ b/src/mbgl/shader/uniform.hpp
@@ -2,7 +2,9 @@
#define MBGL_SHADER_UNIFORM
#include <mbgl/shader/shader.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+
+#include <array>
namespace mbgl {
@@ -10,7 +12,7 @@ template <typename T>
class Uniform {
public:
Uniform(const GLchar* name, const Shader& shader) : current() {
- location = MBGL_CHECK_ERROR(glGetUniformLocation(shader.program, name));
+ location = MBGL_CHECK_ERROR(glGetUniformLocation(shader.getID(), name));
}
void operator=(const T& t) {
@@ -33,7 +35,7 @@ public:
typedef std::array<float, C*R> T;
UniformMatrix(const GLchar* name, const Shader& shader) : current() {
- location = MBGL_CHECK_ERROR(glGetUniformLocation(shader.program, name));
+ location = MBGL_CHECK_ERROR(glGetUniformLocation(shader.getID(), name));
}
void operator=(const std::array<double, C*R>& t) {
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/source/source.cpp
index 7f9b47440b..8947e4f988 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/source/source.cpp
@@ -1,8 +1,8 @@
-#include <mbgl/map/source.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/map/tile.hpp>
-#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/renderer/painter.hpp>
@@ -11,8 +11,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/util/box.hpp>
-#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_update_parameters.hpp>
@@ -22,8 +20,8 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/tile_cover.hpp>
-#include <mbgl/map/vector_tile_data.hpp>
-#include <mbgl/map/raster_tile_data.hpp>
+#include <mbgl/tile/vector_tile_data.hpp>
+#include <mbgl/tile/raster_tile_data.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_parser.hpp>
#include <mbgl/gl/debugging.hpp>
@@ -70,10 +68,7 @@ bool Source::isLoading() const {
return !loaded && req.operator bool();
}
-// Note: This is a separate function that must be called exactly once after creation
-// The reason this isn't part of the constructor is that calling shared_from_this() in
-// the constructor fails.
-void Source::load() {
+void Source::load(FileSource& fileSource) {
if (url.empty()) {
// In case there is no URL set, we assume that we already have all of the data because the
// TileJSON was specified inline in the stylesheet.
@@ -88,80 +83,77 @@ void Source::load() {
}
// URL may either be a TileJSON file, or a GeoJSON file.
- FileSource* fs = util::ThreadContext::getFileSource();
- req = fs->request(Resource::source(url), [this](Response res) {
+ req = fileSource.request(Resource::source(url), [this](Response res) {
if (res.error) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
return;
- }
+ } else if (res.noContent) {
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty source")));
+ } else {
+ bool reloadTiles = false;
+
+ if (type == SourceType::Vector || type == SourceType::Raster) {
+ std::unique_ptr<SourceInfo> newInfo;
+
+ // Create a new copy of the SourceInfo object that holds the base values we've parsed
+ // from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
+ // via the URL.
+ try {
+ newInfo = StyleParser::parseTileJSON(*res.data, url, type, tileSize);
+ } catch (...) {
+ observer->onSourceError(*this, std::current_exception());
+ return;
+ }
- if (res.notModified) {
- // We got the same data back as last time. Abort early.
- return;
- }
+ // Check whether previous information specifies different tile
+ if (info && info->tiles != newInfo->tiles) {
+ reloadTiles = true;
- bool reloadTiles = false;
+ // Tile size changed: We need to recalculate the tiles we need to load because we
+ // might have to load tiles for a different zoom level
+ // This is done automatically when we trigger the onSourceLoaded observer below.
- if (type == SourceType::Vector || type == SourceType::Raster) {
- std::unique_ptr<SourceInfo> newInfo;
+ // Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
+ // loaded that are outside the new zoom range
+ // This is done automatically when we trigger the onSourceLoaded observer below.
- // Create a new copy of the SourceInfo object that holds the base values we've parsed
- // from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
- // via the URL.
- try {
- newInfo = StyleParser::parseTileJSON(*res.data, url, type);
- } catch (...) {
- observer->onSourceError(*this, std::current_exception());
- return;
- }
+ // Attribution changed: We need to notify the embedding application that this
+ // changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
+ // This is not yet implemented.
- // Check whether previous information specifies different tile
- if (info && info->tiles != newInfo->tiles) {
- reloadTiles = true;
+ // Center/bounds changed: We're not using these values currently
+ }
- // Tile size changed: We need to recalculate the tiles we need to load because we
- // might have to load tiles for a different zoom level
- // This is done automatically when we trigger the onSourceLoaded observer below.
+ info = std::move(newInfo);
+ } else if (type == SourceType::GeoJSON) {
+ info = std::make_unique<SourceInfo>();
- // Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
- // loaded that are outside the new zoom range
- // This is done automatically when we trigger the onSourceLoaded observer below.
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
+ d.Parse<0>(res.data->c_str());
- // Attribution changed: We need to notify the embedding application that this
- // changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
- // This is not yet implemented.
+ if (d.HasParseError()) {
+ std::stringstream message;
+ message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
+ return;
+ }
- // Center/bounds changed: We're not using these values currently
+ geojsonvt = StyleParser::parseGeoJSON(d);
+ reloadTiles = true;
}
- info = std::move(newInfo);
- } else if (type == SourceType::GeoJSON) {
- info = std::make_unique<SourceInfo>();
-
- rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
- d.Parse<0>(res.data->c_str());
-
- if (d.HasParseError()) {
- std::stringstream message;
- message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
- observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
- return;
+ if (reloadTiles) {
+ // Tile information changed because we got new GeoJSON data, or a new tile URL.
+ tilePtrs.clear();
+ tileDataMap.clear();
+ tiles.clear();
+ cache.clear();
}
- geojsonvt = StyleParser::parseGeoJSON(d);
- reloadTiles = true;
- }
-
- if (reloadTiles) {
- // Tile information changed because we got new GeoJSON data, or a new tile URL.
- tilePtrs.clear();
- tileDataMap.clear();
- tiles.clear();
- cache.clear();
+ loaded = true;
+ observer->onSourceLoaded(*this);
}
-
- loaded = true;
- observer->onSourceLoaded(*this);
});
}
@@ -173,14 +165,6 @@ void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transf
}
}
-void Source::drawClippingMasks(Painter &painter) {
- for (const auto& pair : tiles) {
- Tile &tile = *pair.second;
- MBGL_DEBUG_GROUP(std::string { "mask: " } + std::string(tile.id));
- painter.drawClippingMask(tile.matrix, tile.clip);
- }
-}
-
void Source::finishRender(Painter &painter) {
for (const auto& pair : tiles) {
Tile &tile = *pair.second;
@@ -271,12 +255,13 @@ TileData::State Source::addTile(const TileID& tileID, const StyleUpdateParameter
info->tiles.at(0),
parameters.texturePool,
parameters.worker,
+ parameters.fileSource,
callback);
} else {
std::unique_ptr<GeometryTileMonitor> monitor;
if (type == SourceType::Vector) {
- monitor = std::make_unique<VectorTileMonitor>(normalizedID, parameters.pixelRatio, info->tiles.at(0));
+ monitor = std::make_unique<VectorTileMonitor>(normalizedID, parameters.pixelRatio, info->tiles.at(0), parameters.fileSource);
} else if (type == SourceType::Annotations) {
monitor = std::make_unique<AnnotationTileMonitor>(normalizedID, parameters.data);
} else if (type == SourceType::GeoJSON) {
@@ -302,47 +287,6 @@ TileData::State Source::addTile(const TileID& tileID, const StyleUpdateParameter
return newState;
}
-double Source::getZoom(const TransformState& state) const {
- double offset = std::log(util::tileSize / tileSize) / std::log(2);
- return state.getZoom() + offset;
-}
-
-int32_t Source::coveringZoomLevel(const TransformState& state) const {
- double zoom = getZoom(state);
- if (type == SourceType::Raster || type == SourceType::Video) {
- zoom = ::round(zoom);
- } else {
- zoom = std::floor(zoom);
- }
- return util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
-}
-
-std::forward_list<TileID> Source::coveringTiles(const TransformState& state) const {
- int32_t z = coveringZoomLevel(state);
-
- auto actualZ = z;
- const bool reparseOverscaled =
- type == SourceType::Vector ||
- type == SourceType::Annotations;
-
- if (z < info->minZoom) return {{}};
- if (z > info->maxZoom) z = info->maxZoom;
-
- // Map four viewport corners to pixel coordinates
- box points = state.cornersToBox(z);
- const TileCoordinate center = state.pointToCoordinate({ state.getWidth() / 2.0f, state.getHeight()/ 2.0f }).zoomTo(z);
-
- std::forward_list<TileID> covering_tiles = tileCover(z, points, reparseOverscaled ? actualZ : z);
-
- covering_tiles.sort([&center](const TileID& a, const TileID& b) {
- // Sorts by distance from the box center
- return std::fabs(a.x - center.column) + std::fabs(a.y - center.row) <
- std::fabs(b.x - center.column) + std::fabs(b.y - center.row);
- });
-
- return covering_tiles;
-}
-
/**
* Recursively find children of the given tile that are already loaded.
*
@@ -352,14 +296,14 @@ std::forward_list<TileID> Source::coveringTiles(const TransformState& state) con
*
* @return boolean Whether the children found completely cover the tile.
*/
-bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, std::forward_list<TileID>& retain) {
+bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, std::vector<TileID>& retain) {
bool complete = true;
int32_t z = tileID.z;
auto ids = tileID.children(info->maxZoom);
for (const auto& child_id : ids) {
const TileData::State state = hasTile(child_id);
if (TileData::isReadyState(state)) {
- retain.emplace_front(child_id);
+ retain.emplace_back(child_id);
}
if (state != TileData::State::parsed) {
complete = false;
@@ -381,12 +325,12 @@ bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, s
*
* @return boolean Whether a parent was found.
*/
-void Source::findLoadedParent(const TileID& tileID, int32_t minCoveringZoom, std::forward_list<TileID>& retain) {
+void Source::findLoadedParent(const TileID& tileID, int32_t minCoveringZoom, std::vector<TileID>& retain) {
for (int32_t z = tileID.z - 1; z >= minCoveringZoom; --z) {
const TileID parent_id = tileID.parent(z, info->maxZoom);
const TileData::State state = hasTile(parent_id);
if (TileData::isReadyState(state)) {
- retain.emplace_front(parent_id);
+ retain.emplace_back(parent_id);
if (state == TileData::State::parsed) {
return;
}
@@ -401,17 +345,29 @@ bool Source::update(const StyleUpdateParameters& parameters) {
return allTilesUpdated;
}
- double zoom = coveringZoomLevel(parameters.transformState);
- std::forward_list<TileID> required = coveringTiles(parameters.transformState);
-
- // Determine the overzooming/underzooming amounts.
+ // Determine the overzooming/underzooming amounts and required tiles.
+ std::vector<TileID> required;
+ int32_t zoom = coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info->minZoom, info->maxZoom);
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info->minZoom, info->maxZoom);
+ if (zoom >= info->minZoom) {
+ const bool reparseOverscaled =
+ type == SourceType::Vector ||
+ type == SourceType::Annotations;
+
+ const auto actualZ = zoom;
+ if (zoom > info->maxZoom) {
+ zoom = info->maxZoom;
+ }
+
+ required = tileCover(parameters.transformState, zoom, reparseOverscaled ? actualZ : zoom);
+ }
+
// Retain is a list of tiles that we shouldn't delete, even if they are not
// the most ideal tile for the current viewport. This may include tiles like
// parent or child tiles that are *already* loaded.
- std::forward_list<TileID> retain(required);
+ std::vector<TileID> retain(required);
// Add existing child/parent tiles if the actual tile is not yet loaded
for (const auto& tileID : required) {
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/source/source.hpp
index d9146c1fdb..52c7d76baf 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/source/source.hpp
@@ -1,13 +1,15 @@
#ifndef MBGL_MAP_SOURCE
#define MBGL_MAP_SOURCE
-#include <mbgl/map/tile_cache.hpp>
-#include <mbgl/map/source_info.hpp>
+#include <mbgl/tile/tile_data.hpp>
+#include <mbgl/tile/tile_cache.hpp>
+#include <mbgl/source/source_info.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <forward_list>
+#include <vector>
#include <map>
namespace mapbox {
@@ -20,6 +22,7 @@ namespace mbgl {
class StyleUpdateParameters;
class Painter;
+class FileSource;
class FileRequest;
class TransformState;
class Tile;
@@ -49,10 +52,12 @@ public:
~Source();
bool loaded = false;
- void load();
+ void load(FileSource&);
bool isLoading() const;
bool isLoaded() const;
+ const SourceInfo* getInfo() const { return info.get(); }
+
// Request or parse all the tiles relevant for the "TransformState". This method
// will return true if all the tiles were scheduled for updating of false if
// they were not. shouldReparsePartialTiles must be set to "true" if there is
@@ -60,7 +65,6 @@ public:
bool update(const StyleUpdateParameters&);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
- void drawClippingMasks(Painter &painter);
void finishRender(Painter &painter);
std::forward_list<Tile *> getLoadedTiles() const;
@@ -83,17 +87,13 @@ private:
std::exception_ptr,
bool isNewTile);
bool handlePartialTile(const TileID&);
- bool findLoadedChildren(const TileID&, int32_t maxCoveringZoom, std::forward_list<TileID>& retain);
- void findLoadedParent(const TileID&, int32_t minCoveringZoom, std::forward_list<TileID>& retain);
- int32_t coveringZoomLevel(const TransformState&) const;
- std::forward_list<TileID> coveringTiles(const TransformState&) const;
+ bool findLoadedChildren(const TileID&, int32_t maxCoveringZoom, std::vector<TileID>& retain);
+ void findLoadedParent(const TileID&, int32_t minCoveringZoom, std::vector<TileID>& retain);
TileData::State addTile(const TileID&, const StyleUpdateParameters&);
TileData::State hasTile(const TileID&);
void updateTilePtrs();
- double getZoom(const TransformState &state) const;
-
private:
std::unique_ptr<const SourceInfo> info;
diff --git a/src/mbgl/map/source_info.hpp b/src/mbgl/source/source_info.hpp
index 2fb5c2466d..2fb5c2466d 100644
--- a/src/mbgl/map/source_info.hpp
+++ b/src/mbgl/source/source_info.hpp
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index be5c59c74c..12d12a53cb 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -1,9 +1,8 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_store.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/gl_object_store.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
@@ -144,9 +143,9 @@ void SpriteAtlas::copy(const Holder& holder, const bool wrap) {
dirty = true;
}
-void SpriteAtlas::upload() {
+void SpriteAtlas::upload(gl::GLObjectStore& glObjectStore) {
if (dirty) {
- bind();
+ bind(false, glObjectStore);
}
}
@@ -181,14 +180,14 @@ void SpriteAtlas::updateDirty() {
}
}
-void SpriteAtlas::bind(bool linear) {
+void SpriteAtlas::bind(bool linear, gl::GLObjectStore& glObjectStore) {
if (!data) {
return; // Empty atlas
}
if (!texture) {
- MBGL_CHECK_ERROR(glGenTextures(1, &texture));
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ texture.create(glObjectStore);
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
@@ -198,7 +197,7 @@ void SpriteAtlas::bind(bool linear) {
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
fullUploadRequired = true;
} else {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
}
GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST;
@@ -247,13 +246,7 @@ void SpriteAtlas::bind(bool linear) {
}
};
-SpriteAtlas::~SpriteAtlas() {
- std::lock_guard<std::recursive_mutex> lock(mtx);
- if (texture) {
- mbgl::util::ThreadContext::getGLObjectStore()->abandonTexture(texture);
- texture = 0;
- }
-}
+SpriteAtlas::~SpriteAtlas() = default;
SpriteAtlas::Holder::Holder(const std::shared_ptr<const SpriteImage>& spriteImage_,
const Rect<dimension>& pos_)
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index 73b3037ec6..ba592c5acb 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -2,7 +2,8 @@
#define MBGL_SPRITE_ATLAS
#include <mbgl/geometry/binpack.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/optional.hpp>
@@ -51,14 +52,14 @@ public:
optional<SpriteAtlasPosition> getPosition(const std::string& name, bool repeating = false);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
- void bind(bool linear = false);
+ void bind(bool linear, gl::GLObjectStore&);
// Updates sprites in the atlas texture that may have changed in the source SpriteStore object.
void updateDirty();
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
- void upload();
+ void upload(gl::GLObjectStore&);
inline dimension getWidth() const { return width; }
inline dimension getHeight() const { return height; }
@@ -94,7 +95,7 @@ private:
std::unique_ptr<uint32_t[]> data;
std::atomic<bool> dirty;
bool fullUploadRequired = true;
- GLuint texture = 0;
+ gl::TextureHolder texture;
uint32_t filter = 0;
static const int buffer = 1;
};
diff --git a/src/mbgl/sprite/sprite_store.cpp b/src/mbgl/sprite/sprite_store.cpp
index 15a345cc4d..869abab39f 100644
--- a/src/mbgl/sprite/sprite_store.cpp
+++ b/src/mbgl/sprite/sprite_store.cpp
@@ -5,7 +5,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/exception.hpp>
-#include <mbgl/util/thread_context.hpp>
#include <cassert>
#include <string>
@@ -25,7 +24,7 @@ SpriteStore::SpriteStore(float pixelRatio_)
SpriteStore::~SpriteStore() = default;
-void SpriteStore::setURL(const std::string& url) {
+void SpriteStore::load(const std::string& url, FileSource& fileSource) {
if (url.empty()) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
loaded = true;
@@ -34,37 +33,30 @@ void SpriteStore::setURL(const std::string& url) {
loader = std::make_unique<Loader>();
- FileSource* fs = util::ThreadContext::getFileSource();
- loader->jsonRequest = fs->request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
+ loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
if (res.error) {
observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
return;
- }
-
- if (res.notModified) {
- // We got the same data back as last time. Abort early.
- return;
- }
-
- if (!loader->json || *loader->json != *res.data) {
+ } else if (res.noContent) {
+ loader->json = std::make_shared<const std::string>();
+ emitSpriteLoadedIfComplete();
+ } else {
// Only trigger a sprite loaded event we got new data.
loader->json = res.data;
emitSpriteLoadedIfComplete();
}
});
- loader->spriteRequest = fs->request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
+ loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
if (res.error) {
observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
return;
- }
-
- if (res.notModified) {
- // We got the same data back as last time. Abort early.
- return;
- }
-
- if (!loader->image || *loader->image != *res.data) {
+ } else if (res.noContent) {
+ loader->image = std::make_shared<const std::string>();
+ emitSpriteLoadedIfComplete();
+ } else {
loader->image = res.data;
emitSpriteLoadedIfComplete();
}
diff --git a/src/mbgl/sprite/sprite_store.hpp b/src/mbgl/sprite/sprite_store.hpp
index 7c5fe71802..995cb81900 100644
--- a/src/mbgl/sprite/sprite_store.hpp
+++ b/src/mbgl/sprite/sprite_store.hpp
@@ -10,6 +10,8 @@
namespace mbgl {
+class FileSource;
+
class SpriteStore : private util::noncopyable {
public:
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
@@ -25,7 +27,7 @@ public:
SpriteStore(float pixelRatio);
~SpriteStore();
- void setURL(const std::string&);
+ void load(const std::string& url, FileSource&);
bool isLoaded() const {
return loaded;
diff --git a/src/mbgl/storage/http_context_base.hpp b/src/mbgl/storage/http_context_base.hpp
index b50bf11ec7..6615ea00cf 100644
--- a/src/mbgl/storage/http_context_base.hpp
+++ b/src/mbgl/storage/http_context_base.hpp
@@ -11,6 +11,7 @@ namespace mbgl {
class HTTPContextBase {
public:
static std::unique_ptr<HTTPContextBase> createContext();
+ static uint32_t maximumConcurrentRequests();
virtual ~HTTPContextBase() = default;
virtual HTTPRequestBase* createRequest(const Resource&, HTTPRequestBase::Callback) = 0;
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 6f727a6027..d5b88d9292 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -49,6 +49,7 @@ Resource Resource::glyphs(const std::string& urlTemplate, const std::string& fon
}
Resource Resource::tile(const std::string& urlTemplate, float pixelRatio, int32_t x, int32_t y, int8_t z) {
+ bool supportsRatio = urlTemplate.find("{ratio}") != std::string::npos;
return Resource {
Resource::Kind::Tile,
util::replaceTokens(urlTemplate, [&](const std::string& token) {
@@ -71,7 +72,7 @@ Resource Resource::tile(const std::string& urlTemplate, float pixelRatio, int32_
}),
Resource::TileData {
urlTemplate,
- uint8_t(pixelRatio > 1.0 ? 2 : 1),
+ uint8_t(supportsRatio && pixelRatio > 1.0 ? 2 : 1),
x,
y,
z
diff --git a/src/mbgl/storage/response.cpp b/src/mbgl/storage/response.cpp
index 22263d2ebb..644d73d286 100644
--- a/src/mbgl/storage/response.cpp
+++ b/src/mbgl/storage/response.cpp
@@ -1,6 +1,9 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/util/chrono.hpp>
+#include <iostream>
+#include <cassert>
+
namespace mbgl {
Response::Response(const Response& res) {
@@ -9,6 +12,7 @@ Response::Response(const Response& res) {
Response& Response::operator=(const Response& res) {
error = res.error ? std::make_unique<Error>(*res.error) : nullptr;
+ noContent = res.noContent;
notModified = res.notModified;
data = res.data;
modified = res.modified;
@@ -21,4 +25,23 @@ Response::Error::Error(Reason reason_, const std::string& message_)
: reason(reason_), message(message_) {
}
+std::ostream& operator<<(std::ostream& os, Response::Error::Reason r) {
+ switch (r) {
+ case Response::Error::Reason::Success:
+ return os << "Response::Error::Reason::NotFound";
+ case Response::Error::Reason::NotFound:
+ return os << "Response::Error::Reason::NotFound";
+ case Response::Error::Reason::Server:
+ return os << "Response::Error::Reason::Server";
+ case Response::Error::Reason::Connection:
+ return os << "Response::Error::Reason::Connection";
+ case Response::Error::Reason::Other:
+ return os << "Response::Error::Reason::Other";
+ }
+
+ // The above switch is exhaustive, but placate GCC nonetheless:
+ assert(false);
+ return os;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/storage/sqlite_cache.hpp b/src/mbgl/storage/sqlite_cache.hpp
deleted file mode 100644
index b5a7cbcc07..0000000000
--- a/src/mbgl/storage/sqlite_cache.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_SQLITE_CACHE
-#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/chrono.hpp>
-
-#include <functional>
-#include <memory>
-#include <string>
-
-namespace mbgl {
-
-class Resource;
-class Response;
-class WorkRequest;
-
-namespace util {
-template <typename T> class Thread;
-} // namespace util
-
-class SQLiteCache : private util::noncopyable {
-public:
- static std::shared_ptr<SQLiteCache> getShared(const std::string &path = ":memory:");
-
- SQLiteCache(const std::string &path = ":memory:");
- ~SQLiteCache();
-
- void setMaximumCacheSize(uint64_t size);
- void setMaximumCacheEntrySize(uint64_t size);
-
- using Callback = std::function<void(std::unique_ptr<Response>)>;
-
- std::unique_ptr<WorkRequest> get(const Resource&, Callback);
- void put(const Resource&, const Response&);
-
- class Impl;
-
-private:
- const std::unique_ptr<util::Thread<Impl>> thread;
-};
-
-} // namespace mbgl
-
-#endif
diff --git a/src/mbgl/style/filter_expression.cpp b/src/mbgl/style/filter_expression.cpp
index e8231b82e0..660c978f0d 100644
--- a/src/mbgl/style/filter_expression.cpp
+++ b/src/mbgl/style/filter_expression.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/filter_expression.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/platform/log.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/function.hpp b/src/mbgl/style/function.hpp
index 4d2e4fcbd7..160f5be390 100644
--- a/src/mbgl/style/function.hpp
+++ b/src/mbgl/style/function.hpp
@@ -27,6 +27,9 @@ public:
T evaluate(const StyleCalculationParameters&) const;
+ float getBase() const { return base; }
+ const std::vector<std::pair<float, T>>& getStops() const { return stops; }
+
private:
float base = 1;
std::vector<std::pair<float, T>> stops;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 1ffd75bf69..e5ba08e57f 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -1,7 +1,7 @@
#include <mbgl/style/style.hpp>
#include <mbgl/map/map_data.hpp>
-#include <mbgl/map/source.hpp>
-#include <mbgl/map/tile.hpp>
+#include <mbgl/source/source.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/layer/custom_layer.hpp>
@@ -27,9 +27,10 @@
namespace mbgl {
-Style::Style(MapData& data_)
+Style::Style(MapData& data_, FileSource& fileSource_)
: data(data_),
- glyphStore(std::make_unique<GlyphStore>()),
+ fileSource(fileSource_),
+ glyphStore(std::make_unique<GlyphStore>(fileSource)),
glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
spriteStore(std::make_unique<SpriteStore>(data.pixelRatio)),
spriteAtlas(std::make_unique<SpriteAtlas>(1024, 1024, data.pixelRatio, *spriteStore)),
@@ -55,7 +56,7 @@ void Style::setJSON(const std::string& json, const std::string&) {
}
glyphStore->setURL(parser.glyphURL);
- spriteStore->setURL(parser.spriteURL);
+ spriteStore->load(parser.spriteURL, fileSource);
loaded = true;
}
@@ -116,13 +117,14 @@ void Style::removeLayer(const std::string& id) {
}
void Style::update(const TransformState& transform,
- TexturePool& texturePool) {
+ gl::TexturePool& texturePool) {
bool allTilesUpdated = true;
StyleUpdateParameters parameters(data.pixelRatio,
data.getDebug(),
data.getAnimationTime(),
transform,
workers,
+ fileSource,
texturePool,
shouldReparsePartialTiles,
data.mode,
@@ -180,7 +182,9 @@ void Style::recalculate(float z) {
Source* source = getSource(layer->source);
if (source && layer->needsRendering()) {
source->enabled = true;
- if (!source->loaded && !source->isLoading()) source->load();
+ if (!source->loaded && !source->isLoading()) {
+ source->load(fileSource);
+ }
}
}
}
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index 7bd98a7552..82c048b195 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -3,7 +3,7 @@
#include <mbgl/style/zoom_history.hpp>
-#include <mbgl/map/source.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/sprite/sprite_store.hpp>
@@ -19,6 +19,7 @@
namespace mbgl {
class MapData;
+class FileSource;
class GlyphAtlas;
class GlyphStore;
class SpriteStore;
@@ -26,11 +27,11 @@ class SpriteAtlas;
class LineAtlas;
class StyleLayer;
class TransformState;
-class TexturePool;
-
class Tile;
class Bucket;
+namespace gl { class TexturePool; }
+
struct RenderItem {
inline RenderItem(const StyleLayer& layer_,
const Tile* tile_ = nullptr,
@@ -54,7 +55,7 @@ class Style : public GlyphStore::Observer,
public Source::Observer,
public util::noncopyable {
public:
- Style(MapData&);
+ Style(MapData&, FileSource&);
~Style();
class Observer : public GlyphStore::Observer,
@@ -79,7 +80,7 @@ public:
// Fetch the tiles needed by the current viewport and emit a signal when
// a tile is ready so observers can render the tile.
- void update(const TransformState&, TexturePool&);
+ void update(const TransformState&, gl::TexturePool&);
void cascade();
void recalculate(float z);
@@ -107,6 +108,7 @@ public:
void dumpDebugLogs() const;
MapData& data;
+ FileSource& fileSource;
std::unique_ptr<GlyphStore> glyphStore;
std::unique_ptr<GlyphAtlas> glyphAtlas;
std::unique_ptr<SpriteStore> spriteStore;
diff --git a/src/mbgl/style/style_bucket_parameters.cpp b/src/mbgl/style/style_bucket_parameters.cpp
index e8303e3d8f..7bde1fd80e 100644
--- a/src/mbgl/style/style_bucket_parameters.cpp
+++ b/src/mbgl/style/style_bucket_parameters.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/style_bucket_parameters.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/style_bucket_parameters.hpp b/src/mbgl/style/style_bucket_parameters.hpp
index 3329cac032..134850066d 100644
--- a/src/mbgl/style/style_bucket_parameters.hpp
+++ b/src/mbgl/style/style_bucket_parameters.hpp
@@ -3,7 +3,7 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/style/filter_expression.hpp>
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <functional>
diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp
index 764906576f..fa09ee2e82 100644
--- a/src/mbgl/style/style_layer.hpp
+++ b/src/mbgl/style/style_layer.hpp
@@ -23,11 +23,18 @@ public:
virtual ~StyleLayer() = default;
// Check whether this layer is of the given subtype.
- template <class T> bool is() const { return dynamic_cast<const T*>(this); }
+ template <class T>
+ bool is() const;
// Dynamically cast this layer to the given subtype.
- template <class T> T* as() { return dynamic_cast< T*>(this); }
- template <class T> const T* as() const { return dynamic_cast<const T*>(this); }
+ template <class T>
+ T* as() {
+ return is<T>() ? reinterpret_cast<T*>(this) : nullptr;
+ }
+ template <class T>
+ const T* as() const {
+ return is<T>() ? reinterpret_cast<const T*>(this) : nullptr;
+ }
// Create a copy of this layer.
virtual std::unique_ptr<StyleLayer> clone() const = 0;
@@ -64,10 +71,22 @@ public:
VisibilityType visibility = VisibilityType::Visible;
protected:
- StyleLayer() = default;
+ enum class Type {
+ Fill,
+ Line,
+ Circle,
+ Symbol,
+ Raster,
+ Background,
+ Custom,
+ };
+
+ StyleLayer(Type type_) : type(type_) {}
StyleLayer(const StyleLayer&) = default;
StyleLayer& operator=(const StyleLayer&) = delete;
+ const Type type;
+
// Stores what render passes this layer is currently enabled for. This depends on the
// evaluated StyleProperties object and is updated accordingly.
RenderPass passes = RenderPass::None;
diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 7d53d603e5..7c2a94b206 100644
--- a/src/mbgl/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
@@ -18,6 +18,7 @@
#include <algorithm>
#include <sstream>
+#include <set>
namespace mbgl {
@@ -255,7 +256,7 @@ std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> StyleParser::parseGeoJSON(const JS
}
}
-std::unique_ptr<SourceInfo> StyleParser::parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type) {
+std::unique_ptr<SourceInfo> StyleParser::parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type, uint16_t tileSize) {
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
document.Parse<0>(json.c_str());
@@ -268,11 +269,10 @@ std::unique_ptr<SourceInfo> StyleParser::parseTileJSON(const std::string& json,
std::unique_ptr<SourceInfo> result = StyleParser::parseTileJSON(document);
// TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
- if (type == SourceType::Raster && util::mapbox::isMapboxURL(sourceURL)) {
- std::transform(result->tiles.begin(),
- result->tiles.end(),
- result->tiles.begin(),
- util::mapbox::normalizeRasterTileURL);
+ if (util::mapbox::isMapboxURL(sourceURL)) {
+ for (auto& url : result->tiles) {
+ url = util::mapbox::canonicalizeTileURL(url, type, tileSize);
+ }
}
return result;
@@ -484,4 +484,23 @@ void StyleParser::parseVisibility(StyleLayer& layer, const JSValue& value) {
layer.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
}
+std::vector<std::string> StyleParser::fontStacks() const {
+ std::set<std::string> result;
+
+ for (const auto& layer : layers) {
+ if (layer->is<SymbolLayer>()) {
+ LayoutProperty<std::string> property = layer->as<SymbolLayer>()->layout.text.font;
+ if (property.parsedValue) {
+ for (const auto& stop : property.parsedValue->getStops()) {
+ result.insert(stop.second);
+ }
+ } else {
+ result.insert(property.value);
+ }
+ }
+ }
+
+ return std::vector<std::string>(result.begin(), result.end());
+}
+
} // namespace mbgl
diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp
index 69bd8a3bf9..280cda530b 100644
--- a/src/mbgl/style/style_parser.hpp
+++ b/src/mbgl/style/style_parser.hpp
@@ -2,7 +2,7 @@
#define MBGL_STYLE_STYLE_PARSER
#include <mbgl/style/style_layer.hpp>
-#include <mbgl/map/source.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <vector>
@@ -28,7 +28,10 @@ public:
std::vector<std::unique_ptr<Source>> sources;
std::vector<std::unique_ptr<StyleLayer>> layers;
- static std::unique_ptr<SourceInfo> parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType);
+ // Statically evaluate layer properties to determine what font stacks are used.
+ std::vector<std::string> fontStacks() const;
+
+ static std::unique_ptr<SourceInfo> parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType, uint16_t tileSize);
static std::unique_ptr<SourceInfo> parseTileJSON(const JSValue&);
static std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> parseGeoJSON(const JSValue&);
diff --git a/src/mbgl/style/style_update_parameters.hpp b/src/mbgl/style/style_update_parameters.hpp
index 0a646219f0..9ea7e112eb 100644
--- a/src/mbgl/style/style_update_parameters.hpp
+++ b/src/mbgl/style/style_update_parameters.hpp
@@ -7,9 +7,10 @@ namespace mbgl {
class TransformState;
class Worker;
-class TexturePool;
+class FileSource;
class MapData;
class Style;
+namespace gl { class TexturePool; }
class StyleUpdateParameters {
public:
@@ -18,7 +19,8 @@ public:
TimePoint animationTime_,
const TransformState& transformState_,
Worker& worker_,
- TexturePool& texturePool_,
+ FileSource& fileSource_,
+ gl::TexturePool& texturePool_,
bool shouldReparsePartialTiles_,
const MapMode mode_,
MapData& data_,
@@ -28,6 +30,7 @@ public:
animationTime(animationTime_),
transformState(transformState_),
worker(worker_),
+ fileSource(fileSource_),
texturePool(texturePool_),
shouldReparsePartialTiles(shouldReparsePartialTiles_),
mode(mode_),
@@ -39,7 +42,8 @@ public:
TimePoint animationTime;
const TransformState& transformState;
Worker& worker;
- TexturePool& texturePool;
+ FileSource& fileSource;
+ gl::TexturePool& texturePool;
bool shouldReparsePartialTiles;
const MapMode mode;
diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp
index 1a2142bfb2..7a129d692c 100644
--- a/src/mbgl/text/get_anchors.cpp
+++ b/src/mbgl/text/get_anchors.cpp
@@ -10,14 +10,19 @@ namespace mbgl {
Anchors resample(const std::vector<Coordinate> &line, const float offset, const float spacing,
const float angleWindowSize, const float maxAngle, const float labelLength, const bool continuedLine, const bool placeAtMiddle) {
+ const float halfLabelLength = labelLength / 2.0f;
+ float lineLength = 0;
+ for (auto it = line.begin(), end = line.end() - 1; it != end; it++) {
+ lineLength += util::dist<float>(*(it), *(it + 1));
+ }
+
float distance = 0;
float markedDistance = offset - spacing;
Anchors anchors;
- auto end = line.end() - 1;
int i = 0;
- for (auto it = line.begin(); it != end; it++, i++) {
+ for (auto it = line.begin(), end = line.end() - 1; it != end; it++, i++) {
const Coordinate &a = *(it);
const Coordinate &b = *(it + 1);
@@ -31,7 +36,12 @@ Anchors resample(const std::vector<Coordinate> &line, const float offset, const
x = util::interpolate(float(a.x), float(b.x), t),
y = util::interpolate(float(a.y), float(b.y), t);
- if (x >= 0 && x < util::EXTENT && y >= 0 && y < util::EXTENT) {
+ // Check that the point is within the tile boundaries and that
+ // the label would fit before the beginning and end of the line
+ // if placed at this point.
+ if (x >= 0 && x < util::EXTENT && y >= 0 && y < util::EXTENT &&
+ markedDistance - halfLabelLength >= 0.0f &&
+ markedDistance + halfLabelLength <= lineLength) {
Anchor anchor(::round(x), ::round(y), angle, 0.5f, i);
if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index 0dfed6b430..c9466e8652 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -8,7 +8,6 @@
#include <mbgl/util/exception.hpp>
#include <mbgl/util/pbf.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/token.hpp>
#include <mbgl/util/url.hpp>
@@ -64,29 +63,29 @@ namespace mbgl {
GlyphPBF::GlyphPBF(GlyphStore* store,
const std::string& fontStack,
const GlyphRange& glyphRange,
- GlyphStore::Observer* observer_)
+ GlyphStore::Observer* observer_,
+ FileSource& fileSource)
: parsed(false),
observer(observer_) {
- FileSource* fs = util::ThreadContext::getFileSource();
- req = fs->request(Resource::glyphs(store->getURL(), fontStack, glyphRange), [this, store, fontStack, glyphRange](Response res) {
+ req = fileSource.request(Resource::glyphs(store->getURL(), fontStack, glyphRange), [this, store, fontStack, glyphRange](Response res) {
if (res.error) {
observer->onGlyphsError(fontStack, glyphRange, std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
return;
- }
-
- if (res.notModified) {
- return;
- }
+ } else if (res.noContent) {
+ parsed = true;
+ observer->onGlyphsLoaded(fontStack, glyphRange);
+ } else {
+ try {
+ parseGlyphPBF(**store->getFontStack(fontStack), *res.data);
+ } catch (...) {
+ observer->onGlyphsError(fontStack, glyphRange, std::current_exception());
+ return;
+ }
- try {
- parseGlyphPBF(**store->getFontStack(fontStack), *res.data);
- } catch (...) {
- observer->onGlyphsError(fontStack, glyphRange, std::current_exception());
- return;
+ parsed = true;
+ observer->onGlyphsLoaded(fontStack, glyphRange);
}
-
- parsed = true;
- observer->onGlyphsLoaded(fontStack, glyphRange);
});
}
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
index 9e2ee4eacf..016792aae8 100644
--- a/src/mbgl/text/glyph_pbf.hpp
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -14,13 +14,15 @@ namespace mbgl {
class FontStack;
class FileRequest;
+class FileSource;
class GlyphPBF : private util::noncopyable {
public:
GlyphPBF(GlyphStore* store,
const std::string& fontStack,
const GlyphRange&,
- GlyphStore::Observer*);
+ GlyphStore::Observer*,
+ FileSource&);
~GlyphPBF();
bool isParsed() const {
diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp
index a3d1530e3d..1c75f7191e 100644
--- a/src/mbgl/text/glyph_store.cpp
+++ b/src/mbgl/text/glyph_store.cpp
@@ -7,7 +7,10 @@
namespace mbgl {
-GlyphStore::GlyphStore() = default;
+GlyphStore::GlyphStore(FileSource& fileSource_)
+ : fileSource(fileSource_) {
+}
+
GlyphStore::~GlyphStore() = default;
void GlyphStore::requestGlyphRange(const std::string& fontStackName, const GlyphRange& range) {
@@ -22,7 +25,7 @@ void GlyphStore::requestGlyphRange(const std::string& fontStackName, const Glyph
}
rangeSets.emplace(range,
- std::make_unique<GlyphPBF>(this, fontStackName, range, observer));
+ std::make_unique<GlyphPBF>(this, fontStackName, range, observer, fileSource));
}
diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp
index 2236bce38c..6829397851 100644
--- a/src/mbgl/text/glyph_store.hpp
+++ b/src/mbgl/text/glyph_store.hpp
@@ -14,6 +14,7 @@
namespace mbgl {
+class FileSource;
class GlyphPBF;
// The GlyphStore manages the loading and storage of Glyphs
@@ -29,7 +30,7 @@ public:
virtual void onGlyphsError(const std::string& /* fontStack */, const GlyphRange&, std::exception_ptr) {};
};
- GlyphStore();
+ GlyphStore(FileSource&);
~GlyphStore();
util::exclusive<FontStack> getFontStack(const std::string& fontStack);
@@ -54,6 +55,7 @@ public:
private:
void requestGlyphRange(const std::string& fontStackName, const GlyphRange& range);
+ FileSource& fileSource;
std::string glyphURL;
std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index fd27fa5917..6f3cbc10d1 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_ANNOTATION_GEOJSON_VT_TILE
#define MBGL_ANNOTATION_GEOJSON_VT_TILE
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/map/tile_id.hpp>
#include <unordered_map>
diff --git a/src/mbgl/map/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 82affc689f..fa41481d4d 100644
--- a/src/mbgl/map/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/filter_expression_private.hpp>
diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 5cb2f96fdc..5cb2f96fdc 100644
--- a/src/mbgl/map/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
diff --git a/src/mbgl/tile/raster_tile_data.cpp b/src/mbgl/tile/raster_tile_data.cpp
new file mode 100644
index 0000000000..3f26bbdfdd
--- /dev/null
+++ b/src/mbgl/tile/raster_tile_data.cpp
@@ -0,0 +1,83 @@
+#include <mbgl/tile/raster_tile_data.hpp>
+#include <mbgl/source/source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/worker.hpp>
+#include <mbgl/util/work_request.hpp>
+
+using namespace mbgl;
+
+RasterTileData::RasterTileData(const TileID& id_,
+ float pixelRatio,
+ const std::string& urlTemplate,
+ gl::TexturePool &texturePool_,
+ Worker& worker_,
+ FileSource& fileSource,
+ const std::function<void(std::exception_ptr)>& callback)
+ : TileData(id_),
+ texturePool(texturePool_),
+ worker(worker_) {
+ state = State::loading;
+
+ const Resource resource = Resource::tile(urlTemplate, pixelRatio, id.x, id.y, id.sourceZ);
+ req = fileSource.request(resource, [callback, this](Response res) {
+ if (res.error) {
+ callback(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ modified = res.modified;
+ expires = res.expires;
+ } else if (res.noContent) {
+ state = State::parsed;
+ modified = res.modified;
+ expires = res.expires;
+ workRequest.reset();
+ bucket.reset();
+ callback(nullptr);
+ } else {
+ modified = res.modified;
+ expires = res.expires;
+
+ // Only overwrite the state when we didn't have a previous tile.
+ if (state == State::loading) {
+ state = State::loaded;
+ }
+
+ workRequest.reset();
+ workRequest = worker.parseRasterTile(std::make_unique<RasterBucket>(texturePool), res.data, [this, callback] (RasterTileParseResult result) {
+ workRequest.reset();
+ if (state != State::loaded) {
+ return;
+ }
+
+ std::exception_ptr error;
+ if (result.is<std::unique_ptr<Bucket>>()) {
+ state = State::parsed;
+ bucket = std::move(result.get<std::unique_ptr<Bucket>>());
+ } else {
+ error = result.get<std::exception_ptr>();
+ state = State::obsolete;
+ bucket.reset();
+ }
+
+ callback(error);
+ });
+ }
+ });
+}
+
+RasterTileData::~RasterTileData() {
+ cancel();
+}
+
+Bucket* RasterTileData::getBucket(StyleLayer const&) {
+ return bucket.get();
+}
+
+void RasterTileData::cancel() {
+ if (state != State::obsolete) {
+ state = State::obsolete;
+ }
+ req = nullptr;
+ workRequest.reset();
+}
diff --git a/src/mbgl/map/raster_tile_data.hpp b/src/mbgl/tile/raster_tile_data.hpp
index e68fbc94c5..59eee88496 100644
--- a/src/mbgl/map/raster_tile_data.hpp
+++ b/src/mbgl/tile/raster_tile_data.hpp
@@ -1,23 +1,25 @@
#ifndef MBGL_MAP_RASTER_TILE_DATA
#define MBGL_MAP_RASTER_TILE_DATA
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
namespace mbgl {
+class FileSource;
class FileRequest;
class StyleLayer;
-class TexturePool;
class WorkRequest;
+namespace gl { class TexturePool; }
class RasterTileData : public TileData {
public:
RasterTileData(const TileID&,
float pixelRatio,
const std::string& urlTemplate,
- TexturePool&,
+ gl::TexturePool&,
Worker&,
+ FileSource&,
const std::function<void(std::exception_ptr)>& callback);
~RasterTileData();
@@ -25,7 +27,7 @@ public:
Bucket* getBucket(StyleLayer const &layer_desc) override;
private:
- TexturePool& texturePool;
+ gl::TexturePool& texturePool;
Worker& worker;
std::unique_ptr<FileRequest> req;
std::unique_ptr<Bucket> bucket;
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
new file mode 100644
index 0000000000..a1d36421a4
--- /dev/null
+++ b/src/mbgl/tile/tile.cpp
@@ -0,0 +1,3 @@
+#include <mbgl/tile/tile.hpp>
+
+using namespace mbgl;
diff --git a/src/mbgl/map/tile.hpp b/src/mbgl/tile/tile.hpp
index 8b9030f1bd..8b9030f1bd 100644
--- a/src/mbgl/map/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
diff --git a/src/mbgl/map/tile_cache.cpp b/src/mbgl/tile/tile_cache.cpp
index 2d1a0da96c..423b355827 100644
--- a/src/mbgl/map/tile_cache.cpp
+++ b/src/mbgl/tile/tile_cache.cpp
@@ -1,4 +1,5 @@
-#include <mbgl/map/tile_cache.hpp>
+#include <mbgl/tile/tile_cache.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <cassert>
diff --git a/src/mbgl/map/tile_cache.hpp b/src/mbgl/tile/tile_cache.hpp
index e39db0ffae..4d0b42242a 100644
--- a/src/mbgl/map/tile_cache.hpp
+++ b/src/mbgl/tile/tile_cache.hpp
@@ -1,13 +1,14 @@
#ifndef MBGL_MAP_TILE_CACHE
#define MBGL_MAP_TILE_CACHE
-#include <mbgl/map/tile_data.hpp>
-
#include <list>
+#include <memory>
#include <unordered_map>
namespace mbgl {
+class TileData;
+
class TileCache {
public:
TileCache(size_t size_ = 0) : size(size_) {}
@@ -18,6 +19,7 @@ public:
std::shared_ptr<TileData> get(uint64_t key);
bool has(uint64_t key);
void clear();
+
private:
std::unordered_map<uint64_t, std::shared_ptr<TileData>> tiles;
std::list<uint64_t> orderedKeys;
diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/tile/tile_data.cpp
index edfe4d7ada..46ce64771c 100644
--- a/src/mbgl/map/tile_data.cpp
+++ b/src/mbgl/tile/tile_data.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/util/string.hpp>
diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/tile/tile_data.hpp
index 90196f8a42..90196f8a42 100644
--- a/src/mbgl/map/tile_data.hpp
+++ b/src/mbgl/tile/tile_data.hpp
diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/tile/tile_worker.cpp
index edbd392057..917b61fde9 100644
--- a/src/mbgl/map/tile_worker.cpp
+++ b/src/mbgl/tile/tile_worker.cpp
@@ -1,6 +1,6 @@
#include <mbgl/text/collision_tile.hpp>
-#include <mbgl/map/tile_worker.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/tile_worker.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket_parameters.hpp>
#include <mbgl/layer/background_layer.hpp>
diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/tile/tile_worker.hpp
index bcd8e59bf9..08048c134b 100644
--- a/src/mbgl/map/tile_worker.hpp
+++ b/src/mbgl/tile/tile_worker.hpp
@@ -4,7 +4,7 @@
#include <mapbox/variant.hpp>
#include <mbgl/map/mode.hpp>
-#include <mbgl/map/tile_data.hpp>
+#include <mbgl/tile/tile_data.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/text/placement_config.hpp>
diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index 17746a26a1..9e35debbff 100644
--- a/src/mbgl/map/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -1,9 +1,8 @@
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/map/source.hpp>
+#include <mbgl/tile/vector_tile.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/url.hpp>
#include <utility>
@@ -182,31 +181,25 @@ util::ptr<const GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i)
return std::make_shared<VectorTileFeature>(features.at(i), *this);
}
-VectorTileMonitor::VectorTileMonitor(const TileID& tileID_, float pixelRatio_, const std::string& urlTemplate_)
+VectorTileMonitor::VectorTileMonitor(const TileID& tileID_, float pixelRatio_, const std::string& urlTemplate_, FileSource& fileSource_)
: tileID(tileID_),
pixelRatio(pixelRatio_),
- urlTemplate(urlTemplate_) {
+ urlTemplate(urlTemplate_),
+ fileSource(fileSource_) {
}
std::unique_ptr<FileRequest> VectorTileMonitor::monitorTile(const GeometryTileMonitor::Callback& callback) {
const Resource resource = Resource::tile(urlTemplate, pixelRatio, tileID.x, tileID.y, tileID.sourceZ);
- return util::ThreadContext::getFileSource()->request(resource, [callback, this](Response res) {
- if (res.notModified) {
- // We got the same data again. Abort early.
- return;
- }
-
+ return fileSource.request(resource, [callback, this](Response res) {
if (res.error) {
- if (res.error->reason == Response::Error::Reason::NotFound) {
- callback(nullptr, nullptr, res.modified, res.expires);
- return;
- } else {
- callback(std::make_exception_ptr(std::runtime_error(res.error->message)), nullptr, res.modified, res.expires);
- return;
- }
+ callback(std::make_exception_ptr(std::runtime_error(res.error->message)), nullptr, res.modified, res.expires);
+ } else if (res.notModified) {
+ return;
+ } else if (res.noContent) {
+ callback(nullptr, nullptr, res.modified, res.expires);
+ } else {
+ callback(nullptr, std::make_unique<VectorTile>(res.data), res.modified, res.expires);
}
-
- callback(nullptr, std::make_unique<VectorTile>(res.data), res.modified, res.expires);
});
}
diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp
index 8550b1c55a..48e501cbd7 100644
--- a/src/mbgl/map/vector_tile.hpp
+++ b/src/mbgl/tile/vector_tile.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_MAP_VECTOR_TILE
#define MBGL_MAP_VECTOR_TILE
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/util/pbf.hpp>
@@ -59,10 +59,11 @@ private:
};
class TileID;
+class FileSource;
class VectorTileMonitor : public GeometryTileMonitor {
public:
- VectorTileMonitor(const TileID&, float pixelRatio, const std::string& urlTemplate);
+ VectorTileMonitor(const TileID&, float pixelRatio, const std::string& urlTemplate, FileSource&);
std::unique_ptr<FileRequest> monitorTile(const GeometryTileMonitor::Callback&) override;
@@ -70,6 +71,7 @@ private:
TileID tileID;
float pixelRatio;
std::string urlTemplate;
+ FileSource& fileSource;
};
} // namespace mbgl
diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
index 27172a3e63..d2eecab975 100644
--- a/src/mbgl/map/vector_tile_data.cpp
+++ b/src/mbgl/tile/vector_tile_data.cpp
@@ -1,5 +1,5 @@
-#include <mbgl/map/vector_tile_data.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/vector_tile_data.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/util/worker.hpp>
#include <mbgl/util/work_request.hpp>
diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp
index b61b2a25a0..d0b599c4cf 100644
--- a/src/mbgl/map/vector_tile_data.hpp
+++ b/src/mbgl/tile/vector_tile_data.hpp
@@ -1,8 +1,8 @@
#ifndef MBGL_MAP_VECTOR_TILE_DATA
#define MBGL_MAP_VECTOR_TILE_DATA
-#include <mbgl/map/tile_data.hpp>
-#include <mbgl/map/tile_worker.hpp>
+#include <mbgl/tile/tile_data.hpp>
+#include <mbgl/tile/tile_worker.hpp>
#include <mbgl/text/placement_config.hpp>
#include <atomic>
diff --git a/src/mbgl/util/box.hpp b/src/mbgl/util/box.hpp
deleted file mode 100644
index 2806fb95fc..0000000000
--- a/src/mbgl/util/box.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef MBGL_UTIL_BOX
-#define MBGL_UTIL_BOX
-
-#include <mbgl/util/tile_coordinate.hpp>
-
-namespace mbgl {
-
-struct box {
- box(TileCoordinate tl_, TileCoordinate tr_, TileCoordinate br_, TileCoordinate bl_) :
- tl(tl_), tr(tr_), br(br_), bl(bl_) {}
- TileCoordinate tl, tr, br, bl;
-};
-
-} // namespace mbgl
-
-#endif
diff --git a/src/mbgl/util/clip_id.cpp b/src/mbgl/util/clip_id.cpp
index b89315d97b..47a5877bb6 100644
--- a/src/mbgl/util/clip_id.cpp
+++ b/src/mbgl/util/clip_id.cpp
@@ -2,7 +2,8 @@
#include <mbgl/platform/log.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/map/tile.hpp>
+#include <mbgl/util/std.hpp>
+#include <mbgl/tile/tile.hpp>
#include <list>
#include <vector>
@@ -10,13 +11,14 @@
#include <cassert>
#include <iostream>
#include <algorithm>
+#include <iterator>
namespace mbgl {
-ClipIDGenerator::Leaf::Leaf(Tile &tile_) : tile(tile_) {}
+ClipIDGenerator::Leaf::Leaf(TileID id_, ClipID& clip_) : id(id_), clip(clip_) {}
void ClipIDGenerator::Leaf::add(const TileID &p) {
- if (p.isChildOf(tile.id)) {
+ if (p.isChildOf(id)) {
// Ensure that no already present child is a parent of the new p.
for (const auto& child : children) {
if (p.isChildOf(child))
@@ -27,27 +29,16 @@ void ClipIDGenerator::Leaf::add(const TileID &p) {
}
bool ClipIDGenerator::Leaf::operator==(const Leaf &other) const {
- return tile.id == other.tile.id && children == other.children;
-}
-
-bool ClipIDGenerator::reuseExisting(Leaf &leaf) {
- for (const auto& pool : pools) {
- auto existing = std::find(pool.begin(), pool.end(), leaf);
- if (existing != pool.end()) {
- leaf.tile.clip = existing->tile.clip;
- return true;
- }
- }
- return false;
+ return id == other.id && children == other.children;
}
void ClipIDGenerator::update(std::forward_list<Tile *> tiles) {
- Pool pool;
-
tiles.sort([](const Tile *a, const Tile *b) {
return a->id < b->id;
});
+ std::size_t size = 0;
+
const auto end = tiles.end();
for (auto it = tiles.begin(); it != end; it++) {
if (!*it) {
@@ -56,37 +47,49 @@ void ClipIDGenerator::update(std::forward_list<Tile *> tiles) {
}
Tile &tile = **it;
- Leaf clip { tile };
+ // Use the actual zoom level for computing the clipping mask.
+ Leaf leaf{ TileID{ tile.id.sourceZ, tile.id.x, tile.id.y, tile.id.sourceZ }, tile.clip };
// Try to add all remaining ids as children. We sorted the tile list
// by z earlier, so all preceding items cannot be children of the current
// tile.
for (auto child_it = std::next(it); child_it != end; child_it++) {
- clip.add((*child_it)->id);
+ // Use the actual zoom level for computing the clipping mask.
+ const auto& childID = (*child_it)->id;
+ leaf.add(TileID { childID.sourceZ, childID.x, childID.y, childID.sourceZ });
}
- clip.children.sort();
+ leaf.children.sort();
// Loop through all existing pools and try to find a matching ClipID.
- if (!reuseExisting(clip)) {
+ auto existing = std::find(pool.begin(), pool.end(), leaf);
+ if (existing != pool.end()) {
+ leaf.clip = existing->clip;
+ } else {
// We haven't found an existing clip ID
- pool.push_back(std::move(clip));
+ leaf.clip = {};
+ size++;
}
+
+ pool.emplace_back(std::move(leaf));
}
- if (!pool.empty()) {
- const uint32_t bit_count = util::ceil_log2(pool.size() + 1);
+ if (size > 0) {
+ const uint32_t bit_count = util::ceil_log2(size + 1);
const std::bitset<8> mask = uint64_t(((1ul << bit_count) - 1) << bit_offset);
// We are starting our count with 1 since we need at least 1 bit set to distinguish between
// areas without any tiles whatsoever and the current area.
uint8_t count = 1;
- for (auto& leaf : pool) {
- leaf.tile.clip.mask = mask;
- leaf.tile.clip.reference = uint32_t(count++) << bit_offset;
+ for (auto& tile : tiles) {
+ tile->clip.mask |= mask;
+
+ // Assign only to clip IDs that have no value yet.
+ if (tile->clip.reference.none()) {
+ tile->clip.reference = uint32_t(count++) << bit_offset;
+ }
}
bit_offset += bit_count;
- pools.push_front(std::move(pool));
}
if (bit_offset > 8) {
@@ -94,4 +97,58 @@ void ClipIDGenerator::update(std::forward_list<Tile *> tiles) {
}
}
+template <typename Container>
+bool coveredByChildren(const TileID& id, const Container& container) {
+ for (const auto& child : id.children()) {
+ const auto lower = container.lower_bound(child);
+ if (lower == container.end() ||
+ (lower->first != child && !coveredByChildren(child, container))) {
+ return false;
+ }
+ }
+
+ // We looked at all four immediate children and verified that they're covered.
+ return true;
+}
+
+std::map<TileID, ClipID> ClipIDGenerator::getStencils() const {
+ std::map<TileID, ClipID> stencils;
+
+ // Merge everything.
+ for (auto& leaf : pool) {
+ auto res = stencils.emplace(leaf.id, leaf.clip);
+ if (!res.second) {
+ // Merge with the existing ClipID when there was already an element with the
+ // same tile ID.
+ res.first->second |= leaf.clip;
+ }
+ }
+
+ for (auto it = stencils.begin(); it != stencils.end(); ++it) {
+ auto& childId = it->first;
+ auto& childClip = it->second;
+
+ // Loop through all preceding stencils, and find all parents.
+
+ for (auto parentIt = std::reverse_iterator<std::map<TileID, ClipID>::iterator>(it);
+ parentIt != stencils.rend(); ++parentIt) {
+ auto& parentId = parentIt->first;
+ if (childId.isChildOf(parentId)) {
+ // Once we have a parent, we add the bits that this ID hasn't set yet.
+ const auto& parentClip = parentIt->second;
+ const auto mask = ~(childClip.mask & parentClip.mask);
+ childClip.reference |= mask & parentClip.reference;
+ childClip.mask |= parentClip.mask;
+ }
+ }
+ }
+
+ // Remove tiles that are entirely covered by children.
+ util::erase_if(stencils, [&] (const auto& stencil) {
+ return coveredByChildren(stencil.first, stencils);
+ });
+
+ return stencils;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/util/clip_id.hpp b/src/mbgl/util/clip_id.hpp
index 71a07708c9..2c128d2643 100644
--- a/src/mbgl/util/clip_id.hpp
+++ b/src/mbgl/util/clip_id.hpp
@@ -14,7 +14,6 @@
namespace mbgl {
class Tile;
-class TileID;
struct ClipID {
inline ClipID() {}
@@ -26,28 +25,33 @@ struct ClipID {
inline bool operator==(const ClipID &other) const {
return mask == other.mask && reference == other.reference;
}
+
+ inline ClipID& operator|=(const ClipID &other) {
+ mask |= other.mask;
+ reference |= other.reference;
+ return *this;
+ }
};
class ClipIDGenerator {
private:
struct Leaf {
- Leaf(Tile &tile);
+ Leaf(TileID, ClipID&);
void add(const TileID &p);
bool operator==(const Leaf &other) const;
- Tile &tile;
+ const TileID id;
std::forward_list<TileID> children;
+ ClipID& clip;
};
- typedef std::vector<Leaf> Pool;
- std::forward_list<Pool> pools;
uint8_t bit_offset = 0;
-
-private:
- bool reuseExisting(Leaf &leaf);
+ std::vector<Leaf> pool;
public:
void update(std::forward_list<Tile *> tiles);
+
+ std::map<TileID, ClipID> getStencils() const;
};
diff --git a/src/mbgl/util/clip_lines.cpp b/src/mbgl/util/clip_lines.cpp
index 3a909d674a..071e9d09bd 100644
--- a/src/mbgl/util/clip_lines.cpp
+++ b/src/mbgl/util/clip_lines.cpp
@@ -21,33 +21,33 @@ std::vector<std::vector<Coordinate>> clipLines(const std::vector<std::vector<Coo
if (p0.x < x1 && p1.x < x1) {
continue;
} else if (p0.x < x1) {
- p0 = { x1, static_cast<int16_t>(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x))) };
+ p0 = { x1, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x)))) };
} else if (p1.x < x1) {
- p1 = { x1, static_cast<int16_t>(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x))) };
+ p1 = { x1, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x1 - p0.x) / (p1.x - p0.x)))) };
}
if (p0.y < y1 && p1.y < y1) {
continue;
} else if (p0.y < y1) {
- p0 = { static_cast<int16_t>(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y))), y1 };
+ p0 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y)))), y1 };
} else if (p1.y < y1) {
- p1 = { static_cast<int16_t>(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y))), y1 };
+ p1 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y1 - p0.y) / (p1.y - p0.y)))), y1 };
}
if (p0.x >= x2 && p1.x >= x2) {
continue;
} else if (p0.x >= x2) {
- p0 = { x2, static_cast<int16_t>(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x))) };
+ p0 = { x2, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x)))) };
} else if (p1.x >= x2) {
- p1 = { x2, static_cast<int16_t>(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x))) };
+ p1 = { x2, static_cast<int16_t>(::round(p0.y + (p1.y - p0.y) * ((float)(x2 - p0.x) / (p1.x - p0.x)))) };
}
if (p0.y >= y2 && p1.y >= y2) {
continue;
} else if (p0.y >= y2) {
- p0 = { static_cast<int16_t>(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y))), y2 };
+ p0 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y)))), y2 };
} else if (p1.y >= y2) {
- p1 = { static_cast<int16_t>(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y))), y2 };
+ p1 = { static_cast<int16_t>(::round(p0.x + (p1.x - p0.x) * ((float)(y2 - p0.y) / (p1.y - p0.y)))), y2 };
}
if (clippedLines.empty() || (!clippedLines.back().empty() && !(p0 == clippedLines.back().back()))) {
diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp
index 0452dd19e5..90a4d28c2f 100644
--- a/src/mbgl/util/constants.cpp
+++ b/src/mbgl/util/constants.cpp
@@ -1,6 +1,12 @@
#include <mbgl/util/constants.hpp>
-const float mbgl::util::tileSize = 512.0f;
+#include <limits>
+
+namespace mbgl {
+
+namespace util {
+
+const float tileSize = 512.0f;
/*
* The maximum extent of a feature that can be safely stored in the buffer.
@@ -12,37 +18,47 @@ const float mbgl::util::tileSize = 512.0f;
* One bit is lost to support features extending past the extent on the right edge of the tile.
* This leaves us with 2^13 = 8192
*/
-const int32_t mbgl::util::EXTENT = 8192;
+const int32_t EXTENT = 8192;
+
+const double DEG2RAD = M_PI / 180.0;
+const double RAD2DEG = 180.0 / M_PI;
+const double M2PI = 2 * M_PI;
+const double EARTH_RADIUS_M = 6378137;
+const double LATITUDE_MAX = 85.05112878;
+const double PITCH_MAX = M_PI / 3;
+const double MIN_ZOOM = 0.0;
+const double MAX_ZOOM = 25.5;
-const double mbgl::util::DEG2RAD = M_PI / 180.0;
-const double mbgl::util::RAD2DEG = 180.0 / M_PI;
-const double mbgl::util::M2PI = 2 * M_PI;
-const double mbgl::util::EARTH_RADIUS_M = 6378137;
-const double mbgl::util::LATITUDE_MAX = 85.05112878;
-const double mbgl::util::PITCH_MAX = M_PI / 3;
-const double mbgl::util::MIN_ZOOM = 0.0;
-const double mbgl::util::MAX_ZOOM = 25.5;
+const uint64_t DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
+
+} // namespace util
+
+namespace debug {
#if defined(DEBUG)
-const bool mbgl::debug::tileParseWarnings = false;
-const bool mbgl::debug::styleParseWarnings = false;
-const bool mbgl::debug::spriteWarnings = false;
-const bool mbgl::debug::renderWarnings = false;
-const bool mbgl::debug::renderTree = false;
-const bool mbgl::debug::labelTextMissingWarning = true;
-const bool mbgl::debug::missingFontStackWarning = true;
-const bool mbgl::debug::missingFontFaceWarning = true;
-const bool mbgl::debug::glyphWarning = true;
-const bool mbgl::debug::shapingWarning = true;
+const bool tileParseWarnings = false;
+const bool styleParseWarnings = false;
+const bool spriteWarnings = false;
+const bool renderWarnings = false;
+const bool renderTree = false;
+const bool labelTextMissingWarning = true;
+const bool missingFontStackWarning = true;
+const bool missingFontFaceWarning = true;
+const bool glyphWarning = true;
+const bool shapingWarning = true;
#else
-const bool mbgl::debug::tileParseWarnings = false;
-const bool mbgl::debug::styleParseWarnings = false;
-const bool mbgl::debug::spriteWarnings = false;
-const bool mbgl::debug::renderWarnings = false;
-const bool mbgl::debug::renderTree = false;
-const bool mbgl::debug::labelTextMissingWarning = false;
-const bool mbgl::debug::missingFontStackWarning = false;
-const bool mbgl::debug::missingFontFaceWarning = false;
-const bool mbgl::debug::glyphWarning = false;
-const bool mbgl::debug::shapingWarning = false;
+const bool tileParseWarnings = false;
+const bool styleParseWarnings = false;
+const bool spriteWarnings = false;
+const bool renderWarnings = false;
+const bool renderTree = false;
+const bool labelTextMissingWarning = false;
+const bool missingFontStackWarning = false;
+const bool missingFontFaceWarning = false;
+const bool glyphWarning = false;
+const bool shapingWarning = false;
#endif
+
+} // namespace debug
+
+} // namespace mbgl
diff --git a/src/mbgl/util/get_geometries.cpp b/src/mbgl/util/get_geometries.cpp
index 4d4d02c5ff..5961af2150 100644
--- a/src/mbgl/util/get_geometries.cpp
+++ b/src/mbgl/util/get_geometries.cpp
@@ -1,6 +1,8 @@
#include <mbgl/util/get_geometries.hpp>
#include <mbgl/util/constants.hpp>
+#include <cmath>
+
namespace mbgl {
GeometryCollection getGeometries(const GeometryTileFeature& feature) {
@@ -8,8 +10,8 @@ GeometryCollection getGeometries(const GeometryTileFeature& feature) {
GeometryCollection geometryCollection = feature.getGeometries();
for (auto& line : geometryCollection) {
for (auto& point : line) {
- point.x = std::round(point.x * scale);
- point.y = std::round(point.y * scale);
+ point.x = ::round(point.x * scale);
+ point.y = ::round(point.y * scale);
}
}
return geometryCollection;
diff --git a/src/mbgl/util/get_geometries.hpp b/src/mbgl/util/get_geometries.hpp
index 32dd389507..013a7e5b9f 100644
--- a/src/mbgl/util/get_geometries.hpp
+++ b/src/mbgl/util/get_geometries.hpp
@@ -1,7 +1,7 @@
#ifndef MBGL_UTIL_GET_GEOMETRIES
#define MBGL_UTIL_GET_GEOMETRIES
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
namespace mbgl {
diff --git a/src/mbgl/util/gl_object_store.cpp b/src/mbgl/util/gl_object_store.cpp
deleted file mode 100644
index 78d6700237..0000000000
--- a/src/mbgl/util/gl_object_store.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <mbgl/util/gl_object_store.hpp>
-
-#include <mbgl/util/thread.hpp>
-#include <mbgl/geometry/vao.hpp>
-#include <mbgl/platform/gl.hpp>
-
-#include <cassert>
-
-namespace mbgl {
-namespace util {
-
-void GLObjectStore::abandonVAO(GLuint vao) {
- assert(ThreadContext::currentlyOn(ThreadType::Map));
- abandonedVAOs.emplace_back(vao);
-}
-
-void GLObjectStore::abandonBuffer(GLuint buffer) {
- assert(ThreadContext::currentlyOn(ThreadType::Map));
- abandonedBuffers.emplace_back(buffer);
-}
-
-void GLObjectStore::abandonTexture(GLuint texture) {
- assert(ThreadContext::currentlyOn(ThreadType::Map));
- abandonedTextures.emplace_back(texture);
-}
-
-void GLObjectStore::performCleanup() {
- assert(ThreadContext::currentlyOn(ThreadType::Map));
-
- if (!abandonedVAOs.empty()) {
- MBGL_CHECK_ERROR(VertexArrayObject::Delete(static_cast<GLsizei>(abandonedVAOs.size()),
- abandonedVAOs.data()));
- abandonedVAOs.clear();
- }
-
- if (!abandonedTextures.empty()) {
- MBGL_CHECK_ERROR(glDeleteTextures(static_cast<GLsizei>(abandonedTextures.size()),
- abandonedTextures.data()));
- abandonedTextures.clear();
- }
-
- if (!abandonedBuffers.empty()) {
- MBGL_CHECK_ERROR(glDeleteBuffers(static_cast<GLsizei>(abandonedBuffers.size()),
- abandonedBuffers.data()));
- abandonedBuffers.clear();
- }
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/gl_object_store.hpp b/src/mbgl/util/gl_object_store.hpp
deleted file mode 100644
index 775d4d1d01..0000000000
--- a/src/mbgl/util/gl_object_store.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef MBGL_MAP_UTIL_GL_OBJECT_STORE
-#define MBGL_MAP_UTIL_GL_OBJECT_STORE
-
-#include <mbgl/platform/gl.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-#include <cstdint>
-#include <vector>
-
-namespace mbgl {
-namespace util {
-
-class GLObjectStore : private util::noncopyable {
-public:
- GLObjectStore() = default;
-
- // Mark OpenGL objects for deletion
- void abandonVAO(GLuint vao);
- void abandonBuffer(GLuint buffer);
- void abandonTexture(GLuint texture);
-
- // Actually remove the objects we marked as abandoned with the above methods.
- // Only call this while the OpenGL context is exclusive to this thread.
- void performCleanup();
-
-private:
- std::vector<GLuint> abandonedVAOs;
- std::vector<GLuint> abandonedBuffers;
- std::vector<GLuint> abandonedTextures;
-};
-
-} // namespace util
-} // namespace mbgl
-
-#endif
diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp
index d94a9a5f7d..7ee0f279b6 100644
--- a/src/mbgl/util/mapbox.cpp
+++ b/src/mbgl/util/mapbox.cpp
@@ -111,83 +111,62 @@ std::string normalizeGlyphsURL(const std::string& url, const std::string& access
return baseURL + "fonts/v1/" + user + "/" + fontstack + "/" + range + "?access_token=" + accessToken;
}
-std::string normalizeRasterTileURL(const std::string& url) {
- std::string::size_type queryIdx = url.rfind("?");
- // Trim off the right end but never touch anything before the extension dot.
- std::string urlSansParams((queryIdx == std::string::npos) ? url : url.substr(0, queryIdx));
-
- while (!urlSansParams.empty() && isdigit(urlSansParams.back())) {
- urlSansParams.pop_back();
- }
-
- std::string::size_type basenameIdx = url.rfind("/", queryIdx);
- std::string::size_type extensionIdx = url.rfind(".", queryIdx);
- if (basenameIdx == std::string::npos || extensionIdx == std::string::npos ||
- basenameIdx > extensionIdx) {
- // No file extension: probably not a file name we can tack a ratio onto.
+std::string normalizeTileURL(const std::string& url, const std::string& accessToken) {
+ if (!isMapboxURL(url)) {
return url;
}
- std::string normalizedURL(url);
-#if !defined(__ANDROID__) && !defined(__APPLE__)
- // Replace PNG with WebP.
- if (normalizedURL.compare(extensionIdx + 1, 3, "png") == 0) {
- normalizedURL.replace(extensionIdx + 1, 3, "webp");
- }
-#endif // !defined(__ANDROID__) && !defined(__APPLE__)
- normalizedURL.insert(extensionIdx, "{ratio}");
- return normalizedURL;
+ return baseURL + "v4/" + url.substr(sizeof("mapbox://tiles/") - 1) + "?access_token=" + accessToken;
}
-
-std::string removeAccessTokenFromURL(const std::string &url) {
- const size_t token_start = url.find("access_token=");
- // Ensure that token exists, isn't at the front and is preceded by either & or ?.
- if (token_start == std::string::npos || token_start == 0 || !(url[token_start - 1] == '&' || url[token_start - 1] == '?')) {
+std::string canonicalizeTileURL(const std::string& url, SourceType type, uint16_t tileSize) {
+ auto tilesetStartIdx = url.find("/v4/");
+ if (tilesetStartIdx == std::string::npos) {
return url;
}
- const size_t token_end = url.find_first_of('&', token_start);
- if (token_end == std::string::npos) {
- // The token is the last query argument. We slice away the "&access_token=..." part
- return url.substr(0, token_start - 1);
- } else {
- // We slice away the "access_token=...&" part.
- return url.substr(0, token_start) + url.substr(token_end + 1);
- }
-}
-
-namespace {
+ tilesetStartIdx += sizeof("/v4/") - 1;
-std::string convertMapboxDomainsToProtocol(const std::string &url) {
- const size_t protocol_separator = url.find("://");
- if (protocol_separator == std::string::npos) {
+ auto tilesetEndIdx = url.find("/", tilesetStartIdx);
+ if (tilesetEndIdx == std::string::npos) {
return url;
}
- const std::string protocol = url.substr(0, protocol_separator);
- if (!(protocol == "http" || protocol == "https")) {
- return url;
+ auto queryIdx = url.rfind("?");
+ if (queryIdx == std::string::npos) {
+ queryIdx = url.length();
}
- const size_t domain_begin = protocol_separator + 3;
- const size_t path_separator = url.find("/", domain_begin);
- if (path_separator == std::string::npos) {
- return url;
+ auto basenameIdx = url.rfind("/", queryIdx);
+ if (basenameIdx == std::string::npos || basenameIdx == queryIdx - 1) {
+ basenameIdx = url.length();
+ } else {
+ basenameIdx += 1;
}
- const std::string domain = url.substr(domain_begin, path_separator - domain_begin);
- if (domain == "api.mapbox.com" || domain.find(".tiles.mapbox.com") != std::string::npos) {
- return std::string{ "mapbox://" } + url.substr(path_separator + 1);
- } else {
+ auto extensionIdx = url.find(".", basenameIdx);
+ if (extensionIdx == std::string::npos || extensionIdx == queryIdx - 1) {
return url;
}
-}
-} // end namespace
+ auto tileset = url.substr(tilesetStartIdx, tilesetEndIdx - tilesetStartIdx);
+ auto extension = url.substr(extensionIdx + 1, queryIdx - extensionIdx - 1);
+
+#if !defined(__ANDROID__) && !defined(__APPLE__)
+ // Replace PNG with WebP.
+ if (extension == "png") {
+ extension = "webp";
+ }
+#endif // !defined(__ANDROID__) && !defined(__APPLE__)
+
+ std::string result = "mapbox://tiles/" + tileset + "/{z}/{x}/{y}";
+
+ if (type == SourceType::Raster) {
+ result += tileSize == 512 ? "@2x" : "{ratio}";
+ }
-std::string canonicalURL(const std::string &url) {
- return removeAccessTokenFromURL(convertMapboxDomainsToProtocol(url));
+ result += "." + extension;
+ return result;
}
} // end namespace mapbox
diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp
index 3c44d704c7..bb0536cfa2 100644
--- a/src/mbgl/util/mapbox.hpp
+++ b/src/mbgl/util/mapbox.hpp
@@ -14,13 +14,10 @@ std::string normalizeSourceURL(const std::string& url, const std::string& access
std::string normalizeStyleURL(const std::string& url, const std::string& accessToken);
std::string normalizeSpriteURL(const std::string& url, const std::string& accessToken);
std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken);
-std::string normalizeRasterTileURL(const std::string& url);
+std::string normalizeTileURL(const std::string& url, const std::string& accessToken);
-// Canonicalizes Mapbox URLs by removing [a-d] subdomain prefixes, access tokens, and protocol.
-// Note that this is close, but not exactly the reverse operation as above, as this retains certain
-// information, such as the API version. It is used to cache resources retrieved from the URL, that
-// sometimes have multiple valid URLs.
-std::string canonicalURL(const std::string &url);
+// Return a "mapbox://tiles/..." URL (suitable for normalizeTileURL) for the given Mapbox tile URL.
+std::string canonicalizeTileURL(const std::string& url, SourceType, uint16_t tileSize);
} // namespace mapbox
} // namespace util
diff --git a/src/mbgl/util/raster.cpp b/src/mbgl/util/raster.cpp
index 704d05e1eb..a74b73a016 100644
--- a/src/mbgl/util/raster.cpp
+++ b/src/mbgl/util/raster.cpp
@@ -1,5 +1,5 @@
#include <mbgl/platform/platform.hpp>
-#include <mbgl/platform/gl.hpp>
+#include <mbgl/gl/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/raster.hpp>
@@ -9,13 +9,14 @@
using namespace mbgl;
-Raster::Raster(TexturePool& texturePool_)
+Raster::Raster(gl::TexturePool& texturePool_)
: texturePool(texturePool_)
{}
Raster::~Raster() {
if (textured) {
- texturePool.removeTextureID(texture);
+ texturePool.releaseTextureID(textureID);
+ textureID = 0;
}
}
@@ -36,16 +37,16 @@ void Raster::load(PremultipliedImage image) {
}
-void Raster::bind(bool linear) {
+void Raster::bind(bool linear, gl::GLObjectStore& glObjectStore) {
if (!width || !height) {
Log::Error(Event::OpenGL, "trying to bind texture without dimension");
return;
}
if (img.data && !textured) {
- upload();
+ upload(glObjectStore);
} else if (textured) {
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, textureID));
}
GLint new_filter = linear ? GL_LINEAR : GL_NEAREST;
@@ -56,10 +57,10 @@ void Raster::bind(bool linear) {
}
}
-void Raster::upload() {
+void Raster::upload(gl::GLObjectStore& glObjectStore) {
if (img.data && !textured) {
- texture = texturePool.getTextureID();
- MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
+ textureID = texturePool.getTextureID(glObjectStore);
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, textureID));
#ifndef GL_ES_VERSION_2_0
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
#endif
diff --git a/src/mbgl/util/raster.hpp b/src/mbgl/util/raster.hpp
index 02d6615a9f..0a275a197c 100644
--- a/src/mbgl/util/raster.hpp
+++ b/src/mbgl/util/raster.hpp
@@ -1,8 +1,8 @@
#ifndef MBGL_UTIL_RASTER
#define MBGL_UTIL_RASTER
-#include <mbgl/platform/gl.hpp>
-#include <mbgl/util/texture_pool.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/texture_pool.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/chrono.hpp>
@@ -14,17 +14,17 @@ namespace mbgl {
class Raster : public std::enable_shared_from_this<Raster> {
public:
- Raster(TexturePool&);
+ Raster(gl::TexturePool&);
~Raster();
// load image data
void load(PremultipliedImage);
// bind current texture
- void bind(bool linear = false);
+ void bind(bool linear, gl::GLObjectStore&);
// uploads the texture if it hasn't been uploaded yet.
- void upload();
+ void upload(gl::GLObjectStore&);
// loaded status
bool isLoaded() const;
@@ -38,7 +38,7 @@ public:
bool textured = false;
// the uploaded texture
- GLuint texture = 0;
+ GLuint textureID = 0;
// texture opacity
double opacity = 0;
@@ -50,7 +50,7 @@ private:
bool loaded = false;
// shared texture pool
- TexturePool& texturePool;
+ gl::TexturePool& texturePool;
// min/mag filter
GLint filter = 0;
diff --git a/src/mbgl/util/texture_pool.cpp b/src/mbgl/util/texture_pool.cpp
deleted file mode 100644
index d4afb1f868..0000000000
--- a/src/mbgl/util/texture_pool.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <mbgl/util/texture_pool.hpp>
-
-#include <mbgl/util/gl_object_store.hpp>
-#include <mbgl/util/thread_context.hpp>
-
-#include <vector>
-
-const GLsizei TextureMax = 64;
-
-using namespace mbgl;
-
-GLuint TexturePool::getTextureID() {
- if (texture_ids.empty()) {
- GLuint new_texture_ids[TextureMax];
- MBGL_CHECK_ERROR(glGenTextures(TextureMax, new_texture_ids));
- for (GLuint id = 0; id < TextureMax; id++) {
- texture_ids.insert(new_texture_ids[id]);
- }
- }
-
- GLuint id = 0;
-
- if (!texture_ids.empty()) {
- std::set<GLuint>::iterator id_iterator = texture_ids.begin();
- id = *id_iterator;
- texture_ids.erase(id_iterator);
- }
-
- return id;
-}
-
-void TexturePool::removeTextureID(GLuint texture_id) {
- bool needs_clear = false;
-
- texture_ids.insert(texture_id);
-
- if (texture_ids.size() > TextureMax) {
- needs_clear = true;
- }
-
- if (needs_clear) {
- // TODO: We need to find a better way to deal with texture pool cleanup
-// clearTextureIDs();
- }
-}
-
-void TexturePool::clearTextureIDs() {
- auto getGLObjectStore = util::ThreadContext::getGLObjectStore();
- for (auto texture : texture_ids) {
- getGLObjectStore->abandonTexture(texture);
- }
- texture_ids.clear();
-}
diff --git a/src/mbgl/util/texture_pool.hpp b/src/mbgl/util/texture_pool.hpp
deleted file mode 100644
index a980584c13..0000000000
--- a/src/mbgl/util/texture_pool.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef MBGL_UTIL_TEXTUREPOOL
-#define MBGL_UTIL_TEXTUREPOOL
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/platform/gl.hpp>
-
-#include <set>
-#include <mutex>
-
-namespace mbgl {
-
-class TexturePool : private util::noncopyable {
-
-public:
- GLuint getTextureID();
- void removeTextureID(GLuint texture_id);
- void clearTextureIDs();
-
-private:
- std::set<GLuint> texture_ids;
-};
-
-} // namespace mbgl
-
-#endif
diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp
index b611b3d023..d6ddda2e8e 100644
--- a/src/mbgl/util/thread_context.cpp
+++ b/src/mbgl/util/thread_context.cpp
@@ -44,38 +44,6 @@ ThreadPriority ThreadContext::getPriority() {
}
}
-FileSource* ThreadContext::getFileSource() {
- if (current.get() != nullptr) {
- return current.get()->fileSource;
- } else {
- return nullptr;
- }
-}
-
-void ThreadContext::setFileSource(FileSource* fileSource) {
- if (current.get() != nullptr) {
- current.get()->fileSource = fileSource;
- } else {
- throw std::runtime_error("Current thread has no current ThreadContext.");
- }
-}
-
-GLObjectStore* ThreadContext::getGLObjectStore() {
- if (current.get() != nullptr) {
- return current.get()->glObjectStore;
- } else {
- return nullptr;
- }
-}
-
-void ThreadContext::setGLObjectStore(GLObjectStore* glObjectStore) {
- if (current.get() != nullptr) {
- current.get()->glObjectStore = glObjectStore;
- } else {
- throw std::runtime_error("Current thread has no current ThreadContext.");
- }
-}
-
class MainThreadContextRegistrar {
public:
MainThreadContextRegistrar() : context("Main", ThreadType::Main, ThreadPriority::Regular) {
diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp
index 2b22b2faf4..dea98fe3fa 100644
--- a/src/mbgl/util/thread_context.hpp
+++ b/src/mbgl/util/thread_context.hpp
@@ -6,13 +6,8 @@
#include <thread>
namespace mbgl {
-
-class FileSource;
-
namespace util {
-class GLObjectStore;
-
enum class ThreadPriority : bool {
Regular,
Low,
@@ -35,17 +30,9 @@ public:
static std::string getName();
static ThreadPriority getPriority();
- static FileSource* getFileSource();
- static void setFileSource(FileSource* fileSource);
- static GLObjectStore* getGLObjectStore();
- static void setGLObjectStore(GLObjectStore* glObjectStore);
-
std::string name;
ThreadType type;
ThreadPriority priority;
-
- FileSource* fileSource = nullptr;
- GLObjectStore* glObjectStore = nullptr;
};
} // namespace util
diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp
index 4710e08d0a..a989bef0c9 100644
--- a/src/mbgl/util/tile_coordinate.hpp
+++ b/src/mbgl/util/tile_coordinate.hpp
@@ -5,23 +5,11 @@
namespace mbgl {
-struct TileCoordinate {
+class TileCoordinate {
+public:
double column;
double row;
double zoom;
-
- TileCoordinate(double column_, double row_, double zoom_) :
- column(column_), row(row_), zoom(zoom_) {}
-
- TileCoordinate zoomTo(double targetZoom) {
- double scale = std::pow(2, targetZoom - zoom);
- return { column * scale, row * scale, targetZoom };
- }
-
- TileCoordinate operator-(TileCoordinate c) {
- c = c.zoomTo(zoom);
- return { column - c.column, row - c.row, zoom };
- };
};
} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 803aa53eee..e77ea469a7 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -1,7 +1,8 @@
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/util/vec.hpp>
-#include <mbgl/util/box.hpp>
#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/map/transform_state.hpp>
namespace mbgl {
@@ -66,7 +67,27 @@ static void scanTriangle(const mbgl::vec2<double> a, const mbgl::vec2<double> b,
if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);
}
-std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t actualZ) {
+int32_t coveringZoomLevel(double zoom, SourceType type, uint16_t tileSize) {
+ zoom += std::log(util::tileSize / tileSize) / std::log(2);
+ if (type == SourceType::Raster || type == SourceType::Video) {
+ return ::round(zoom);
+ } else {
+ return std::floor(zoom);
+ }
+}
+
+static mbgl::vec2<double> zoomTo(const TileCoordinate& c, double z) {
+ double scale = std::pow(2, z - c.zoom);
+ return { c.column * scale, c.row * scale };
+}
+
+std::vector<TileID> tileCover(const TileCoordinate& tl_,
+ const TileCoordinate& tr_,
+ const TileCoordinate& br_,
+ const TileCoordinate& bl_,
+ const TileCoordinate& center,
+ int32_t z,
+ int32_t actualZ) {
int32_t tiles = 1 << z;
std::forward_list<mbgl::TileID> t;
@@ -79,10 +100,11 @@ std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t ac
}
};
- mbgl::vec2<double> tl = { bounds.tl.column, bounds.tl.row };
- mbgl::vec2<double> tr = { bounds.tr.column, bounds.tr.row };
- mbgl::vec2<double> br = { bounds.br.column, bounds.br.row };
- mbgl::vec2<double> bl = { bounds.bl.column, bounds.bl.row };
+ mbgl::vec2<double> tl = zoomTo(tl_, z);
+ mbgl::vec2<double> tr = zoomTo(tr_, z);
+ mbgl::vec2<double> br = zoomTo(br_, z);
+ mbgl::vec2<double> bl = zoomTo(bl_, z);
+ mbgl::vec2<double> c = zoomTo(center, z);
// Divide the screen up in two triangles and scan each of them:
// \---+
@@ -94,7 +116,46 @@ std::forward_list<TileID> tileCover(int8_t z, const mbgl::box &bounds, int8_t ac
t.sort();
t.unique();
- return t;
+ t.sort([&](const TileID& a, const TileID& b) {
+ // Sorts by distance from the box center
+ return std::fabs(a.x - c.x) + std::fabs(a.y - c.y) <
+ std::fabs(b.x - c.x) + std::fabs(b.y - c.y);
+ });
+
+ return std::vector<TileID>(t.begin(), t.end());
+}
+
+std::vector<TileID> tileCover(const LatLngBounds& bounds_, int32_t z, int32_t actualZ) {
+ if (bounds_.isEmpty() ||
+ bounds_.south() > util::LATITUDE_MAX ||
+ bounds_.north() < -util::LATITUDE_MAX) {
+ return {};
+ }
+
+ LatLngBounds bounds = LatLngBounds::hull(
+ { std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
+ { std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
+
+ const TransformState state;
+ return tileCover(
+ state.latLngToCoordinate(bounds.northwest()),
+ state.latLngToCoordinate(bounds.northeast()),
+ state.latLngToCoordinate(bounds.southeast()),
+ state.latLngToCoordinate(bounds.southwest()),
+ state.latLngToCoordinate(bounds.center()),
+ z, actualZ);
+}
+
+std::vector<TileID> tileCover(const TransformState& state, int32_t z, int32_t actualZ) {
+ const double w = state.getWidth();
+ const double h = state.getHeight();
+ return tileCover(
+ state.pointToCoordinate({ 0, 0 }),
+ state.pointToCoordinate({ w, 0 }),
+ state.pointToCoordinate({ w, h }),
+ state.pointToCoordinate({ 0, h }),
+ state.pointToCoordinate({ w/2, h/2 }),
+ z, actualZ);
}
} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index 0514c36b62..a489964abf 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -2,13 +2,19 @@
#define MBGL_UTIL_TILE_COVER
#include <mbgl/map/tile_id.hpp>
-#include <mbgl/util/box.hpp>
+#include <mbgl/style/types.hpp>
-#include <forward_list>
+#include <vector>
namespace mbgl {
-std::forward_list<TileID> tileCover(int8_t z, const box& bounds, int8_t actualZ);
+class TransformState;
+class LatLngBounds;
+
+int32_t coveringZoomLevel(double z, SourceType type, uint16_t tileSize);
+
+std::vector<TileID> tileCover(const TransformState&, int32_t z, int32_t actualZ);
+std::vector<TileID> tileCover(const LatLngBounds&, int32_t z, int32_t actualZ);
} // namespace mbgl
diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp
index fe8ee81779..bc6e4be3db 100644
--- a/src/mbgl/util/worker.cpp
+++ b/src/mbgl/util/worker.cpp
@@ -3,7 +3,7 @@
#include <mbgl/util/work_request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/style/style_layer.hpp>
#include <cassert>
diff --git a/src/mbgl/util/worker.hpp b/src/mbgl/util/worker.hpp
index d72438bc75..96a7b27885 100644
--- a/src/mbgl/util/worker.hpp
+++ b/src/mbgl/util/worker.hpp
@@ -3,7 +3,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/thread.hpp>
-#include <mbgl/map/tile_worker.hpp>
+#include <mbgl/tile/tile_worker.hpp>
#include <functional>
#include <memory>
diff --git a/test/api/annotations.cpp b/test/api/annotations.cpp
index f427331eef..8e21b615a1 100644
--- a/test/api/annotations.cpp
+++ b/test/api/annotations.cpp
@@ -31,7 +31,7 @@ void checkRendering(Map& map, const char * name) {
TEST(Annotations, PointAnnotation) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -44,7 +44,7 @@ TEST(Annotations, PointAnnotation) {
TEST(Annotations, LineAnnotation) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -63,7 +63,7 @@ TEST(Annotations, LineAnnotation) {
TEST(Annotations, FillAnnotation) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -81,7 +81,7 @@ TEST(Annotations, FillAnnotation) {
TEST(Annotations, StyleSourcedShapeAnnotation) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/annotation.json"), "");
@@ -96,7 +96,7 @@ TEST(Annotations, StyleSourcedShapeAnnotation) {
TEST(Annotations, AddMultiple) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -113,7 +113,7 @@ TEST(Annotations, AddMultiple) {
TEST(Annotations, NonImmediateAdd) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -130,10 +130,10 @@ TEST(Annotations, NonImmediateAdd) {
checkRendering(map, "non_immediate_add");
}
-TEST(Annotations, UpdatePoint) {
+TEST(Annotations, UpdateIcon) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
@@ -146,18 +146,36 @@ TEST(Annotations, UpdatePoint) {
map.addAnnotationIcon("flipped_marker", namedMarker("flipped_marker.png"));
map.update(Update::Annotations);
+ checkRendering(map, "update_icon");
+}
+
+TEST(Annotations, UpdatePoint) {
+ auto display = std::make_shared<mbgl::HeadlessDisplay>();
+ HeadlessView view(display, 1);
+ OnlineFileSource fileSource;
+
+ Map map(view, fileSource, MapMode::Still);
+ map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
+ map.addAnnotationIcon("default_marker", namedMarker("default_marker.png"));
+ map.addAnnotationIcon("flipped_marker", namedMarker("flipped_marker.png"));
+ AnnotationID point = map.addPointAnnotation(PointAnnotation({ 0, 0 }, "default_marker"));
+
+ test::render(map);
+
+ map.updatePointAnnotation(point, PointAnnotation({ 0, -10 }, "flipped_marker"));
+
checkRendering(map, "update_point");
}
TEST(Annotations, RemovePoint) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
map.addAnnotationIcon("default_marker", namedMarker("default_marker.png"));
- uint32_t point = map.addPointAnnotation(PointAnnotation({ 0, 0 }, "default_marker"));
+ AnnotationID point = map.addPointAnnotation(PointAnnotation({ 0, 0 }, "default_marker"));
test::render(map);
@@ -169,7 +187,7 @@ TEST(Annotations, RemovePoint) {
TEST(Annotations, RemoveShape) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
AnnotationSegments segments = {{ {{ { 0, 0 }, { 45, 45 } }} }};
@@ -179,7 +197,7 @@ TEST(Annotations, RemoveShape) {
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
- uint32_t shape = map.addShapeAnnotation(ShapeAnnotation(segments, properties));
+ AnnotationID shape = map.addShapeAnnotation(ShapeAnnotation(segments, properties));
test::render(map);
@@ -191,7 +209,7 @@ TEST(Annotations, RemoveShape) {
TEST(Annotations, ImmediateRemoveShape) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.removeAnnotation(map.addShapeAnnotation(ShapeAnnotation({}, {})));
@@ -203,7 +221,7 @@ TEST(Annotations, ImmediateRemoveShape) {
TEST(Annotations, SwitchStyle) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
diff --git a/test/api/api_misuse.cpp b/test/api/api_misuse.cpp
index 3ac6939b49..b1bfa5a59a 100644
--- a/test/api/api_misuse.cpp
+++ b/test/api/api_misuse.cpp
@@ -18,7 +18,7 @@ TEST(API, RenderWithoutCallback) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
view.resize(128, 512);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
std::unique_ptr<Map> map = std::make_unique<Map>(view, fileSource, MapMode::Still);
map->renderStill(nullptr);
@@ -40,7 +40,7 @@ TEST(API, RenderWithoutStyle) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
view.resize(128, 512);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
diff --git a/test/api/custom_layer.cpp b/test/api/custom_layer.cpp
index 923bf4566e..ef98b05983 100644
--- a/test/api/custom_layer.cpp
+++ b/test/api/custom_layer.cpp
@@ -13,6 +13,10 @@ using namespace mbgl;
static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }";
static const GLchar * fragmentShaderSource = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
+// Not using any mbgl-specific stuff (other than a basic error-checking macro) in the
+// layer implementation because it is intended to reflect how someone using custom layers
+// might actually write their own implementation.
+
class TestLayer {
public:
~TestLayer() {
@@ -66,7 +70,7 @@ public:
TEST(CustomLayer, Basic) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), "");
diff --git a/test/api/offline.cpp b/test/api/offline.cpp
new file mode 100644
index 0000000000..f168ff71f5
--- /dev/null
+++ b/test/api/offline.cpp
@@ -0,0 +1,50 @@
+#include "../fixtures/util.hpp"
+
+#include <mbgl/platform/default/headless_display.hpp>
+#include <mbgl/platform/default/headless_view.hpp>
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <mbgl/platform/log.hpp>
+#include <mbgl/util/work_request.hpp>
+#include <mbgl/util/io.hpp>
+
+using namespace mbgl;
+using namespace std::literals::chrono_literals;
+using namespace std::literals::string_literals;
+
+namespace {
+
+Response expiredItem(const std::string& path) {
+ Response response;
+ response.data = std::make_shared<std::string>(util::read_file("test/fixtures/"s + path));
+ response.expires = SystemClock::from_time_t(0);
+ return response;
+}
+
+const std::string prefix = "http://127.0.0.1:3000";
+
+}
+
+auto display = std::make_shared<mbgl::HeadlessDisplay>();
+
+TEST(API, Offline) {
+ HeadlessView view(display, 1);
+ DefaultFileSource fileSource(":memory:", ".");
+
+ fileSource.put(Resource::style(prefix + "/offline/style.json"), expiredItem("offline/style.json"));
+ fileSource.put(Resource::source(prefix + "/offline/streets.json"), expiredItem("offline/streets.json"));
+ fileSource.put(Resource::spriteJSON(prefix + "/offline/sprite", 1.0), expiredItem("offline/sprite.json"));
+ fileSource.put(Resource::spriteImage(prefix + "/offline/sprite", 1.0), expiredItem("offline/sprite.png"));
+ fileSource.put(Resource::tile(prefix + "/offline/{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0), expiredItem("offline/0-0-0.vector.pbf"));
+ fileSource.put(Resource::glyphs(prefix + "/offline/{fontstack}/{range}.pbf", "Helvetica", {0, 255}), expiredItem("offline/glyph.pbf"));
+ fileSource.goOffline();
+
+ Map map(view, fileSource, MapMode::Still);
+ map.setStyleURL(prefix + "/offline/style.json");
+
+ test::checkImage("test/fixtures/offline"s,
+ test::render(map),
+ 0.0015,
+ 0.1);
+}
diff --git a/test/api/set_style.cpp b/test/api/set_style.cpp
index f5c1592516..befbf62210 100644
--- a/test/api/set_style.cpp
+++ b/test/api/set_style.cpp
@@ -12,7 +12,7 @@ TEST(API, SetStyle) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Log::setObserver(std::make_unique<FixtureLogObserver>());
diff --git a/test/fixtures/annotations/update_icon/expected.png b/test/fixtures/annotations/update_icon/expected.png
new file mode 100644
index 0000000000..3b6ca22747
--- /dev/null
+++ b/test/fixtures/annotations/update_icon/expected.png
Binary files differ
diff --git a/test/fixtures/annotations/update_point/expected.png b/test/fixtures/annotations/update_point/expected.png
index 3b6ca22747..02cf77df8d 100644
--- a/test/fixtures/annotations/update_point/expected.png
+++ b/test/fixtures/annotations/update_point/expected.png
Binary files differ
diff --git a/test/fixtures/stale/0-0-0.vector.pbf b/test/fixtures/offline/0-0-0.vector.pbf
index a0f049ad43..a0f049ad43 100644
--- a/test/fixtures/stale/0-0-0.vector.pbf
+++ b/test/fixtures/offline/0-0-0.vector.pbf
Binary files differ
diff --git a/test/fixtures/offline/empty.style.json b/test/fixtures/offline/empty.style.json
new file mode 100644
index 0000000000..61a8fadcdb
--- /dev/null
+++ b/test/fixtures/offline/empty.style.json
@@ -0,0 +1,5 @@
+{
+ "version": 8,
+ "sources": {},
+ "layers": []
+}
diff --git a/test/fixtures/offline/expected.png b/test/fixtures/offline/expected.png
new file mode 100644
index 0000000000..1b1c2be4c6
--- /dev/null
+++ b/test/fixtures/offline/expected.png
Binary files differ
diff --git a/test/fixtures/offline/geojson.json b/test/fixtures/offline/geojson.json
new file mode 100644
index 0000000000..8b3698faf7
--- /dev/null
+++ b/test/fixtures/offline/geojson.json
@@ -0,0 +1,4 @@
+{
+ "type": "FeatureCollection",
+ "features": []
+}
diff --git a/test/fixtures/offline/geojson_source.style.json b/test/fixtures/offline/geojson_source.style.json
new file mode 100644
index 0000000000..511fca9fd0
--- /dev/null
+++ b/test/fixtures/offline/geojson_source.style.json
@@ -0,0 +1,10 @@
+{
+ "version": 8,
+ "sources": {
+ "geojson": {
+ "type": "geojson",
+ "data": "http://127.0.0.1:3000/offline/geojson.json"
+ }
+ },
+ "layers": []
+}
diff --git a/test/fixtures/stale/glyph.pbf b/test/fixtures/offline/glyph.pbf
index 0d160f7898..0d160f7898 100644
--- a/test/fixtures/stale/glyph.pbf
+++ b/test/fixtures/offline/glyph.pbf
Binary files differ
diff --git a/test/fixtures/offline/inline_source.style.json b/test/fixtures/offline/inline_source.style.json
new file mode 100644
index 0000000000..87155d07d8
--- /dev/null
+++ b/test/fixtures/offline/inline_source.style.json
@@ -0,0 +1,17 @@
+{
+ "version": 8,
+ "sources": {
+ "inline": {
+ "type": "vector",
+ "maxzoom": 15,
+ "minzoom": 0,
+ "tiles": [ "http://127.0.0.1:3000/offline/{z}-{x}-{y}.vector.pbf" ]
+ }
+ },
+ "layers": [{
+ "id": "fill",
+ "type": "fill",
+ "source": "inline",
+ "source-layer": "water"
+ }]
+}
diff --git a/test/fixtures/stale/sprite.json b/test/fixtures/offline/sprite.json
index e640365519..e640365519 100644
--- a/test/fixtures/stale/sprite.json
+++ b/test/fixtures/offline/sprite.json
diff --git a/test/fixtures/stale/sprite.png b/test/fixtures/offline/sprite.png
index a02d8eb542..a02d8eb542 100644
--- a/test/fixtures/stale/sprite.png
+++ b/test/fixtures/offline/sprite.png
Binary files differ
diff --git a/test/fixtures/stale/streets.json b/test/fixtures/offline/streets.json
index 11cb5c8557..805bd68f45 100644
--- a/test/fixtures/stale/streets.json
+++ b/test/fixtures/offline/streets.json
@@ -10,5 +10,5 @@
"name": "Streets",
"scheme": "xyz",
"tilejson": "2.0.0",
- "tiles": [ "asset://test/fixtures/stale/{z}-{x}-{y}.vector.pbf" ]
+ "tiles": [ "http://127.0.0.1:3000/offline/{z}-{x}-{y}.vector.pbf" ]
}
diff --git a/test/fixtures/stale/style_and_glyphs.json b/test/fixtures/offline/style.json
index adf91705fb..c34ee59893 100644
--- a/test/fixtures/stale/style_and_glyphs.json
+++ b/test/fixtures/offline/style.json
@@ -4,10 +4,11 @@
"sources": {
"mapbox": {
"type": "vector",
- "url": "asset://test/fixtures/stale/streets.json"
+ "url": "http://127.0.0.1:3000/offline/streets.json"
}
},
- "glyphs": "http://127.0.0.1:3000/stale/{fontstack}/{range}.pbf",
+ "glyphs": "http://127.0.0.1:3000/offline/{fontstack}/{range}.pbf",
+ "sprite": "http://127.0.0.1:3000/offline/sprite",
"layers": [{
"id": "background",
"type": "background",
@@ -20,7 +21,7 @@
"source": "mapbox",
"source-layer": "water",
"paint": {
- "fill-color": "blue"
+ "fill-pattern": "noise"
}
}, {
"id": "admin",
@@ -28,7 +29,8 @@
"source": "mapbox",
"source-layer": "admin",
"layout": {
- "text-field": "Text"
+ "text-font": ["Helvetica"],
+ "text-field": "Text"
},
"paint": {
"text-color": "black",
diff --git a/test/fixtures/stale/stale_style/expected.png b/test/fixtures/stale/stale_style/expected.png
deleted file mode 100644
index d3c6ef3cd5..0000000000
--- a/test/fixtures/stale/stale_style/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/stale/stale_style_and_glyphs/expected.png b/test/fixtures/stale/stale_style_and_glyphs/expected.png
deleted file mode 100644
index d8dbda1092..0000000000
--- a/test/fixtures/stale/stale_style_and_glyphs/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/stale/stale_style_and_sprite/expected.png b/test/fixtures/stale/stale_style_and_sprite/expected.png
deleted file mode 100644
index 171599bf5c..0000000000
--- a/test/fixtures/stale/stale_style_and_sprite/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/stale/stale_style_and_tilejson/expected.png b/test/fixtures/stale/stale_style_and_tilejson/expected.png
deleted file mode 100644
index d3c6ef3cd5..0000000000
--- a/test/fixtures/stale/stale_style_and_tilejson/expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/stale/style.json b/test/fixtures/stale/style.json
deleted file mode 100644
index ca86503d4f..0000000000
--- a/test/fixtures/stale/style.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "version": 8,
- "name": "Water",
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "asset://test/fixtures/stale/streets.json"
- }
- },
- "layers": [{
- "id": "background",
- "type": "background",
- "paint": {
- "background-color": "red"
- }
- }, {
- "id": "water",
- "type": "fill",
- "source": "mapbox",
- "source-layer": "water",
- "paint": {
- "fill-color": "blue"
- }
- }]
-}
diff --git a/test/fixtures/stale/style_and_sprite.json b/test/fixtures/stale/style_and_sprite.json
deleted file mode 100644
index 61e3214a5e..0000000000
--- a/test/fixtures/stale/style_and_sprite.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "version": 8,
- "name": "Water",
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "asset://test/fixtures/stale/streets.json"
- }
- },
- "sprite": "http://127.0.0.1:3000/stale/sprite",
- "layers": [{
- "id": "background",
- "type": "background",
- "paint": {
- "background-color": "red"
- }
- }, {
- "id": "water",
- "type": "fill",
- "source": "mapbox",
- "source-layer": "water",
- "paint": {
- "fill-pattern": "noise"
- }
- }]
-}
diff --git a/test/fixtures/stale/style_and_tilejson.json b/test/fixtures/stale/style_and_tilejson.json
deleted file mode 100644
index f2a4fddd0b..0000000000
--- a/test/fixtures/stale/style_and_tilejson.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "version": 8,
- "name": "Water",
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "http://127.0.0.1:3000/stale/streets.json"
- }
- },
- "layers": [{
- "id": "background",
- "type": "background",
- "paint": {
- "background-color": "red"
- }
- }, {
- "id": "water",
- "type": "fill",
- "source": "mapbox",
- "source-layer": "water",
- "paint": {
- "fill-color": "blue"
- }
- }]
-}
diff --git a/test/fixtures/stub_file_source.cpp b/test/fixtures/stub_file_source.cpp
index 9eb37b7928..b41eded084 100644
--- a/test/fixtures/stub_file_source.cpp
+++ b/test/fixtures/stub_file_source.cpp
@@ -19,11 +19,12 @@ public:
StubFileSource::StubFileSource() {
timer.start(10ms, 10ms, [this] {
- // Explicit move to avoid iterator invalidation if ~StubFileRequest gets called within the loop.
- auto pending_ = std::move(pending);
+ // Explicit copy to avoid iterator invalidation if ~StubFileRequest gets called within the loop.
+ auto pending_ = pending;
for (auto& pair : pending_) {
- if (pair.second.first) {
- pair.second.second(*pair.second.first);
+ optional<Response> res = std::get<1>(pair.second)(std::get<0>(pair.second));
+ if (res) {
+ std::get<2>(pair.second)(*res);
}
}
});
@@ -33,7 +34,7 @@ StubFileSource::~StubFileSource() = default;
std::unique_ptr<FileRequest> StubFileSource::request(const Resource& resource, Callback callback) {
auto req = std::make_unique<StubFileRequest>(*this);
- pending.emplace(req.get(), std::make_pair(response(resource), callback));
+ pending.emplace(req.get(), std::make_tuple(resource, response, callback));
return std::move(req);
}
diff --git a/test/fixtures/stub_file_source.hpp b/test/fixtures/stub_file_source.hpp
index 344dff6073..dbb584fdcc 100644
--- a/test/fixtures/stub_file_source.hpp
+++ b/test/fixtures/stub_file_source.hpp
@@ -15,18 +15,20 @@ public:
std::unique_ptr<FileRequest> request(const Resource&, Callback) override;
+ using ResponseFunction = std::function<optional<Response> (const Resource&)>;
+
// You can set the response callback on a global level by assigning this callback:
- std::function<optional<Response> (const Resource&)> response = [this] (const Resource& resource) {
+ ResponseFunction response = [this] (const Resource& resource) {
return defaultResponse(resource);
};
// Or set per-kind responses by setting these callbacks:
- std::function<optional<Response> (const Resource&)> styleResponse;
- std::function<optional<Response> (const Resource&)> sourceResponse;
- std::function<optional<Response> (const Resource&)> tileResponse;
- std::function<optional<Response> (const Resource&)> glyphsResponse;
- std::function<optional<Response> (const Resource&)> spriteJSONResponse;
- std::function<optional<Response> (const Resource&)> spriteImageResponse;
+ ResponseFunction styleResponse;
+ ResponseFunction sourceResponse;
+ ResponseFunction tileResponse;
+ ResponseFunction glyphsResponse;
+ ResponseFunction spriteJSONResponse;
+ ResponseFunction spriteImageResponse;
private:
friend class StubFileRequest;
@@ -34,7 +36,7 @@ private:
// The default behavior is to throw if no per-kind callback has been set.
optional<Response> defaultResponse(const Resource&);
- std::unordered_map<FileRequest*, std::pair<optional<Response>, Callback>> pending;
+ std::unordered_map<FileRequest*, std::tuple<Resource, ResponseFunction, Callback>> pending;
util::Timer timer;
};
diff --git a/test/fixtures/style_parser/font_stacks.json b/test/fixtures/style_parser/font_stacks.json
new file mode 100644
index 0000000000..07fe223d46
--- /dev/null
+++ b/test/fixtures/style_parser/font_stacks.json
@@ -0,0 +1,38 @@
+{
+ "version": 8,
+ "sources": {
+ "source": {
+ "type": "vector",
+ "tiles": []
+ }
+ },
+ "layers": [{
+ "id": "a",
+ "type": "symbol",
+ "source": "source",
+ "source-layer": "source-layer",
+ "layout": {
+ "text-font": ["a"]
+ }
+ }, {
+ "id": "a,b",
+ "type": "symbol",
+ "source": "source",
+ "source-layer": "source-layer",
+ "layout": {
+ "text-font": {
+ "stops": [[0, ["a", "b"]]]
+ }
+ }
+ }, {
+ "id": "a,b;a,b,c",
+ "type": "symbol",
+ "source": "source",
+ "source-layer": "source-layer",
+ "layout": {
+ "text-font": {
+ "stops": [[0, ["a", "b"]], [1, ["a", "b", "c"]]]
+ }
+ }
+ }]
+}
diff --git a/test/fixtures/style_parser/tilejson.raster.json b/test/fixtures/style_parser/tilejson.raster.json
index 2eb0971a03..3fc819f292 100644
--- a/test/fixtures/style_parser/tilejson.raster.json
+++ b/test/fixtures/style_parser/tilejson.raster.json
@@ -4,5 +4,5 @@
"center": [ 1, 2, 3 ],
"bounds": [ 4, 5, 6, 7 ],
"attribution": "attribution",
- "tiles": [ "http://a.tiles.mapbox.com/mapbox.satellite/{z}-{x}-{y}.png?access_token=key" ]
+ "tiles": [ "http://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.png?access_token=key" ]
}
diff --git a/test/fixtures/style_parser/tilejson.vector.json b/test/fixtures/style_parser/tilejson.vector.json
index ea7d4bc352..9144bd502c 100644
--- a/test/fixtures/style_parser/tilejson.vector.json
+++ b/test/fixtures/style_parser/tilejson.vector.json
@@ -4,5 +4,5 @@
"center": [ 1, 2, 3 ],
"bounds": [ 4, 5, 6, 7 ],
"attribution": "attribution",
- "tiles": [ "http://a.tiles.mapbox.com/mapbox.streets/{z}-{x}-{y}.vector.pbf?access_token=key" ]
+ "tiles": [ "http://a.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.vector.pbf?access_token=key" ]
}
diff --git a/test/fixtures/util.cpp b/test/fixtures/util.cpp
index fcb6abed4e..5617b15e8b 100644
--- a/test/fixtures/util.cpp
+++ b/test/fixtures/util.cpp
@@ -106,20 +106,12 @@ uint64_t crc64(const PremultipliedImage &image) {
return crc64(reinterpret_cast<const char*>(image.data.get()), image.size());
}
-PremultipliedImage render(Map& map, Milliseconds timeout) {
+PremultipliedImage render(Map& map) {
std::promise<PremultipliedImage> promise;
map.renderStill([&](std::exception_ptr, PremultipliedImage&& image) {
promise.set_value(std::move(image));
});
-
- // Limit maximum wait time.
- auto future = promise.get_future();
- if (future.wait_for(timeout) != std::future_status::ready) {
- // Alas, we didn't get the promised future :(
- Log::Error(Event::Image, "Failed to generate image within %dms", timeout.count());
- return { 0, 0 };
- }
- return future.get();
+ return promise.get_future().get();
}
void checkImage(const std::string& base,
diff --git a/test/fixtures/util.hpp b/test/fixtures/util.hpp
index b93d822a83..2e27e5bf0f 100644
--- a/test/fixtures/util.hpp
+++ b/test/fixtures/util.hpp
@@ -4,7 +4,6 @@
#include <mbgl/util/image.hpp>
#include <mbgl/util/chrono.hpp>
-#include <chrono>
#include <cstdint>
#include <gtest/gtest.h>
@@ -36,12 +35,13 @@ uint64_t crc64(const char*, size_t);
uint64_t crc64(const std::string&);
uint64_t crc64(const PremultipliedImage&);
-PremultipliedImage render(Map&, Milliseconds timeout = Milliseconds(1000));
+PremultipliedImage render(Map&);
void checkImage(const std::string& base,
const PremultipliedImage& actual,
double imageThreshold = 0,
double pixelThreshold = 0);
+
}
}
diff --git a/test/ios/KIF b/test/ios/KIF
deleted file mode 160000
-Subproject 21a137bc8068f9fb738f835c6e285d44fe2ce4d
diff --git a/test/map/map.cpp b/test/map/map.cpp
index ed63bb085c..37caa95e97 100644
--- a/test/map/map.cpp
+++ b/test/map/map.cpp
@@ -12,7 +12,7 @@ TEST(Map, PauseResume) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Continuous);
@@ -25,7 +25,7 @@ TEST(Map, DoublePause) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Continuous);
@@ -39,7 +39,7 @@ TEST(Map, ResumeWithoutPause) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Continuous);
@@ -51,7 +51,7 @@ TEST(Map, DestroyPaused) {
auto display = std::make_shared<mbgl::HeadlessDisplay>();
HeadlessView view(display, 1);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
Map map(view, fileSource, MapMode::Continuous);
diff --git a/test/map/map_context.cpp b/test/map/map_context.cpp
index 60cb3d6b7f..2f3576a3b5 100644
--- a/test/map/map_context.cpp
+++ b/test/map/map_context.cpp
@@ -12,7 +12,7 @@ using namespace mbgl;
TEST(MapContext, DoubleStyleLoad) {
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
HeadlessView view(display, 1, 512, 512);
- OnlineFileSource fileSource(nullptr);
+ OnlineFileSource fileSource;
util::Thread<MapContext> context({"Map", util::ThreadType::Map, util::ThreadPriority::Regular},
view, fileSource, MapMode::Continuous, GLContextMode::Unique, view.getPixelRatio());
diff --git a/test/sprite/sprite_store.cpp b/test/sprite/sprite_store.cpp
index ee6ea2e9e0..ec7b91b875 100644
--- a/test/sprite/sprite_store.cpp
+++ b/test/sprite/sprite_store.cpp
@@ -156,7 +156,6 @@ public:
SpriteStoreTest()
: spriteStore(1.0) {}
- util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
util::RunLoop loop;
StubFileSource fileSource;
StubStyleObserver observer;
@@ -166,11 +165,8 @@ public:
// Squelch logging.
Log::setObserver(std::make_unique<Log::NullObserver>());
- util::ThreadContext::Set(&context);
- util::ThreadContext::setFileSource(&fileSource);
-
spriteStore.setObserver(&observer);
- spriteStore.setURL("test/fixtures/resources/sprite");
+ spriteStore.load("test/fixtures/resources/sprite", fileSource);
loop.run();
}
diff --git a/test/storage/asset_file_source.cpp b/test/storage/asset_file_source.cpp
index 22ee3f793a..a9261ee8a2 100644
--- a/test/storage/asset_file_source.cpp
+++ b/test/storage/asset_file_source.cpp
@@ -1,7 +1,6 @@
#include "storage.hpp"
#include <mbgl/storage/asset_file_source.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
@@ -173,3 +172,24 @@ TEST_F(Storage, AssetReadDirectory) {
loop.run();
}
+
+TEST_F(Storage, AssetURLEncoding) {
+ SCOPED_TEST(NonEmptyFile)
+
+ using namespace mbgl;
+
+ util::RunLoop loop;
+
+ AssetFileSource fs(getFileSourceRoot());
+
+ std::unique_ptr<FileRequest> req = fs.request({ Resource::Unknown, "asset://%6eonempty" }, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("content is here\n", *res.data);
+ loop.stop();
+ NonEmptyFile.finish();
+ });
+
+ loop.run();
+}
diff --git a/test/storage/cache_response.cpp b/test/storage/cache_response.cpp
deleted file mode 100644
index aa5e5dbfcf..0000000000
--- a/test/storage/cache_response.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-TEST_F(Storage, CacheResponse) {
- SCOPED_TEST(CacheResponse);
-
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/cache" };
- Response response;
-
- std::unique_ptr<FileRequest> req1;
- std::unique_ptr<FileRequest> req2;
-
- req1 = fs.request(resource, [&](Response res) {
- req1.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Response 1", *res.data);
- EXPECT_TRUE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- response = res;
-
- // Now test that we get the same values as in the previous request. If we'd go to the server
- // again, we'd get different values.
- req2 = fs.request(resource, [&](Response res2) {
- req2.reset();
- EXPECT_EQ(response.error, res2.error);
- ASSERT_TRUE(res2.data.get());
- EXPECT_EQ(*response.data, *res2.data);
- EXPECT_EQ(response.expires, res2.expires);
- EXPECT_EQ(response.modified, res2.modified);
- EXPECT_EQ(response.etag, res2.etag);
-
- loop.stop();
- CacheResponse.finish();
- });
- });
-
- loop.run();
-}
-
-// Make sure we /do/ store 404 Not Found responses into the cache
-TEST_F(Storage, CacheNotFound) {
- SCOPED_TEST(CacheNotFound);
-
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
-
- const Resource resource{ Resource::Unknown, "http://127.0.0.1:3000/not-found" };
-
- // Insert existing data into the cache that will be marked as stale.
- Response response;
- response.data = std::make_shared<const std::string>("existing data");
- cache.put(resource, response);
-
- std::unique_ptr<FileRequest> req1;
- std::unique_ptr<WorkRequest> req2;
-
- int counter = 0;
-
- // Then, request the actual URL and check that we're getting the rigged cache response first,
- // then the connection error message.
- req1 = fs.request(resource, [&](Response res) {
- if (counter == 0) {
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("existing data", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- } else if (counter == 1) {
- EXPECT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Not Found!", *res.data);
- req1.reset();
-
- // Finally, check the cache to make sure we cached the 404 response.
- req2 = cache.get(resource, [&](std::unique_ptr<Response> res2) {
- EXPECT_NE(nullptr, res2->error);
- EXPECT_EQ(Response::Error::Reason::NotFound, res2->error->reason);
- ASSERT_TRUE(res2->data.get());
- EXPECT_EQ("Not Found!", *res2->data);
- CacheNotFound.finish();
- loop.stop();
- });
- } else {
- FAIL() << "Got too many responses";
- }
- counter++;
- });
-
- loop.run();
-}
-
-// Make sure we don't store a connection error into the cache
-TEST_F(Storage, DontCacheConnectionErrors) {
- SCOPED_TEST(DontCacheConnectionErrors);
-
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
-
- const Resource resource{ Resource::Unknown, "http://127.0.0.1:3001" };
-
- // Insert existing data into the cache that will be marked as stale.
- Response response;
- response.data = std::make_shared<const std::string>("existing data");
- cache.put(resource, response);
-
- std::unique_ptr<FileRequest> req1;
- std::unique_ptr<WorkRequest> req2;
-
- int counter = 0;
-
- // Then, request the actual URL and check that we're getting the rigged cache response first,
- // then the connection error message.
- req1 = fs.request(resource, [&](Response res) {
- if (counter == 0) {
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("existing data", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- } else if (counter == 1) {
- EXPECT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
- req1.reset();
-
- // Finally, check the cache to make sure we still have our original data in there rather
- // than the failed connection attempt.
- req2 = cache.get(resource, [&](std::unique_ptr<Response> res2) {
- EXPECT_EQ(nullptr, res2->error);
- ASSERT_TRUE(res2->data.get());
- EXPECT_EQ("existing data", *res2->data);
- DontCacheConnectionErrors.finish();
- loop.stop();
- });
- } else {
- FAIL() << "Got too many responses";
- }
- counter++;
- });
-
- loop.run();
-}
-
-// Make sure we don't store a bad server response into the cache
-TEST_F(Storage, DontCacheServerErrors) {
- SCOPED_TEST(DontCacheServerErrors);
-
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
-
- const Resource resource{ Resource::Unknown, "http://127.0.0.1:3000/permanent-error" };
-
- // Insert existing data into the cache that will be marked as stale.
- Response response;
- response.data = std::make_shared<const std::string>("existing data");
- cache.put(resource, response);
-
- std::unique_ptr<FileRequest> req1;
- std::unique_ptr<WorkRequest> req2;
-
- int counter = 0;
-
- // Then, request the actual URL and check that we're getting the rigged cache response first,
- // then the server error message.
- req1 = fs.request(resource, [&](Response res) {
- if (counter == 0) {
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("existing data", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- } else if (counter == 1) {
- EXPECT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Server Error!", *res.data);
- req1.reset();
-
- // Finally, check the cache to make sure we still have our original data in there rather
- // than the failed connection attempt.
- req2 = cache.get(resource, [&](std::unique_ptr<Response> res2) {
- EXPECT_EQ(nullptr, res2->error);
- ASSERT_TRUE(res2->data.get());
- EXPECT_EQ("existing data", *res2->data);
- DontCacheServerErrors.finish();
- loop.stop();
- });
- } else {
- FAIL() << "Got too many responses";
- }
- counter++;
- });
-
- loop.run();
-}
diff --git a/test/storage/cache_shared.cpp b/test/storage/cache_shared.cpp
deleted file mode 100644
index 89ef3bfb84..0000000000
--- a/test/storage/cache_shared.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-TEST_F(Storage, CacheShared) {
- SCOPED_TEST(CacheShared)
- using namespace mbgl;
-
- util::RunLoop loop;
-
- // Check that we're getting two different caches when we request different paths.
- auto memory = SQLiteCache::getShared();
- auto file = SQLiteCache::getShared("test/fixtures/database/cache.db");
- EXPECT_NE(memory.get(), file.get());
- EXPECT_EQ(memory.get(), SQLiteCache::getShared().get());
-
- // Store a response into the memory file cache, then delete the last reference.
- const Resource resource { Resource::Kind::Unknown, "http://example.com" };
- memory->put(resource, Response());
- memory.reset();
-
- // Now check that the original memory file cache has been destructed and that it doesn't contain
- // the information we put into it.
- memory = SQLiteCache::getShared();
- auto req = memory->get(resource, [&](std::unique_ptr<Response> res) {
- EXPECT_FALSE(res.get());
- CacheShared.finish();
- loop.stop();
- });
-
- loop.run();
-}
diff --git a/test/storage/cache_size.cpp b/test/storage/cache_size.cpp
deleted file mode 100644
index b0d59d5934..0000000000
--- a/test/storage/cache_size.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/timer.hpp>
-#include <mbgl/util/chrono.hpp>
-
-#include <memory>
-#include <random>
-
-bool tileIsCached(mbgl::SQLiteCache* cache, unsigned id) {
- using namespace mbgl;
-
- auto url = std::string("http://tile") + mbgl::util::toString(id);
- bool replied = false;
-
- std::unique_ptr<Response> response;
- auto callback = [&] (std::unique_ptr<Response> res) {
- replied = true;
- response = std::move(res);
- };
-
- Resource resource{ Resource::Kind::Tile, url };
- auto req = cache->get(resource, callback);
-
- while (!replied) {
- util::RunLoop::Get()->runOnce();
- }
-
- return response != nullptr;
-}
-
-void insertTile(mbgl::SQLiteCache* cache, unsigned id, uint64_t size) {
- using namespace mbgl;
-
- auto url = std::string("http://tile") + mbgl::util::toString(id);
-
- Response response;
- response.modified = SystemClock::now();
- response.expires = SystemClock::now() + Seconds(5000);
- response.etag = url;
-
- auto data = std::make_shared<std::string>(size, 0);
-
- // Fill data with garbage so SQLite won't try to
- // optimize allocation by reusing pages.
- static std::mt19937 generator;
- std::generate_n(data->begin(), size, generator);
-
- response.data = data;
-
- Resource resource{ Resource::Kind::Tile, url };
- cache->put(resource, response);
-}
-
-void refreshTile(mbgl::SQLiteCache* cache, unsigned id) {
- using namespace mbgl;
-
- auto url = std::string("http://tile") + mbgl::util::toString(id);
-
- Response response;
- response.modified = SystemClock::now();
- response.expires = SystemClock::now() + Seconds(5000);
- response.notModified = true;
-
- Resource resource{ Resource::Kind::Tile, url };
- cache->put(resource, response);
-}
-
-uint64_t cacheSize(mbgl::SQLiteCache* cache, unsigned entryCount, uint64_t entrySize) {
- uint64_t total = 0;
-
- for (unsigned i = 0; i < entryCount; ++i) {
- if (tileIsCached(cache, i)) {
- total += entrySize;
- }
- }
-
- return total;
-}
-
-TEST_F(Storage, CacheEntrySizeLimit) {
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
-
- const uint64_t entrySize = 5 * 1024 * 1024; // 5 MB
-
- insertTile(&cache, 0, entrySize);
- EXPECT_TRUE(tileIsCached(&cache, 0));
-
- insertTile(&cache, 1, entrySize + 1);
- EXPECT_FALSE(tileIsCached(&cache, 1));
-
- insertTile(&cache, 2, entrySize - 1);
- EXPECT_TRUE(tileIsCached(&cache, 2));
-
- // Setting a new size should not delete existing entries.
- cache.setMaximumCacheEntrySize(entrySize / 2);
- EXPECT_TRUE(tileIsCached(&cache, 2));
-
- insertTile(&cache, 3, entrySize / 2 - 1);
- EXPECT_TRUE(tileIsCached(&cache, 3));
-
- insertTile(&cache, 4, entrySize);
- EXPECT_FALSE(tileIsCached(&cache, 4));
-
- cache.setMaximumCacheEntrySize(entrySize * 2);
- insertTile(&cache, 5, entrySize);
- EXPECT_TRUE(tileIsCached(&cache, 5));
-}
-
-TEST_F(Storage, CacheSizeSetNewLimit) {
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
-
- const unsigned entryCount = 800;
- const uint64_t entrySize = 10 * 1024; // 10 KB
-
- cache.setMaximumCacheEntrySize(entrySize + 1);
-
- // Cache size defaults to unlimited, all these
- // inserts should work.
- for (unsigned i = 0; i < entryCount; ++i) {
- insertTile(&cache, i, entrySize);
- }
-
- for (unsigned i = 0; i < entryCount; ++i) {
- EXPECT_TRUE(tileIsCached(&cache, i));
- }
-
- uint64_t expectedCacheSize = entryCount * entrySize;
- EXPECT_EQ(cacheSize(&cache, entryCount, entrySize), expectedCacheSize);
-
- // Setting a new size should remove records until the new
- // size limit is satisfied.
- cache.setMaximumCacheSize(expectedCacheSize / 2);
- EXPECT_LT(cacheSize(&cache, entryCount, entrySize), expectedCacheSize / 2);
-
- // Cache size 1 should practically clean the cache and
- // prevent adding any record, although it makes no sense
- // to use such size limit IRL.
- cache.setMaximumCacheSize(1);
- EXPECT_EQ(cacheSize(&cache, entryCount, entrySize), 0);
-
- insertTile(&cache, 1000, entrySize);
- EXPECT_FALSE(tileIsCached(&cache, 1000));
-
- // Zero should be treated as unlimited.
- cache.setMaximumCacheSize(0);
-
- for (unsigned i = 0; i < entryCount; ++i) {
- insertTile(&cache, i, entrySize);
- }
-
- EXPECT_EQ(cacheSize(&cache, entryCount, entrySize), expectedCacheSize);
-}
-
-TEST_F(Storage, CacheSizePruneLeastAccessed) {
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
-
- const unsigned entryCount = 400;
- const uint64_t entrySize = 10 * 1024; // 10 KB
-
- cache.setMaximumCacheEntrySize(entrySize + 1);
- cache.setMaximumCacheSize(entrySize * 350);
-
- for (unsigned i = 0; i < entryCount; ++i) {
- insertTile(&cache, i, entrySize);
-
- if (i == entryCount / 2) {
- // We need to sleep for 1s here because
- // that is the time resolution for the
- // `accessed` time. Then we 'ping' the
- // entry, that should update the
- // `accessed` time, so it won't get
- // pruned when we need more space.
- bool done = false;
-
- util::Timer timer;
- timer.start(Milliseconds(1300),
- Duration::zero(),
- [&done] { done = true; });
-
- while (!done) {
- loop.runOnce();
- }
-
- EXPECT_TRUE(tileIsCached(&cache, 7));
-
- // Refresh should also update the `accessed`
- // time of a tile.
- refreshTile(&cache, 9);
- }
- }
-
- EXPECT_FALSE(tileIsCached(&cache, 6));
- EXPECT_FALSE(tileIsCached(&cache, 8));
- EXPECT_FALSE(tileIsCached(&cache, 10));
-
- EXPECT_TRUE(tileIsCached(&cache, 7));
- EXPECT_TRUE(tileIsCached(&cache, 9));
-}
-
-TEST_F(Storage, CacheSizeStress) {
- using namespace mbgl;
-
- util::RunLoop loop;
- SQLiteCache cache(":memory:");
-
- const unsigned entryCount = 2000;
- const uint64_t entrySize = 10 * 1024; // 10 KB
-
- cache.setMaximumCacheEntrySize(entrySize + 1);
- cache.setMaximumCacheSize(entrySize * 300);
-
- for (unsigned i = 0; i < entryCount; ++i) {
- insertTile(&cache, i, entrySize);
- }
-
- // Should not be in the cache as they were
- // first inserted.
- EXPECT_FALSE(tileIsCached(&cache, 0));
- EXPECT_FALSE(tileIsCached(&cache, 99));
- EXPECT_FALSE(tileIsCached(&cache, 199));
- EXPECT_FALSE(tileIsCached(&cache, 299));
- EXPECT_FALSE(tileIsCached(&cache, 399));
-
- EXPECT_TRUE(tileIsCached(&cache, entryCount - 1));
-
- EXPECT_LT(cacheSize(&cache, entryCount, entrySize), entrySize * 300);
-}
diff --git a/test/storage/cache_stale.cpp b/test/storage/cache_stale.cpp
deleted file mode 100644
index 9ad0d1c06e..0000000000
--- a/test/storage/cache_stale.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/platform/default/headless_display.hpp>
-#include <mbgl/platform/default/headless_view.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/storage/default_file_source.hpp>
-
-#include <mbgl/platform/log.hpp>
-#include <mbgl/util/work_request.hpp>
-#include <mbgl/util/io.hpp>
-
-using namespace mbgl;
-using namespace std::literals::chrono_literals;
-using namespace std::literals::string_literals;
-
-namespace {
-
-void checkRendering(Map& map,
- const char* name,
- std::chrono::milliseconds timeout,
- double imageThreshold = 0.001,
- double pixelThreshold = 0.1) {
- test::checkImage("test/fixtures/stale/"s + name, test::render(map, timeout), imageThreshold,
- pixelThreshold);
-}
-
-Response expiredItem(const std::string& path) {
- Response response;
- response.data = std::make_shared<std::string>(util::read_file("test/fixtures/"s + path));
- response.expires = SystemClock::from_time_t(0);
- return response;
-}
-
-const std::string prefix = "http://127.0.0.1:3000";
-
-}
-
-auto display = std::make_shared<mbgl::HeadlessDisplay>();
-
-TEST_F(Storage, CacheStaleStyle) {
- HeadlessView view(display, 1);
-
- auto cache = SQLiteCache::getShared(":memory:");
-
- // Rig the cache with an expired stylesheet.
- const std::string stylePath = "stale/style.json";
- const Resource styleResource{ Resource::Kind::Style, prefix + "/" + stylePath };
- cache->put(styleResource, expiredItem(stylePath));
-
- DefaultFileSource fileSource(":memory:", ".");
-
- Map map(view, fileSource, MapMode::Still);
- map.setStyleURL(styleResource.url);
-
- checkRendering(map, "stale_style", 1000ms);
-}
-
-TEST_F(Storage, CacheStaleStyleAndTileJSON) {
- HeadlessView view(display, 1);
-
- auto cache = SQLiteCache::getShared(":memory:");
-
- // Rig the cache with an expired stylesheet.
- const std::string stylePath = "stale/style_and_tilejson.json";
- const Resource styleResource{ Resource::Kind::Style, prefix + "/" + stylePath };
- cache->put(styleResource, expiredItem(stylePath));
-
- // Rig the cache with an expired TileJSON.
- const std::string tilejsonPath = "stale/streets.json";
- const Resource tilejsonResource{ Resource::Kind::Source, prefix + "/" + tilejsonPath };
- cache->put(tilejsonResource, expiredItem(tilejsonPath));
-
- DefaultFileSource fileSource(":memory:", ".");
-
- Map map(view, fileSource, MapMode::Still);
- map.setStyleURL(styleResource.url);
-
- checkRendering(map, "stale_style_and_tilejson", 1000ms);
-}
-
-TEST_F(Storage, CacheStaleStyleAndSprite) {
- HeadlessView view(display, 1);
-
- auto cache = SQLiteCache::getShared(":memory:");
-
- // Rig the cache with an expired stylesheet.
- const std::string stylePath = "stale/style_and_sprite.json";
- const Resource styleResource{ Resource::Kind::Style, prefix + "/" + stylePath };
- cache->put(styleResource, expiredItem(stylePath));
-
- // Rig the cache with an expired sprite JSON.
- const std::string spritejsonPath = "stale/sprite.json";
- const Resource spritejsonResource{ Resource::Kind::SpriteJSON, prefix + "/" + spritejsonPath };
- cache->put(spritejsonResource, expiredItem(spritejsonPath));
-
- // Rig the cache with an expired sprite JSON.
- const std::string spriteimagePath = "stale/sprite.png";
- const Resource spriteimageResource{ Resource::Kind::SpriteImage, prefix + "/" + spriteimagePath };
- cache->put(spriteimageResource, expiredItem(spriteimagePath));
-
- DefaultFileSource fileSource(":memory:", ".");
-
- Map map(view, fileSource, MapMode::Still);
- map.setStyleURL(styleResource.url);
-
- checkRendering(map, "stale_style_and_sprite", 1000ms);
-}
-
-TEST_F(Storage, CacheStaleStyleAndGlyphs) {
- HeadlessView view(display, 1);
-
- auto cache = SQLiteCache::getShared(":memory:");
-
- // Rig the cache with an expired stylesheet.
- const std::string stylePath = "stale/style_and_glyphs.json";
- const Resource styleResource{ Resource::Kind::Style, prefix + "/" + stylePath };
- cache->put(styleResource, expiredItem(stylePath));
-
- // Rig the cache with an expired glyph PBF.
- const std::string glyphPath = "stale/glyph.pbf";
- const Resource glyphResource{ Resource::Kind::Glyphs, prefix + "/stale/Open%20Sans%20Regular%2c%20Arial%20Unicode%20MS%20Regular/0-255.pbf" };
- cache->put(glyphResource, expiredItem(glyphPath));
-
- DefaultFileSource fileSource(":memory:", ".");
-
- Map map(view, fileSource, MapMode::Still);
- map.setStyleURL(styleResource.url);
-
- // TODO: this shouldn't take > 1 second
- checkRendering(map, "stale_style_and_glyphs", 2000ms, 0.0015);
-}
diff --git a/test/storage/database.cpp b/test/storage/database.cpp
deleted file mode 100644
index 19b46763b9..0000000000
--- a/test/storage/database.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
-#include "storage.hpp"
-#include "../fixtures/fixture_log_observer.hpp"
-
-#include "sqlite_cache_impl.hpp"
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/util/io.hpp>
-
-#include <sqlite3.h>
-
-TEST_F(Storage, DatabaseDoesNotExist) {
- using namespace mbgl;
-
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- SQLiteCache::Impl cache("test/fixtures/404/cache.db");
-
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- auto observer = Log::removeObserver();
- EXPECT_EQ(1ul, dynamic_cast<FixtureLogObserver*>(observer.get())->count({ EventSeverity::Error, Event::Database, 14, "unable to open database file" }));
-}
-
-void createDir(const char* name) {
- const int ret = mkdir(name, 0755);
- if (ret == -1) {
- ASSERT_EQ(EEXIST, errno);
- } else {
- ASSERT_EQ(0, ret);
- }
-}
-
-void deleteFile(const char* name) {
- const int ret = unlink(name);
- if (ret == -1) {
- ASSERT_EQ(ENOENT, errno);
- } else {
- ASSERT_EQ(0, ret);
- }
-}
-
-
-void writeFile(const char* name, const std::string& data) {
- mbgl::util::write_file(name, data);
-}
-
-
-TEST_F(Storage, DatabaseCreate) {
- using namespace mbgl;
-
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/cache.db");
-
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- SQLiteCache::Impl cache("test/fixtures/database/cache.db");
-
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- Log::removeObserver();
-}
-
-TEST_F(Storage, DatabaseVersion) {
- using namespace mbgl;
-
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/cache.db");
- std::string path("test/fixtures/database/cache.db");
-
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- {
- SQLiteCache::Impl cache(path);
- cache.put({ Resource::Unknown, "mapbox://test" }, Response());
- }
-
- sqlite3* db;
- sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READWRITE, nullptr);
- sqlite3_exec(db, "PRAGMA user_version = 999999", nullptr, nullptr, nullptr);
- sqlite3_close_v2(db);
-
- // Changing the version will force the database to get recreated
- // thus removing every pre-existing cache entry.
- {
- SQLiteCache::Impl cache(path);
-
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
- }
-
- Log::removeObserver();
-}
-
-class FileLock {
-public:
- FileLock(const std::string& path) {
- const int err = sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
- if (err != SQLITE_OK) {
- throw std::runtime_error("Could not open db");
- }
- lock();
- }
-
- void lock() {
- assert(!locked);
- const int err = sqlite3_exec(db, "begin exclusive transaction", nullptr, nullptr, nullptr);
- if (err != SQLITE_OK) {
- throw std::runtime_error("Could not lock db");
- }
- locked = true;
- }
-
- void unlock() {
- assert(locked);
- const int err = sqlite3_exec(db, "commit", nullptr, nullptr, nullptr);
- if (err != SQLITE_OK) {
- throw std::runtime_error("Could not unlock db");
- }
- locked = false;
- }
-
- ~FileLock() {
- if (locked) {
- unlock();
- }
- }
-
-private:
- sqlite3* db;
- bool locked = false;
-};
-
-TEST_F(Storage, DatabaseLockedRead) {
- using namespace mbgl;
-
- // Create a locked file.
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/locked.db");
- FileLock guard("test/fixtures/database/locked.db");
-
- SQLiteCache::Impl cache("test/fixtures/database/locked.db");
-
- {
- // First request should fail.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- // Make sure that we got a few "database locked" errors
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(4ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
- }
-
- // Then, unlock the file and try again.
- guard.unlock();
-
- {
- // First, try getting a file (the cache value should not exist).
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- // Make sure that we got a no errors
- Log::removeObserver();
- }
-}
-
-
-
-TEST_F(Storage, DatabaseLockedWrite) {
- using namespace mbgl;
-
- // Create a locked file.
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/locked.db");
- FileLock guard("test/fixtures/database/locked.db");
-
- SQLiteCache::Impl cache("test/fixtures/database/locked.db");
-
- {
- // Adds a file (which should fail).
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- cache.put({ Resource::Unknown, "mapbox://test" }, Response());
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(8ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
- }
-
- // Then, unlock the file and try again.
- guard.unlock();
-
- {
- // Then, set a file and obtain it again.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Response response;
- response.data = std::make_shared<std::string>("Demo");
- cache.put({ Resource::Unknown, "mapbox://test" }, response);
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- ASSERT_NE(nullptr, res.get());
- ASSERT_TRUE(res->data.get());
- EXPECT_EQ("Demo", *res->data);
- });
-
- // Make sure that we got a no errors
- Log::removeObserver();
- }
-}
-
-
-
-
-TEST_F(Storage, DatabaseLockedRefresh) {
- using namespace mbgl;
-
- // Create a locked file.
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/locked.db");
-
- SQLiteCache::Impl cache("test/fixtures/database/locked.db");
-
- // Then, lock the file and try again.
- FileLock guard("test/fixtures/database/locked.db");
-
- {
- // Adds a file.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Response response;
- response.data = std::make_shared<std::string>("Demo");
- cache.put({ Resource::Unknown, "mapbox://test" }, response);
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(8ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
- }
-
- {
- // Then, try to refresh it.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- cache.refresh({ Resource::Unknown, "mapbox://test" }, {});
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- EXPECT_EQ(nullptr, res.get());
- });
-
- // Make sure that we got the right errors.
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(8ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
- }
-}
-
-
-
-TEST_F(Storage, DatabaseDeleted) {
- using namespace mbgl;
-
- // Create a locked file.
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/locked.db");
-
- SQLiteCache::Impl cache("test/fixtures/database/locked.db");
-
- {
- // Adds a file.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Response response;
- response.data = std::make_shared<std::string>("Demo");
- cache.put({ Resource::Unknown, "mapbox://test" }, response);
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- ASSERT_NE(nullptr, res.get());
- ASSERT_TRUE(res->data.get());
- EXPECT_EQ("Demo", *res->data);
- });
-
- Log::removeObserver();
- }
-
- deleteFile("test/fixtures/database/locked.db");
-
- {
- // Adds a file.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Response response;
- response.data = std::make_shared<std::string>("Demo");
- cache.put({ Resource::Unknown, "mapbox://test" }, response);
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- ASSERT_NE(nullptr, res.get());
- ASSERT_TRUE(res->data.get());
- EXPECT_EQ("Demo", *res->data);
- });
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(1ul, flo->count({ EventSeverity::Error, Event::Database, 8, "attempt to write a readonly database" }));
- }
-}
-
-
-
-TEST_F(Storage, DatabaseInvalid) {
- using namespace mbgl;
-
- // Create a locked file.
- createDir("test/fixtures/database");
- deleteFile("test/fixtures/database/invalid.db");
- writeFile("test/fixtures/database/invalid.db", "this is an invalid file");
-
- SQLiteCache::Impl cache("test/fixtures/database/invalid.db");
-
- {
- // Adds a file.
- Log::setObserver(std::make_unique<FixtureLogObserver>());
-
- Response response;
- response.data = std::make_shared<std::string>("Demo");
- cache.put({ Resource::Unknown, "mapbox://test" }, response);
- cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
- ASSERT_NE(nullptr, res.get());
- ASSERT_TRUE(res->data.get());
- EXPECT_EQ("Demo", *res->data);
- });
-
- auto observer = Log::removeObserver();
- auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
- EXPECT_EQ(1ul, flo->count({ EventSeverity::Warning, Event::Database, -1, "Trashing invalid database" }));
- }
-}
diff --git a/test/storage/cache_revalidate.cpp b/test/storage/default_file_source.cpp
index 10dee80a00..26fb164d3f 100644
--- a/test/storage/cache_revalidate.cpp
+++ b/test/storage/default_file_source.cpp
@@ -1,18 +1,60 @@
#include "storage.hpp"
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/util/chrono.hpp>
+#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/run_loop.hpp>
-TEST_F(Storage, CacheRevalidateSame) {
+class DefaultFileSourceTest : public Storage {};
+
+TEST_F(DefaultFileSourceTest, CacheResponse) {
+ SCOPED_TEST(CacheResponse);
+
+ using namespace mbgl;
+
+ util::RunLoop loop;
+ DefaultFileSource fs(":memory:", ".");
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/cache" };
+ Response response;
+
+ std::unique_ptr<FileRequest> req1;
+ std::unique_ptr<FileRequest> req2;
+
+ req1 = fs.request(resource, [&](Response res) {
+ req1.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Response 1", *res.data);
+ EXPECT_TRUE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ response = res;
+
+ // Now test that we get the same values as in the previous request. If we'd go to the server
+ // again, we'd get different values.
+ req2 = fs.request(resource, [&](Response res2) {
+ req2.reset();
+ EXPECT_EQ(response.error, res2.error);
+ ASSERT_TRUE(res2.data.get());
+ EXPECT_EQ(*response.data, *res2.data);
+ EXPECT_EQ(response.expires, res2.expires);
+ EXPECT_EQ(response.modified, res2.modified);
+ EXPECT_EQ(response.etag, res2.etag);
+
+ loop.stop();
+ CacheResponse.finish();
+ });
+ });
+
+ loop.run();
+}
+
+TEST_F(DefaultFileSourceTest, CacheRevalidateSame) {
SCOPED_TEST(CacheRevalidateSame)
using namespace mbgl;
util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
+ DefaultFileSource fs(":memory:", ".");
const Resource revalidateSame { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" };
std::unique_ptr<FileRequest> req1;
@@ -55,14 +97,13 @@ TEST_F(Storage, CacheRevalidateSame) {
loop.run();
}
-TEST_F(Storage, CacheRevalidateModified) {
+TEST_F(DefaultFileSourceTest, CacheRevalidateModified) {
SCOPED_TEST(CacheRevalidateModified)
using namespace mbgl;
util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
+ DefaultFileSource fs(":memory:", ".");
const Resource revalidateModified{ Resource::Unknown,
"http://127.0.0.1:3000/revalidate-modified" };
@@ -105,14 +146,13 @@ TEST_F(Storage, CacheRevalidateModified) {
loop.run();
}
-TEST_F(Storage, CacheRevalidateEtag) {
+TEST_F(DefaultFileSourceTest, CacheRevalidateEtag) {
SCOPED_TEST(CacheRevalidateEtag)
using namespace mbgl;
util::RunLoop loop;
- SQLiteCache cache(":memory:");
- OnlineFileSource fs(&cache);
+ DefaultFileSource fs(":memory:", ".");
const Resource revalidateEtag { Resource::Unknown, "http://127.0.0.1:3000/revalidate-etag" };
std::unique_ptr<FileRequest> req1;
diff --git a/test/storage/headers.cpp b/test/storage/headers.cpp
index a0b6ecd546..2ec409e8e0 100644
--- a/test/storage/headers.cpp
+++ b/test/storage/headers.cpp
@@ -10,62 +10,62 @@ TEST_F(Storage, HTTPHeaderParsing) {
cc = http::CacheControl::parse(R"#()#");
ASSERT_FALSE(bool(cc.maxAge));
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age =34)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(34, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(,max-age=1)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(1, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age=-1)#");
ASSERT_FALSE(bool(cc.maxAge));
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age=foo)#");
ASSERT_FALSE(bool(cc.maxAge));
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age="34,max-age="22,max-age=28)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(28, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age=3,max-age="34)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(3, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age="\",max-age=4,")#");
ASSERT_FALSE(bool(cc.maxAge));
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(private, max-age=0, no-cache)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(0, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age=0, no-cache, no-store)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(0, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(, private , max-bar=3 , no-cache, "\,",,foo=",",,max-age=32)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(32, *cc.maxAge);
- EXPECT_EQ(false, cc.mustRevalidate);
+ EXPECT_FALSE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(max-age=3600, must-revalidate)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(3600, *cc.maxAge);
- EXPECT_EQ(true, cc.mustRevalidate);
+ EXPECT_TRUE(cc.mustRevalidate);
cc = http::CacheControl::parse(R"#(no-cache="Expires,Via",max-age=3600, must-revalidate)#");
ASSERT_TRUE(bool(cc.maxAge));
EXPECT_EQ(3600, *cc.maxAge);
- EXPECT_EQ(true, cc.mustRevalidate);
+ EXPECT_TRUE(cc.mustRevalidate);
}
diff --git a/test/storage/http_cancel.cpp b/test/storage/http_cancel.cpp
index 4d816c5095..983bc22b16 100644
--- a/test/storage/http_cancel.cpp
+++ b/test/storage/http_cancel.cpp
@@ -13,7 +13,7 @@ TEST_F(Storage, HTTPCancel) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
auto req =
fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
@@ -31,7 +31,7 @@ TEST_F(Storage, HTTPCancelMultiple) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
diff --git a/test/storage/http_error.cpp b/test/storage/http_error.cpp
index 28e8573a2c..259ea825eb 100644
--- a/test/storage/http_error.cpp
+++ b/test/storage/http_error.cpp
@@ -13,7 +13,7 @@ TEST_F(Storage, HTTPTemporaryError) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const auto start = Clock::now();
@@ -26,8 +26,7 @@ TEST_F(Storage, HTTPTemporaryError) {
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
EXPECT_EQ("HTTP status code 500", res.error->message);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("", *res.data);
+ ASSERT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
@@ -58,7 +57,7 @@ TEST_F(Storage, HTTPConnectionError) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const auto start = Clock::now();
diff --git a/test/storage/http_header_parsing.cpp b/test/storage/http_header_parsing.cpp
index 521fa239e6..d98b09924f 100644
--- a/test/storage/http_header_parsing.cpp
+++ b/test/storage/http_header_parsing.cpp
@@ -12,7 +12,7 @@ TEST_F(Storage, HTTPExpiresParsing) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req1 = fs.request({ Resource::Unknown,
"http://127.0.0.1:3000/test?modified=1420794326&expires=1420797926&etag=foo" },
@@ -37,7 +37,7 @@ TEST_F(Storage, HTTPCacheControlParsing) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=120" },
[&](Response res) {
diff --git a/test/storage/http_issue_1369.cpp b/test/storage/http_issue_1369.cpp
index 17c6f86f74..3830a51718 100644
--- a/test/storage/http_issue_1369.cpp
+++ b/test/storage/http_issue_1369.cpp
@@ -1,8 +1,6 @@
#include "storage.hpp"
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/sqlite_cache.hpp>
-#include <mbgl/util/chrono.hpp>
+#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/run_loop.hpp>
// Test for https://github.com/mapbox/mapbox-gl-native/issue/1369
@@ -22,8 +20,7 @@ TEST_F(Storage, HTTPIssue1369) {
using namespace mbgl;
util::RunLoop loop;
- SQLiteCache cache;
- OnlineFileSource fs(&cache);
+ DefaultFileSource fs(":memory:", ".");
const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
diff --git a/test/storage/http_load.cpp b/test/storage/http_load.cpp
index 8088bb5e34..52f700c4f8 100644
--- a/test/storage/http_load.cpp
+++ b/test/storage/http_load.cpp
@@ -10,7 +10,7 @@ TEST_F(Storage, HTTPLoad) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const int concurrency = 50;
const int max = 10000;
diff --git a/test/storage/http_other_loop.cpp b/test/storage/http_other_loop.cpp
index fda51c3cf3..4eb6a7df18 100644
--- a/test/storage/http_other_loop.cpp
+++ b/test/storage/http_other_loop.cpp
@@ -11,7 +11,7 @@ TEST_F(Storage, HTTPOtherLoop) {
// This file source launches a separate thread to do the processing.
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
[&](Response res) {
diff --git a/test/storage/http_reading.cpp b/test/storage/http_reading.cpp
index 4d8d510615..fdc49ee5e6 100644
--- a/test/storage/http_reading.cpp
+++ b/test/storage/http_reading.cpp
@@ -14,7 +14,7 @@ TEST_F(Storage, HTTPTest) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req1 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
[&](Response res) {
@@ -39,7 +39,7 @@ TEST_F(Storage, HTTP404) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/doesnotexist" },
[&](Response res) {
@@ -47,9 +47,8 @@ TEST_F(Storage, HTTP404) {
EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Cannot GET /doesnotexist\n", *res.data);
EXPECT_EQ("HTTP status code 404", res.error->message);
+ EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
@@ -60,13 +59,88 @@ TEST_F(Storage, HTTP404) {
loop.run();
}
+TEST_F(Storage, HTTPTile404) {
+ SCOPED_TEST(HTTPTile404)
+
+ using namespace mbgl;
+
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ std::unique_ptr<FileRequest> req2 = fs.request({ Resource::Tile, "http://127.0.0.1:3000/doesnotexist" },
+ [&](Response res) {
+ req2.reset();
+ EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
+ EXPECT_TRUE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ HTTPTile404.finish();
+ });
+
+ loop.run();
+}
+
+TEST_F(Storage, HTTP200EmptyData) {
+ SCOPED_TEST(HTTP200EmptyData)
+
+ using namespace mbgl;
+
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ std::unique_ptr<FileRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/empty-data" },
+ [&](Response res) {
+ req.reset();
+ EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
+ EXPECT_FALSE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_EQ(*res.data, std::string());
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ HTTP200EmptyData.finish();
+ });
+
+ loop.run();
+}
+
+TEST_F(Storage, HTTP204) {
+ SCOPED_TEST(HTTP204)
+
+ using namespace mbgl;
+
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ std::unique_ptr<FileRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/no-content" },
+ [&](Response res) {
+ req2.reset();
+ EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
+ EXPECT_TRUE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ HTTP204.finish();
+ });
+
+ loop.run();
+}
+
TEST_F(Storage, HTTP500) {
SCOPED_TEST(HTTP500)
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
std::unique_ptr<FileRequest> req3 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/permanent-error" },
[&](Response res) {
@@ -74,9 +148,8 @@ TEST_F(Storage, HTTP500) {
EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Server Error!", *res.data);
EXPECT_EQ("HTTP status code 500", res.error->message);
+ EXPECT_FALSE(bool(res.data));
EXPECT_FALSE(bool(res.expires));
EXPECT_FALSE(bool(res.modified));
EXPECT_FALSE(bool(res.etag));
@@ -93,7 +166,7 @@ TEST_F(Storage, HTTPNoCallback) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
try {
fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
diff --git a/test/storage/http_retry_network_status.cpp b/test/storage/http_retry_network_status.cpp
index df9284f995..feb07d0245 100644
--- a/test/storage/http_retry_network_status.cpp
+++ b/test/storage/http_retry_network_status.cpp
@@ -18,7 +18,7 @@ TEST_F(Storage, HTTPNetworkStatusChange) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/delayed" };
@@ -41,11 +41,6 @@ TEST_F(Storage, HTTPNetworkStatusChange) {
mbgl::NetworkStatus::Reachable();
});
- // This timer will keep the loop alive to make sure we would be getting a response in caes the
- // network status change triggered another change (which it shouldn't).
- util::Timer delayTimer;
- delayTimer.start(Milliseconds(300), Duration::zero(), [] () {});
-
loop.run();
}
@@ -57,7 +52,7 @@ TEST_F(Storage, HTTPNetworkStatusChangePreempt) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
const auto start = Clock::now();
diff --git a/test/storage/http_timeout.cpp b/test/storage/http_timeout.cpp
index 8f8a5e2633..ef0750010e 100644
--- a/test/storage/http_timeout.cpp
+++ b/test/storage/http_timeout.cpp
@@ -11,7 +11,7 @@ TEST_F(Storage, HTTPTimeout) {
using namespace mbgl;
util::RunLoop loop;
- OnlineFileSource fs(nullptr);
+ OnlineFileSource fs;
int counter = 0;
diff --git a/test/storage/offline.cpp b/test/storage/offline.cpp
new file mode 100644
index 0000000000..e8f78425f5
--- /dev/null
+++ b/test/storage/offline.cpp
@@ -0,0 +1,73 @@
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/source/source_info.hpp>
+#include <mbgl/map/tile_id.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace mbgl;
+
+static const LatLngBounds sanFrancisco = LatLngBounds::hull(
+ { 37.6609, -122.5744 },
+ { 37.8271, -122.3204 });
+
+static const LatLngBounds sanFranciscoWrapped = LatLngBounds::hull(
+ { 37.6609, 238.5744 },
+ { 37.8271, 238.3204 });
+
+TEST(OfflineTilePyramidRegionDefinition, TileCoverEmpty) {
+ OfflineTilePyramidRegionDefinition region("", LatLngBounds::empty(), 0, 20, 1.0);
+ SourceInfo info;
+
+ auto result = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_TRUE(result.empty());
+}
+
+TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomIntersection) {
+ OfflineTilePyramidRegionDefinition region("", sanFrancisco, 2, 2, 1.0);
+ SourceInfo info;
+
+ info.minZoom = 0;
+ auto resultIntersection = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_EQ(1, resultIntersection.size());
+
+ info.minZoom = 3;
+ auto resultNoIntersection = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_TRUE(resultNoIntersection.empty());
+}
+
+TEST(OfflineTilePyramidRegionDefinition, TileCoverTileSize) {
+ OfflineTilePyramidRegionDefinition region("", LatLngBounds::world(), 0, 0, 1.0);
+ SourceInfo info;
+
+ auto result512 = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_EQ(1, result512.size());
+ ASSERT_EQ(0, result512[0].z);
+
+ auto result256 = region.tileCover(SourceType::Vector, 256, info);
+ ASSERT_EQ(4, result256.size());
+ ASSERT_EQ(1, result256[0].z);
+}
+
+TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomRounding) {
+ OfflineTilePyramidRegionDefinition region("", sanFrancisco, 0.6, 0.7, 1.0);
+ SourceInfo info;
+
+ auto resultVector = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_EQ(1, resultVector.size());
+ ASSERT_EQ(0, resultVector[0].z);
+
+ auto resultRaster = region.tileCover(SourceType::Raster, 512, info);
+ ASSERT_EQ(1, resultRaster.size());
+ ASSERT_EQ(1, resultRaster[0].z);
+}
+
+TEST(OfflineTilePyramidRegionDefinition, TileCoverWrapped) {
+ OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 0, 1.0);
+ SourceInfo info;
+
+ auto result = region.tileCover(SourceType::Vector, 512, info);
+ ASSERT_EQ(1, result.size());
+ ASSERT_EQ(0, result[0].z);
+ ASSERT_EQ(0, result[0].x);
+ ASSERT_EQ(0, result[0].y);
+}
diff --git a/test/storage/offline_database.cpp b/test/storage/offline_database.cpp
new file mode 100644
index 0000000000..3a731e3995
--- /dev/null
+++ b/test/storage/offline_database.cpp
@@ -0,0 +1,573 @@
+#include "../fixtures/fixture_log_observer.hpp"
+
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <gtest/gtest.h>
+#include <sqlite3.h>
+#include <thread>
+#include <random>
+
+using namespace std::literals::string_literals;
+
+namespace {
+
+void createDir(const char* name) {
+ const int ret = mkdir(name, 0755);
+ if (ret == -1) {
+ ASSERT_EQ(EEXIST, errno);
+ } else {
+ ASSERT_EQ(0, ret);
+ }
+}
+
+void deleteFile(const char* name) {
+ const int ret = unlink(name);
+ if (ret == -1) {
+ ASSERT_EQ(ENOENT, errno);
+ } else {
+ ASSERT_EQ(0, ret);
+ }
+}
+
+void writeFile(const char* name, const std::string& data) {
+ mbgl::util::write_file(name, data);
+}
+
+class FileLock {
+public:
+ FileLock(const std::string& path) {
+ const int err = sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
+ if (err != SQLITE_OK) {
+ throw std::runtime_error("Could not open db");
+ }
+ lock();
+ }
+
+ void lock() {
+ assert(!locked);
+ const int err = sqlite3_exec(db, "begin exclusive transaction", nullptr, nullptr, nullptr);
+ if (err != SQLITE_OK) {
+ throw std::runtime_error("Could not lock db");
+ }
+ locked = true;
+ }
+
+ void unlock() {
+ assert(locked);
+ const int err = sqlite3_exec(db, "commit", nullptr, nullptr, nullptr);
+ if (err != SQLITE_OK) {
+ throw std::runtime_error("Could not unlock db");
+ }
+ locked = false;
+ }
+
+ ~FileLock() {
+ if (locked) {
+ unlock();
+ }
+ }
+
+private:
+ sqlite3* db;
+ bool locked = false;
+};
+
+}
+
+//TEST(OfflineDatabase, NonexistentDirectory) {
+// using namespace mbgl;
+//
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// OfflineDatabase db("test/fixtures/404/offline.db");
+//
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// EXPECT_FALSE(bool(res));
+// });
+//
+// auto observer = Log::removeObserver();
+// EXPECT_EQ(1ul, dynamic_cast<FixtureLogObserver*>(observer.get())->count({ EventSeverity::Error, Event::Database, 14, "unable to open database file" }));
+//}
+
+TEST(OfflineDatabase, Create) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/database");
+ deleteFile("test/fixtures/database/offline.db");
+
+ Log::setObserver(std::make_unique<FixtureLogObserver>());
+
+ OfflineDatabase db("test/fixtures/database/offline.db");
+ EXPECT_FALSE(bool(db.get({ Resource::Unknown, "mapbox://test" })));
+
+ Log::removeObserver();
+}
+
+TEST(OfflineDatabase, SchemaVersion) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/database");
+ deleteFile("test/fixtures/database/offline.db");
+ std::string path("test/fixtures/database/offline.db");
+
+ {
+ sqlite3* db;
+ sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
+ sqlite3_exec(db, "PRAGMA user_version = 1", nullptr, nullptr, nullptr);
+ sqlite3_close_v2(db);
+ }
+
+ Log::setObserver(std::make_unique<FixtureLogObserver>());
+ OfflineDatabase db(path);
+
+ auto observer = Log::removeObserver();
+ auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+ EXPECT_EQ(1ul, flo->count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" }));
+}
+
+TEST(OfflineDatabase, Invalid) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/database");
+ deleteFile("test/fixtures/database/invalid.db");
+ writeFile("test/fixtures/database/invalid.db", "this is an invalid file");
+
+ Log::setObserver(std::make_unique<FixtureLogObserver>());
+
+ OfflineDatabase db("test/fixtures/database/invalid.db");
+
+ auto observer = Log::removeObserver();
+ auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+ EXPECT_EQ(1ul, flo->count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" }));
+}
+
+//TEST(OfflineDatabase, DatabaseLockedRead) {
+// using namespace mbgl;
+//
+// // Create a locked file.
+// createDir("test/fixtures/database");
+// deleteFile("test/fixtures/database/locked.db");
+// FileLock guard("test/fixtures/database/locked.db");
+//
+// OfflineDatabase db("test/fixtures/database/locked.db");
+//
+// {
+// // First request should fail.
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// EXPECT_FALSE(bool(res));
+// });
+//
+// // Make sure that we got a few "database locked" errors
+// auto observer = Log::removeObserver();
+// auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+// EXPECT_EQ(4ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
+// }
+//
+// // Then, unlock the file and try again.
+// guard.unlock();
+//
+// {
+// // First, try getting a file (the cache value should not exist).
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// EXPECT_FALSE(bool(res));
+// });
+//
+// // Make sure that we got a no errors
+// Log::removeObserver();
+// }
+//}
+//
+//TEST(OfflineDatabase, DatabaseLockedWrite) {
+// using namespace mbgl;
+//
+// // Create a locked file.
+// createDir("test/fixtures/database");
+// deleteFile("test/fixtures/database/locked.db");
+// FileLock guard("test/fixtures/database/locked.db");
+//
+// OfflineDatabase db("test/fixtures/database/locked.db");
+//
+// {
+// // Adds a file (which should fail).
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// db.put({ Resource::Unknown, "mapbox://test" }, Response());
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// EXPECT_FALSE(bool(res));
+// });
+//
+// auto observer = Log::removeObserver();
+// auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+// EXPECT_EQ(8ul, flo->count({ EventSeverity::Error, Event::Database, 5, "database is locked" }));
+// }
+//
+// // Then, unlock the file and try again.
+// guard.unlock();
+//
+// {
+// // Then, set a file and obtain it again.
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// Response response;
+// response.data = std::make_shared<std::string>("Demo");
+// db.put({ Resource::Unknown, "mapbox://test" }, response);
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// ASSERT_TRUE(bool(res));
+// ASSERT_TRUE(res->data.get());
+// EXPECT_EQ("Demo", *res->data);
+// });
+//
+// // Make sure that we got a no errors
+// Log::removeObserver();
+// }
+//}
+//
+//TEST(OfflineDatabase, DatabaseDeleted) {
+// using namespace mbgl;
+//
+// // Create a locked file.
+// createDir("test/fixtures/database");
+// deleteFile("test/fixtures/database/locked.db");
+//
+// OfflineDatabase db("test/fixtures/database/locked.db");
+//
+// {
+// // Adds a file.
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// Response response;
+// response.data = std::make_shared<std::string>("Demo");
+// db.put({ Resource::Unknown, "mapbox://test" }, response);
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// ASSERT_TRUE(bool(res));
+// ASSERT_TRUE(res->data.get());
+// EXPECT_EQ("Demo", *res->data);
+// });
+//
+// Log::removeObserver();
+// }
+//
+// deleteFile("test/fixtures/database/locked.db");
+//
+// {
+// // Adds a file.
+// Log::setObserver(std::make_unique<FixtureLogObserver>());
+//
+// Response response;
+// response.data = std::make_shared<std::string>("Demo");
+// db.put({ Resource::Unknown, "mapbox://test" }, response);
+// db.get({ Resource::Unknown, "mapbox://test" }, [] (optional<Response> res) {
+// ASSERT_TRUE(bool(res));
+// ASSERT_TRUE(res->data.get());
+// EXPECT_EQ("Demo", *res->data);
+// });
+//
+// auto observer = Log::removeObserver();
+// auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+// EXPECT_EQ(1ul, flo->count({ EventSeverity::Error, Event::Database, 8, "attempt to write a readonly database" }));
+// }
+//}
+
+TEST(OfflineDatabase, PutDoesNotStoreConnectionErrors) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Unknown, "http://example.com/" };
+ Response response;
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::Connection);
+
+ db.put(resource, response);
+ EXPECT_FALSE(bool(db.get(resource)));
+}
+
+TEST(OfflineDatabase, PutDoesNotStoreServerErrors) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Unknown, "http://example.com/" };
+ Response response;
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::Server);
+
+ db.put(resource, response);
+ EXPECT_FALSE(bool(db.get(resource)));
+}
+
+TEST(OfflineDatabase, PutResource) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Style, "http://example.com/" };
+ Response response;
+ response.data = std::make_shared<std::string>("data");
+
+ db.put(resource, response);
+ auto res = db.get(resource);
+ EXPECT_EQ(nullptr, res->error.get());
+ EXPECT_EQ("data", *res->data);
+}
+
+TEST(OfflineDatabase, PutTile) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Tile, "http://example.com/" };
+ resource.tileData = Resource::TileData {
+ "http://example.com/",
+ 1,
+ 0,
+ 0,
+ 0
+ };
+ Response response;
+ response.data = std::make_shared<std::string>("data");
+
+ db.put(resource, response);
+ auto res = db.get(resource);
+ EXPECT_EQ(nullptr, res->error.get());
+ EXPECT_EQ("data", *res->data);
+}
+
+TEST(OfflineDatabase, PutResourceNoContent) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Style, "http://example.com/" };
+ Response response;
+ response.noContent = true;
+
+ db.put(resource, response);
+ auto res = db.get(resource);
+ EXPECT_EQ(nullptr, res->error);
+ EXPECT_TRUE(res->noContent);
+ EXPECT_FALSE(res->data.get());
+}
+
+TEST(OfflineDatabase, PutTileNotFound) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Resource resource { Resource::Tile, "http://example.com/" };
+ resource.tileData = Resource::TileData {
+ "http://example.com/",
+ 1,
+ 0,
+ 0,
+ 0
+ };
+ Response response;
+ response.noContent = true;
+
+ db.put(resource, response);
+ auto res = db.get(resource);
+ EXPECT_EQ(nullptr, res->error);
+ EXPECT_TRUE(res->noContent);
+ EXPECT_FALSE(res->data.get());
+}
+
+TEST(OfflineDatabase, CreateRegion) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+ OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 };
+ OfflineRegionMetadata metadata {{ 1, 2, 3 }};
+ OfflineRegion region = db.createRegion(definition, metadata);
+
+ EXPECT_EQ(definition.styleURL, region.getDefinition().styleURL);
+ EXPECT_EQ(definition.bounds, region.getDefinition().bounds);
+ EXPECT_EQ(definition.minZoom, region.getDefinition().minZoom);
+ EXPECT_EQ(definition.maxZoom, region.getDefinition().maxZoom);
+ EXPECT_EQ(definition.pixelRatio, region.getDefinition().pixelRatio);
+ EXPECT_EQ(metadata, region.getMetadata());
+}
+
+TEST(OfflineDatabase, ListRegions) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+ OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 };
+ OfflineRegionMetadata metadata {{ 1, 2, 3 }};
+
+ OfflineRegion region = db.createRegion(definition, metadata);
+ std::vector<OfflineRegion> regions = db.listRegions();
+
+ ASSERT_EQ(1, regions.size());
+ EXPECT_EQ(region.getID(), regions.at(0).getID());
+ EXPECT_EQ(definition.styleURL, regions.at(0).getDefinition().styleURL);
+ EXPECT_EQ(definition.bounds, regions.at(0).getDefinition().bounds);
+ EXPECT_EQ(definition.minZoom, regions.at(0).getDefinition().minZoom);
+ EXPECT_EQ(definition.maxZoom, regions.at(0).getDefinition().maxZoom);
+ EXPECT_EQ(definition.pixelRatio, regions.at(0).getDefinition().pixelRatio);
+ EXPECT_EQ(metadata, regions.at(0).getMetadata());
+}
+
+TEST(OfflineDatabase, GetRegionDefinition) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+ OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 };
+ OfflineRegionMetadata metadata {{ 1, 2, 3 }};
+
+ OfflineRegion region = db.createRegion(definition, metadata);
+ OfflineRegionDefinition result = db.getRegionDefinition(region.getID());
+
+ EXPECT_EQ(definition.styleURL, result.styleURL);
+ EXPECT_EQ(definition.bounds, result.bounds);
+ EXPECT_EQ(definition.minZoom, result.minZoom);
+ EXPECT_EQ(definition.maxZoom, result.maxZoom);
+ EXPECT_EQ(definition.pixelRatio, result.pixelRatio);
+}
+
+TEST(OfflineDatabase, DeleteRegion) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+ OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 };
+ OfflineRegionMetadata metadata {{ 1, 2, 3 }};
+ db.deleteRegion(db.createRegion(definition, metadata));
+
+ ASSERT_EQ(0, db.listRegions().size());
+}
+
+TEST(OfflineDatabase, CreateRegionInfiniteMaxZoom) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+ OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 };
+ OfflineRegionMetadata metadata;
+ OfflineRegion region = db.createRegion(definition, metadata);
+
+ EXPECT_EQ(0, region.getDefinition().minZoom);
+ EXPECT_EQ(INFINITY, region.getDefinition().maxZoom);
+}
+
+TEST(OfflineDatabase, ConcurrentUse) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/database");
+ deleteFile("test/fixtures/database/offline.db");
+
+ OfflineDatabase db1("test/fixtures/database/offline.db");
+ OfflineDatabase db2("test/fixtures/database/offline.db");
+
+ Resource resource { Resource::Style, "http://example.com/" };
+ Response response;
+ response.noContent = true;
+
+ std::thread thread1([&] {
+ for (auto i = 0; i < 100; i++) {
+ db1.put(resource, response);
+ EXPECT_TRUE(bool(db1.get(resource)));
+ }
+ });
+
+ std::thread thread2([&] {
+ for (auto i = 0; i < 100; i++) {
+ db2.put(resource, response);
+ EXPECT_TRUE(bool(db2.get(resource)));
+ }
+ });
+
+ thread1.join();
+ thread2.join();
+}
+
+static std::shared_ptr<std::string> randomString(size_t size) {
+ auto result = std::make_shared<std::string>(size, 0);
+ std::mt19937 random;
+
+ for (size_t i = 0; i < size; i++) {
+ (*result)[i] = random();
+ }
+
+ return result;
+}
+
+TEST(OfflineDatabase, PutReturnsSize) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Response compressible;
+ compressible.data = std::make_shared<std::string>(1024, 0);
+ EXPECT_EQ(17, db.put(Resource::style("http://example.com/compressible"), compressible));
+
+ Response incompressible;
+ incompressible.data = randomString(1024);
+ EXPECT_EQ(1024, db.put(Resource::style("http://example.com/incompressible"), incompressible));
+
+ Response noContent;
+ noContent.noContent = true;
+ EXPECT_EQ(0, db.put(Resource::style("http://example.com/noContent"), noContent));
+}
+
+TEST(OfflineDatabase, PutEvictsLeastRecentlyUsedResources) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:", 1024 * 25);
+
+ Response response;
+ response.data = randomString(1024);
+
+ for (uint32_t i = 1; i <= 20; i++) {
+ Resource resource = Resource::style("http://example.com/"s + util::toString(i));
+ db.put(resource, response);
+ EXPECT_TRUE(bool(db.get(resource))) << i;
+ }
+
+ EXPECT_FALSE(bool(db.get(Resource::style("http://example.com/1"))));
+}
+
+TEST(OfflineDatabase, PutRegionResourceDoesNotEvict) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:", 1024 * 25);
+ OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 };
+ OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata());
+
+ Response response;
+ response.data = randomString(1024);
+
+ for (uint32_t i = 1; i <= 20; i++) {
+ db.putRegionResource(region.getID(), Resource::style("http://example.com/"s + util::toString(i)), response);
+ }
+
+ EXPECT_TRUE(bool(db.get(Resource::style("http://example.com/1"))));
+ EXPECT_TRUE(bool(db.get(Resource::style("http://example.com/20"))));
+}
+
+TEST(OfflineDatabase, PutFailsWhenEvictionInsuffices) {
+ using namespace mbgl;
+
+ Log::setObserver(std::make_unique<FixtureLogObserver>());
+ OfflineDatabase db(":memory:", 1024 * 25);
+
+ Response small;
+ small.data = randomString(1024);
+
+ for (uint32_t i = 1; i <= 10; i++) {
+ db.put(Resource::style("http://example.com/"s + util::toString(i)), small);
+ }
+
+ Response big;
+ big.data = randomString(1024 * 15);
+ db.put(Resource::style("http://example.com/big"), big);
+ EXPECT_FALSE(bool(db.get(Resource::style("http://example.com/big"))));
+
+ auto observer = Log::removeObserver();
+ auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
+ EXPECT_EQ(1ul, flo->count({ EventSeverity::Warning, Event::Database, -1, "Unable to make space for entry" }));
+}
diff --git a/test/storage/offline_download.cpp b/test/storage/offline_download.cpp
new file mode 100644
index 0000000000..6de14d37b2
--- /dev/null
+++ b/test/storage/offline_download.cpp
@@ -0,0 +1,334 @@
+#include "../fixtures/stub_file_source.hpp"
+
+#include <mbgl/storage/offline.hpp>
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/offline_download.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/compression.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <gtest/gtest.h>
+#include <iostream>
+
+using namespace mbgl;
+using namespace std::literals::string_literals;
+
+class MockObserver : public OfflineRegionObserver {
+public:
+ void statusChanged(OfflineRegionStatus status) override {
+ if (statusChangedFn) statusChangedFn(status);
+ }
+
+ void responseError(Response::Error error) override {
+ if (responseErrorFn) responseErrorFn(error);
+ }
+
+ std::function<void (OfflineRegionStatus)> statusChangedFn;
+ std::function<void (Response::Error)> responseErrorFn;
+};
+
+class OfflineTest {
+public:
+ util::RunLoop loop;
+ StubFileSource fileSource;
+ OfflineDatabase db { ":memory:" };
+ std::size_t size = 0;
+
+ Response response(const std::string& path) {
+ Response result;
+ result.data = std::make_shared<std::string>(util::read_file("test/fixtures/"s + path));
+ size_t uncompressed = result.data->size();
+ size_t compressed = util::compress(*result.data).size();
+ size += std::min(uncompressed, compressed);
+ return result;
+ }
+};
+
+TEST(OfflineDownload, NoSubresources) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/style.json", resource.url);
+ return test.response("offline/empty.style.json");
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->statusChangedFn = [&] (OfflineRegionStatus status) {
+ if (status.complete()) {
+ EXPECT_EQ(1, status.completedResourceCount);
+ EXPECT_EQ(test.size, status.completedResourceSize);
+ EXPECT_FALSE(status.requiredResourceCountIsIndeterminate);
+ test.loop.stop();
+ }
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
+
+TEST(OfflineDownload, InlineSource) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/style.json", resource.url);
+ return test.response("offline/inline_source.style.json");
+ };
+
+ test.fileSource.tileResponse = [&] (const Resource& resource) {
+ const Resource::TileData& tile = *resource.tileData;
+ EXPECT_EQ("http://127.0.0.1:3000/offline/{z}-{x}-{y}.vector.pbf", tile.urlTemplate);
+ EXPECT_EQ(1, tile.pixelRatio);
+ EXPECT_EQ(0, tile.x);
+ EXPECT_EQ(0, tile.y);
+ EXPECT_EQ(0, tile.z);
+ return test.response("offline/0-0-0.vector.pbf");
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->statusChangedFn = [&] (OfflineRegionStatus status) {
+ if (status.complete()) {
+ EXPECT_EQ(2, status.completedResourceCount);
+ EXPECT_EQ(test.size, status.completedResourceSize);
+ EXPECT_FALSE(status.requiredResourceCountIsIndeterminate);
+ test.loop.stop();
+ }
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
+
+TEST(OfflineDownload, GeoJSONSource) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/style.json", resource.url);
+ return test.response("offline/geojson_source.style.json");
+ };
+
+ test.fileSource.sourceResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/geojson.json", resource.url);
+ return test.response("offline/geojson.json");
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->statusChangedFn = [&] (OfflineRegionStatus status) {
+ if (status.complete()) {
+ EXPECT_EQ(2, status.completedResourceCount);
+ EXPECT_EQ(test.size, status.completedResourceSize);
+ EXPECT_FALSE(status.requiredResourceCountIsIndeterminate);
+ test.loop.stop();
+ }
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
+
+TEST(OfflineDownload, Activate) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/style.json", resource.url);
+ return test.response("offline/style.json");
+ };
+
+ test.fileSource.spriteImageResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/sprite.png", resource.url);
+ return test.response("offline/sprite.png");
+ };
+
+ test.fileSource.spriteJSONResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/sprite.json", resource.url);
+ return test.response("offline/sprite.json");
+ };
+
+ test.fileSource.glyphsResponse = [&] (const Resource&) {
+ return test.response("offline/glyph.pbf");
+ };
+
+ test.fileSource.sourceResponse = [&] (const Resource& resource) {
+ EXPECT_EQ("http://127.0.0.1:3000/offline/streets.json", resource.url);
+ return test.response("offline/streets.json");
+ };
+
+ test.fileSource.tileResponse = [&] (const Resource& resource) {
+ const Resource::TileData& tile = *resource.tileData;
+ EXPECT_EQ("http://127.0.0.1:3000/offline/{z}-{x}-{y}.vector.pbf", tile.urlTemplate);
+ EXPECT_EQ(1, tile.pixelRatio);
+ EXPECT_EQ(0, tile.x);
+ EXPECT_EQ(0, tile.y);
+ EXPECT_EQ(0, tile.z);
+ return test.response("offline/0-0-0.vector.pbf");
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->statusChangedFn = [&] (OfflineRegionStatus status) {
+ if (status.complete()) {
+ EXPECT_EQ(261, status.completedResourceCount); // 256 glyphs, 1 tile, 1 style, source, sprite image, and sprite json
+ EXPECT_EQ(test.size, status.completedResourceSize);
+
+ download.setState(OfflineRegionDownloadState::Inactive);
+ OfflineRegionStatus computedStatus = download.getStatus();
+ EXPECT_EQ(status.requiredResourceCount, computedStatus.requiredResourceCount);
+ EXPECT_EQ(status.completedResourceCount, computedStatus.completedResourceCount);
+ EXPECT_EQ(status.completedResourceSize, computedStatus.completedResourceSize);
+ EXPECT_FALSE(status.requiredResourceCountIsIndeterminate);
+
+ test.loop.stop();
+ }
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
+
+TEST(OfflineDownload, GetStatusNoResources) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+ OfflineRegionStatus status = download.getStatus();
+
+ EXPECT_EQ(OfflineRegionDownloadState::Inactive, status.downloadState);
+ EXPECT_EQ(0, status.completedResourceCount);
+ EXPECT_EQ(0, status.completedResourceSize);
+ EXPECT_EQ(1, status.requiredResourceCount);
+ EXPECT_TRUE(status.requiredResourceCountIsIndeterminate);
+ EXPECT_FALSE(status.complete());
+}
+
+TEST(OfflineDownload, GetStatusStyleComplete) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.db.putRegionResource(1,
+ Resource::style("http://127.0.0.1:3000/offline/style.json"),
+ test.response("offline/style.json"));
+
+ OfflineRegionStatus status = download.getStatus();
+
+ EXPECT_EQ(OfflineRegionDownloadState::Inactive, status.downloadState);
+ EXPECT_EQ(1, status.completedResourceCount);
+ EXPECT_EQ(test.size, status.completedResourceSize);
+ EXPECT_EQ(260, status.requiredResourceCount);
+ EXPECT_TRUE(status.requiredResourceCountIsIndeterminate);
+ EXPECT_FALSE(status.complete());
+}
+
+TEST(OfflineDownload, GetStatusStyleAndSourceComplete) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.db.putRegionResource(1,
+ Resource::style("http://127.0.0.1:3000/offline/style.json"),
+ test.response("offline/style.json"));
+
+ test.db.putRegionResource(1,
+ Resource::source("http://127.0.0.1:3000/offline/streets.json"),
+ test.response("offline/streets.json"));
+
+ OfflineRegionStatus status = download.getStatus();
+
+ EXPECT_EQ(OfflineRegionDownloadState::Inactive, status.downloadState);
+ EXPECT_EQ(2, status.completedResourceCount);
+ EXPECT_EQ(test.size, status.completedResourceSize);
+ EXPECT_EQ(261, status.requiredResourceCount);
+ EXPECT_FALSE(status.requiredResourceCountIsIndeterminate);
+ EXPECT_FALSE(status.complete());
+}
+
+TEST(OfflineDownload, RequestError) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource&) {
+ Response response;
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::Connection, "connection error");
+ return response;
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->responseErrorFn = [&] (Response::Error error) {
+ EXPECT_EQ(Response::Error::Reason::Connection, error.reason);
+ EXPECT_EQ("connection error", error.message);
+ test.loop.stop();
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
+
+TEST(OfflineDownload, RequestErrorsAreRetried) {
+ OfflineTest test;
+ OfflineDownload download(
+ 1,
+ OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/offline/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0),
+ test.db, test.fileSource);
+
+ test.fileSource.styleResponse = [&] (const Resource&) {
+ test.fileSource.styleResponse = [&] (const Resource&) {
+ return test.response("offline/empty.style.json");
+ };
+
+ Response response;
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::Connection, "connection error");
+ return response;
+ };
+
+ auto observer = std::make_unique<MockObserver>();
+
+ observer->statusChangedFn = [&] (OfflineRegionStatus status) {
+ if (status.complete()) {
+ EXPECT_EQ(1, status.completedResourceCount);
+ test.loop.stop();
+ }
+ };
+
+ download.setObserver(std::move(observer));
+ download.setState(OfflineRegionDownloadState::Active);
+
+ test.loop.run();
+}
diff --git a/test/storage/resource.cpp b/test/storage/resource.cpp
index 30c1597df2..0b04c1b3e4 100644
--- a/test/storage/resource.cpp
+++ b/test/storage/resource.cpp
@@ -18,14 +18,24 @@ TEST(Resource, Source) {
TEST(Resource, Tile) {
using namespace mbgl;
- Resource resource = Resource::tile("http://example.com/{z}/{x}/{y}{ratio}.png", 2.0, 1, 2, 3);
- EXPECT_EQ(Resource::Kind::Tile, resource.kind);
- EXPECT_EQ("http://example.com/3/1/2@2x.png", resource.url);
- EXPECT_EQ("http://example.com/{z}/{x}/{y}{ratio}.png", resource.tileData->urlTemplate);
- EXPECT_EQ(2.0, resource.tileData->pixelRatio);
- EXPECT_EQ(1, resource.tileData->x);
- EXPECT_EQ(2, resource.tileData->y);
- EXPECT_EQ(3, resource.tileData->z);
+
+ Resource rasterTile = Resource::tile("http://example.com/{z}/{x}/{y}{ratio}.png", 2.0, 1, 2, 3);
+ EXPECT_EQ(Resource::Kind::Tile, rasterTile.kind);
+ EXPECT_EQ("http://example.com/3/1/2@2x.png", rasterTile.url);
+ EXPECT_EQ("http://example.com/{z}/{x}/{y}{ratio}.png", rasterTile.tileData->urlTemplate);
+ EXPECT_EQ(2, rasterTile.tileData->pixelRatio);
+ EXPECT_EQ(1, rasterTile.tileData->x);
+ EXPECT_EQ(2, rasterTile.tileData->y);
+ EXPECT_EQ(3, rasterTile.tileData->z);
+
+ Resource vectorTile = Resource::tile("http://example.com/{z}/{x}/{y}.mvt", 2.0, 1, 2, 3);
+ EXPECT_EQ(Resource::Kind::Tile, vectorTile.kind);
+ EXPECT_EQ("http://example.com/3/1/2.mvt", vectorTile.url);
+ EXPECT_EQ("http://example.com/{z}/{x}/{y}.mvt", vectorTile.tileData->urlTemplate);
+ EXPECT_EQ(1, vectorTile.tileData->pixelRatio);
+ EXPECT_EQ(1, vectorTile.tileData->x);
+ EXPECT_EQ(2, vectorTile.tileData->y);
+ EXPECT_EQ(3, vectorTile.tileData->z);
}
TEST(Resource, Glyphs) {
diff --git a/test/storage/server.js b/test/storage/server.js
index 0024330037..d15544a0fd 100755
--- a/test/storage/server.js
+++ b/test/storage/server.js
@@ -84,6 +84,14 @@ app.get('/revalidate-etag', function(req, res) {
revalidateEtagCounter++;
});
+app.get('/empty-data', function(req, res) {
+ res.status(200).send();
+});
+
+app.get('/no-content', function(req, res) {
+ res.status(204).send();
+});
+
app.get('/not-found', function(req, res) {
res.status(404).send('Not Found!');
});
diff --git a/test/storage/storage.hpp b/test/storage/storage.hpp
index a4bb1bfbb7..3dc13d0d9f 100644
--- a/test/storage/storage.hpp
+++ b/test/storage/storage.hpp
@@ -3,7 +3,6 @@
#include "../fixtures/util.hpp"
#include <mbgl/storage/response.hpp>
-#include <iostream>
#include <memory>
class Storage : public testing::Test {
@@ -15,20 +14,4 @@ protected:
static std::unique_ptr<mbgl::test::Server> server;
};
-namespace mbgl {
-
-inline std::ostream& operator<<(std::ostream& os, Response::Error::Reason r) {
- // Special case
- if (uint8_t(r) == 1) return os << "Response::Error::Reason::Success";
- switch (r) {
- case Response::Error::Reason::NotFound: return os << "Response::Error::Reason::NotFound";
- case Response::Error::Reason::Server: return os << "Response::Error::Reason::Server";
- case Response::Error::Reason::Connection: return os << "Response::Error::Reason::Connection";
- case Response::Error::Reason::Other: return os << "Response::Error::Reason::Other";
- default: return os << "<Unknown>";
- }
-}
-
-} // namespace mbgl
-
#endif
diff --git a/test/style/comparisons.cpp b/test/style/comparisons.cpp
index dc2d74bf11..88f2645be8 100644
--- a/test/style/comparisons.cpp
+++ b/test/style/comparisons.cpp
@@ -1,7 +1,7 @@
#include <iostream>
#include "../fixtures/util.hpp"
-#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/filter_expression_private.hpp>
diff --git a/test/style/glyph_store.cpp b/test/style/glyph_store.cpp
index 55f19672af..ff88841450 100644
--- a/test/style/glyph_store.cpp
+++ b/test/style/glyph_store.cpp
@@ -17,14 +17,13 @@ public:
util::RunLoop loop;
StubFileSource fileSource;
StubStyleObserver observer;
- GlyphStore glyphStore;
+ GlyphStore glyphStore { fileSource };
void run(const std::string& url, const std::string& fontStack, const std::set<GlyphRange>& glyphRanges) {
// Squelch logging.
Log::setObserver(std::make_unique<Log::NullObserver>());
util::ThreadContext::Set(&context);
- util::ThreadContext::setFileSource(&fileSource);
glyphStore.setObserver(&observer);
glyphStore.setURL(url);
diff --git a/test/style/source.cpp b/test/style/source.cpp
index 528059ae9f..bbe37fcf05 100644
--- a/test/style/source.cpp
+++ b/test/style/source.cpp
@@ -3,7 +3,7 @@
#include "../fixtures/mock_view.hpp"
#include "../fixtures/stub_style_observer.hpp"
-#include <mbgl/map/source.hpp>
+#include <mbgl/source/source.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/io.hpp>
@@ -12,7 +12,7 @@
#include <mbgl/map/transform.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/util/worker.hpp>
-#include <mbgl/util/texture_pool.hpp>
+#include <mbgl/gl/texture_pool.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_update_parameters.hpp>
#include <mbgl/layer/line_layer.hpp>
@@ -29,9 +29,9 @@ public:
Transform transform { view, ConstrainMode::HeightOnly };
TransformState transformState;
Worker worker { 1 };
- TexturePool texturePool;
+ gl::TexturePool texturePool;
MapData mapData { MapMode::Still, GLContextMode::Unique, 1.0 };
- Style style { mapData };
+ Style style { mapData, fileSource };
StyleUpdateParameters updateParameters {
1.0,
@@ -39,6 +39,7 @@ public:
TimePoint(),
transformState,
worker,
+ fileSource,
texturePool,
true,
MapMode::Continuous,
@@ -51,7 +52,6 @@ public:
Log::setObserver(std::make_unique<Log::NullObserver>());
util::ThreadContext::Set(&context);
- util::ThreadContext::setFileSource(&fileSource);
transform.resize({{ 512, 512 }});
transform.setLatLngZoom({0, 0}, 0);
@@ -88,7 +88,7 @@ TEST(Source, LoadingFail) {
Source source(SourceType::Vector, "source", "url", 512, nullptr, nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
test.run();
}
@@ -111,7 +111,65 @@ TEST(Source, LoadingCorrupt) {
Source source(SourceType::Vector, "source", "url", 512, nullptr, nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
+
+ test.run();
+}
+
+TEST(Source, RasterTileEmpty) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.noContent = true;
+ return response;
+ };
+
+ test.observer.tileLoaded = [&] (Source& source, const TileID&, bool) {
+ EXPECT_EQ("source", source.id);
+ test.end();
+ };
+
+ test.observer.tileError = [&] (Source&, const TileID&, std::exception_ptr) {
+ FAIL() << "Should never be called";
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load(test.fileSource);
+ source.update(test.updateParameters);
+
+ test.run();
+}
+
+TEST(Source, VectorTileEmpty) {
+ SourceTest test;
+
+ test.fileSource.tileResponse = [&] (const Resource&) {
+ Response response;
+ response.noContent = true;
+ return response;
+ };
+
+ test.observer.tileLoaded = [&] (Source& source, const TileID&, bool) {
+ EXPECT_EQ("source", source.id);
+ test.end();
+ };
+
+ test.observer.tileError = [&] (Source&, const TileID&, std::exception_ptr) {
+ FAIL() << "Should never be called";
+ };
+
+ auto info = std::make_unique<SourceInfo>();
+ info->tiles = { "tiles" };
+
+ Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
+ source.setObserver(&test.observer);
+ source.load(test.fileSource);
+ source.update(test.updateParameters);
test.run();
}
@@ -139,7 +197,7 @@ TEST(Source, RasterTileFail) {
Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
@@ -168,7 +226,7 @@ TEST(Source, VectorTileFail) {
Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
@@ -196,7 +254,7 @@ TEST(Source, RasterTileCorrupt) {
Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
@@ -229,7 +287,7 @@ TEST(Source, VectorTileCorrupt) {
Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
@@ -256,7 +314,7 @@ TEST(Source, RasterTileCancel) {
Source source(SourceType::Raster, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
@@ -283,7 +341,7 @@ TEST(Source, VectorTileCancel) {
Source source(SourceType::Vector, "source", "", 512, std::move(info), nullptr);
source.setObserver(&test.observer);
- source.load();
+ source.load(test.fileSource);
source.update(test.updateParameters);
test.run();
diff --git a/test/style/style.cpp b/test/style/style.cpp
index 59366ea7dd..b4211cb071 100644
--- a/test/style/style.cpp
+++ b/test/style/style.cpp
@@ -1,4 +1,5 @@
#include "../fixtures/util.hpp"
+#include "../fixtures/stub_file_source.hpp"
#include <mbgl/map/map_data.hpp>
#include <mbgl/style/style.hpp>
@@ -7,11 +8,13 @@
using namespace mbgl;
TEST(Style, UnusedSource) {
+ util::RunLoop loop;
util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
util::ThreadContext::Set(&context);
MapData data { MapMode::Still, GLContextMode::Unique, 1.0 };
- Style style { data };
+ StubFileSource fileSource;
+ Style style { data, fileSource };
style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"), "");
style.cascade();
@@ -27,11 +30,13 @@ TEST(Style, UnusedSource) {
}
TEST(Style, UnusedSourceActiveViaClassUpdate) {
+ util::RunLoop loop;
util::ThreadContext context { "Map", util::ThreadType::Map, util::ThreadPriority::Regular };
util::ThreadContext::Set(&context);
MapData data { MapMode::Still, GLContextMode::Unique, 1.0 };
- Style style { data };
+ StubFileSource fileSource;
+ Style style { data, fileSource };
data.addClass("visible");
diff --git a/test/style/style_parser.cpp b/test/style/style_parser.cpp
index 22b5acb12b..64ee4af9fc 100644
--- a/test/style/style_parser.cpp
+++ b/test/style/style_parser.cpp
@@ -90,15 +90,16 @@ TEST(StyleParser, ParseTileJSONRaster) {
auto result = StyleParser::parseTileJSON(
util::read_file("test/fixtures/style_parser/tilejson.raster.json"),
"mapbox://mapbox.satellite",
- SourceType::Raster);
+ SourceType::Raster,
+ 256);
EXPECT_EQ(0, result->minZoom);
EXPECT_EQ(15, result->maxZoom);
EXPECT_EQ("attribution", result->attribution);
#if !defined(__ANDROID__) && !defined(__APPLE__)
- EXPECT_EQ("http://a.tiles.mapbox.com/mapbox.satellite/{z}-{x}-{y}{ratio}.webp?access_token=key", result->tiles[0]);
+ EXPECT_EQ("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.webp", result->tiles[0]);
#else
- EXPECT_EQ("http://a.tiles.mapbox.com/mapbox.satellite/{z}-{x}-{y}{ratio}.png?access_token=key", result->tiles[0]);
+ EXPECT_EQ("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", result->tiles[0]);
#endif
}
@@ -106,10 +107,21 @@ TEST(StyleParser, ParseTileJSONVector) {
auto result = StyleParser::parseTileJSON(
util::read_file("test/fixtures/style_parser/tilejson.vector.json"),
"mapbox://mapbox.streets",
- SourceType::Vector);
+ SourceType::Vector,
+ 256);
EXPECT_EQ(0, result->minZoom);
EXPECT_EQ(15, result->maxZoom);
EXPECT_EQ("attribution", result->attribution);
- EXPECT_EQ("http://a.tiles.mapbox.com/mapbox.streets/{z}-{x}-{y}.vector.pbf?access_token=key", result->tiles[0]);
+ EXPECT_EQ("mapbox://tiles/mapbox.streets/{z}/{x}/{y}.vector.pbf", result->tiles[0]);
+}
+
+TEST(StyleParser, FontStacks) {
+ StyleParser parser;
+ parser.parse(util::read_file("test/fixtures/style_parser/font_stacks.json"));
+ auto result = parser.fontStacks();
+ ASSERT_EQ(3, result.size());
+ ASSERT_EQ("a", result[0]);
+ ASSERT_EQ("a,b", result[1]);
+ ASSERT_EQ("a,b,c", result[2]);
}
diff --git a/test/test.gypi b/test/test.gypi
index 34c9d8dd56..32b686a80d 100644
--- a/test/test.gypi
+++ b/test/test.gypi
@@ -47,6 +47,7 @@
'util/text_conversions.cpp',
'util/thread.cpp',
'util/thread_local.cpp',
+ 'util/tile_cover.cpp',
'util/timer.cpp',
'util/token.cpp',
'util/work_queue.cpp',
@@ -57,6 +58,7 @@
'api/render_missing.cpp',
'api/set_style.cpp',
'api/custom_layer.cpp',
+ 'api/offline.cpp',
'geometry/binpack.cpp',
@@ -67,12 +69,10 @@
'storage/storage.hpp',
'storage/storage.cpp',
- 'storage/cache_response.cpp',
- 'storage/cache_revalidate.cpp',
- 'storage/cache_shared.cpp',
- 'storage/cache_size.cpp',
- 'storage/cache_stale.cpp',
- 'storage/database.cpp',
+ 'storage/default_file_source.cpp',
+ 'storage/offline.cpp',
+ 'storage/offline_database.cpp',
+ 'storage/offline_download.cpp',
'storage/asset_file_source.cpp',
'storage/headers.cpp',
'storage/http_cancel.cpp',
@@ -100,11 +100,6 @@
'sprite/sprite_parser.cpp',
'sprite/sprite_store.cpp',
],
- 'libraries': [
- '<@(gtest_static_libs)',
- '<@(sqlite_static_libs)',
- '<@(geojsonvt_static_libs)',
- ],
'variables': {
'cflags_cc': [
'<@(gtest_cflags)',
@@ -114,23 +109,37 @@
'<@(geojsonvt_cflags)',
'<@(rapidjson_cflags)',
'<@(pixelmatch_cflags)',
+ '<@(variant_cflags)',
],
'ldflags': [
'<@(gtest_ldflags)',
'<@(sqlite_ldflags)',
],
+ 'libraries': [
+ '<@(gtest_static_libs)',
+ '<@(sqlite_static_libs)',
+ '<@(geojsonvt_static_libs)',
+ ],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
- 'OTHER_LDFLAGS': [ '<@(ldflags)' ],
},
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
- 'libraries': [ '<@(ldflags)' ],
}],
],
+ 'link_settings': {
+ 'conditions': [
+ ['OS == "mac"', {
+ 'libraries': [ '<@(libraries)' ],
+ 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
+ }, {
+ 'libraries': [ '<@(libraries)', '<@(ldflags)' ],
+ }]
+ ],
+ },
},
]
}
diff --git a/test/util/clip_ids.cpp b/test/util/clip_ids.cpp
index 4ecd1797e6..fb7616d8ff 100644
--- a/test/util/clip_ids.cpp
+++ b/test/util/clip_ids.cpp
@@ -4,13 +4,13 @@
#include <algorithm>
#include <mbgl/util/clip_id.hpp>
-#include <mbgl/map/tile.hpp>
+#include <mbgl/tile/tile.hpp>
using namespace mbgl;
-template <typename T> void generate(const T &sources) {
- ClipIDGenerator generator;
+using Stencil = std::pair<const TileID, ClipID>;
+template <typename T> void generate(ClipIDGenerator& generator, const T &sources) {
for (size_t j = 0; j < sources.size(); j++) {
std::forward_list<Tile *> tile_ptrs;
std::transform(sources[j].begin(), sources[j].end(), std::front_inserter(tile_ptrs), [](const std::shared_ptr<Tile> &tile) { return tile.get(); });
@@ -18,7 +18,7 @@ template <typename T> void generate(const T &sources) {
}
}
-template <typename T> void print(const T &sources) {
+void print(const std::vector<std::vector<std::shared_ptr<Tile>>> &sources) {
for (size_t j = 0; j < sources.size(); j++) {
for (size_t i = 0; i < sources[j].size(); i++) {
std::cout << " ASSERT_EQ(ClipID(\"" << sources[j][i]->clip.mask << "\", \"" << sources[j][i]->clip.reference << "\"), sources[" << j << "][" << i << "]->clip);\n";
@@ -26,6 +26,18 @@ template <typename T> void print(const T &sources) {
}
}
+void print(const std::map<TileID, ClipID>& stencils) {
+ std::cout << " auto it = stencils.begin();\n";
+ std::cout << " ASSERT_EQ(" << stencils.size() << ", stencils.size());\n";
+ for (auto& stencil : stencils) {
+ std::cout << " ASSERT_EQ(Stencil(TileID{ " << (int)stencil.first.z << ", "
+ << stencil.first.x << ", " << stencil.first.y << ", "
+ << (int)stencil.first.sourceZ << " }, { \"" << stencil.second.mask.to_string()
+ << "\", \"" << stencil.second.reference.to_string() << "\"}), *it++);\n";
+ }
+ std::cout << " ASSERT_EQ(stencils.end(), it);\n";
+}
+
TEST(ClipIDs, ParentAndFourChildren) {
const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
@@ -37,7 +49,8 @@ TEST(ClipIDs, ParentAndFourChildren) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][0]->clip);
@@ -45,6 +58,18 @@ TEST(ClipIDs, ParentAndFourChildren) {
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][4]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(4, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "00000111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 0, 1, 1 }, { "00000111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 1, 0, 1 }, { "00000111", "00000100"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 1, 1, 1 }, { "00000111", "00000101"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
+
}
TEST(ClipIDs, ParentAndFourChildrenNegative) {
@@ -58,7 +83,8 @@ TEST(ClipIDs, ParentAndFourChildrenNegative) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][0]->clip);
@@ -66,6 +92,17 @@ TEST(ClipIDs, ParentAndFourChildrenNegative) {
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][4]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(4, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 1, -2, 0, 1 }, { "00000111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, -2, 1, 1 }, { "00000111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, -1, 0, 1 }, { "00000111", "00000100"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, -1, 1, 1 }, { "00000111", "00000101"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, NegativeParentAndMissingLevel) {
@@ -79,7 +116,8 @@ TEST(ClipIDs, NegativeParentAndMissingLevel) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
@@ -87,6 +125,17 @@ TEST(ClipIDs, NegativeParentAndMissingLevel) {
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][3]->clip);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][4]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(4, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 2, -2, 0, 2 }, { "00000111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, -2, 1, 2 }, { "00000111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, -1, 0, 2 }, { "00000111", "00000100"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, -1, 1, 2 }, { "00000111", "00000101"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
@@ -103,7 +152,8 @@ TEST(ClipIDs, SevenOnSameLevel) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
@@ -113,6 +163,20 @@ TEST(ClipIDs, SevenOnSameLevel) {
ASSERT_EQ(ClipID("00000111", "00000101"), sources[0][4]->clip);
ASSERT_EQ(ClipID("00000111", "00000110"), sources[0][5]->clip);
ASSERT_EQ(ClipID("00000111", "00000111"), sources[0][6]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(7, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 2, 0, 0, 2 }, { "00000111", "00000001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 0, 1, 2 }, { "00000111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 0, 2, 2 }, { "00000111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 1, 0, 2 }, { "00000111", "00000100"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 1, 1, 2 }, { "00000111", "00000101"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 1, 2, 2 }, { "00000111", "00000110"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 2, 0, 2 }, { "00000111", "00000111"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, MultipleLevels) {
@@ -133,7 +197,8 @@ TEST(ClipIDs, MultipleLevels) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00001111", "00000001"), sources[0][0]->clip);
@@ -148,6 +213,23 @@ TEST(ClipIDs, MultipleLevels) {
ASSERT_EQ(ClipID("00001111", "00000010"), sources[0][9]->clip);
ASSERT_EQ(ClipID("00001111", "00000111"), sources[0][10]->clip);
ASSERT_EQ(ClipID("00001111", "00001000"), sources[0][11]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(10, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 2, 1, 0, 2 }, { "00001111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 3, 0, 0, 3 }, { "00001111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 3, 1, 0, 3 }, { "00001111", "00000101"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 3, 1, 1, 3 }, { "00001111", "00000110"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 3, 2, 0, 3 }, { "00001111", "00000111"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 3, 2, 1, 3 }, { "00001111", "00001000"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 4, 0, 2, 4 }, { "00001111", "00001001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 4, 0, 3, 4 }, { "00001111", "00001010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 4, 1, 2, 4 }, { "00001111", "00001011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 4, 1, 3, 4 }, { "00001111", "00001100"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
@@ -157,18 +239,19 @@ TEST(ClipIDs, Bug206) {
std::make_shared<Tile>(TileID { 10, 162, 395, 10 }),
std::make_shared<Tile>(TileID { 10, 162, 396, 10 }),
std::make_shared<Tile>(TileID { 10, 163, 395, 10 }),
- std::make_shared<Tile>(TileID { 11, 326, 791, 10 }),
- std::make_shared<Tile>(TileID { 12, 654, 1582, 10 }),
- std::make_shared<Tile>(TileID { 12, 654, 1583, 10 }),
- std::make_shared<Tile>(TileID { 12, 655, 1582, 10 }),
- std::make_shared<Tile>(TileID { 12, 655, 1583, 10 }),
+ std::make_shared<Tile>(TileID { 11, 326, 791, 11 }),
+ std::make_shared<Tile>(TileID { 12, 654, 1582, 12 }),
+ std::make_shared<Tile>(TileID { 12, 654, 1583, 12 }),
+ std::make_shared<Tile>(TileID { 12, 655, 1582, 12 }),
+ std::make_shared<Tile>(TileID { 12, 655, 1583, 12 }),
std::make_shared<Tile>(TileID { 10, 163, 396, 10 }),
std::make_shared<Tile>(TileID { 10, 164, 395, 10 }),
std::make_shared<Tile>(TileID { 10, 164, 396, 10 }),
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00001111", "00000001"), sources[0][0]->clip);
@@ -182,6 +265,24 @@ TEST(ClipIDs, Bug206) {
ASSERT_EQ(ClipID("00001111", "00000100"), sources[0][8]->clip);
ASSERT_EQ(ClipID("00001111", "00000101"), sources[0][9]->clip);
ASSERT_EQ(ClipID("00001111", "00000110"), sources[0][10]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(11, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 10, 162, 395, 10 }, { "00001111", "00000001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 10, 162, 396, 10 }, { "00001111", "00000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 10, 163, 395, 10 }, { "00001111", "00000011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 10, 163, 396, 10 }, { "00001111", "00000100"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 10, 164, 395, 10 }, { "00001111", "00000101"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 10, 164, 396, 10 }, { "00001111", "00000110"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 11, 326, 791, 11 }, { "00001111", "00000111"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 12, 654, 1582, 12 }, { "00001111", "00001000"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 12, 654, 1583, 12 }, { "00001111", "00001001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 12, 655, 1582, 12 }, { "00001111", "00001010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 12, 655, 1583, 12 }, { "00001111", "00001011"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
@@ -208,27 +309,44 @@ TEST(ClipIDs, MultipleSources) {
},
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000111", "00000001"), sources[0][0]->clip);
ASSERT_EQ(ClipID("00000111", "00000010"), sources[0][1]->clip);
ASSERT_EQ(ClipID("00000111", "00000011"), sources[0][2]->clip);
ASSERT_EQ(ClipID("00000111", "00000100"), sources[0][3]->clip);
+
ASSERT_EQ(ClipID("00011000", "00001000"), sources[1][0]->clip);
- ASSERT_EQ(ClipID("00000111", "00000010"), sources[1][1]->clip);
+ ASSERT_EQ(ClipID("00011111", "00000010"), sources[1][1]->clip);
ASSERT_EQ(ClipID("00011000", "00010000"), sources[1][2]->clip);
- ASSERT_EQ(ClipID("00000111", "00000100"), sources[1][3]->clip);
+ ASSERT_EQ(ClipID("00011111", "00000100"), sources[1][3]->clip);
+
ASSERT_EQ(ClipID("11100000", "00100000"), sources[2][0]->clip);
ASSERT_EQ(ClipID("11100000", "01000000"), sources[2][1]->clip);
ASSERT_EQ(ClipID("11100000", "01100000"), sources[2][2]->clip);
ASSERT_EQ(ClipID("11100000", "10000000"), sources[2][3]->clip);
- ASSERT_EQ(ClipID("00011000", "00010000"), sources[2][4]->clip);
+ ASSERT_EQ(ClipID("11111000", "00010000"), sources[2][4]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(7, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "11111111", "00101001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 0, 1, 1 }, { "11111111", "01001001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 1, 0, 1 }, { "11111111", "01101001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 1, 1, 1 }, { "11111111", "10000010"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 1, 1, 2 }, { "11111111", "00010001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 2, 1, 2 }, { "11111111", "01101011"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 2, 2, 2 }, { "11111111", "10000100"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
TEST(ClipIDs, DuplicateIDs) {
- const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
+ const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
{
std::make_shared<Tile>(TileID { 2, 0, 0, 2 }),
std::make_shared<Tile>(TileID { 2, 0, 1, 2 }),
@@ -240,7 +358,8 @@ TEST(ClipIDs, DuplicateIDs) {
}
};
- generate(sources);
+ ClipIDGenerator generator;
+ generate(generator, sources);
// print(sources);
ASSERT_EQ(ClipID("00000011", "00000001"), sources[0][0]->clip);
@@ -248,4 +367,45 @@ TEST(ClipIDs, DuplicateIDs) {
ASSERT_EQ(ClipID("00000011", "00000001"), sources[1][0]->clip);
ASSERT_EQ(ClipID("00000011", "00000010"), sources[1][1]->clip);
ASSERT_EQ(ClipID("00000011", "00000010"), sources[1][2]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(2, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 2, 0, 0, 2 }, { "00000011", "00000001"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 2, 0, 1, 2 }, { "00000011", "00000010"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
+}
+
+TEST(ClipIDs, SecondSourceHasParentOfFirstSource) {
+ const std::vector<std::vector<std::shared_ptr<Tile>>> sources = {
+ {
+ std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
+ },
+ {
+ std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
+ std::make_shared<Tile>(TileID { 1, 0, 0, 1 }),
+ },
+ {
+ std::make_shared<Tile>(TileID { 0, 0, 0, 0 }),
+ }
+ };
+
+ ClipIDGenerator generator;
+ generate(generator, sources);
+ // print(sources);
+
+ ASSERT_EQ(ClipID("00000001", "00000001"), sources[0][0]->clip);
+ ASSERT_EQ(ClipID("00000010", "00000010"), sources[1][0]->clip);
+ ASSERT_EQ(ClipID("00000011", "00000001"), sources[1][1]->clip);
+
+ const auto stencils = generator.getStencils();
+ // print(stencils);
+
+ auto it = stencils.begin();
+ ASSERT_EQ(2, stencils.size());
+ ASSERT_EQ(Stencil(TileID{ 0, 0, 0, 0 }, { "00000110", "00000110"}), *it++);
+ ASSERT_EQ(Stencil(TileID{ 1, 0, 0, 1 }, { "00000111", "00000101"}), *it++);
+ ASSERT_EQ(stencils.end(), it);
}
diff --git a/test/util/mapbox.cpp b/test/util/mapbox.cpp
index d6f9948e66..4fc22d3b34 100644
--- a/test/util/mapbox.cpp
+++ b/test/util/mapbox.cpp
@@ -7,6 +7,8 @@
using namespace mbgl;
+// TODO: correct all EXPECT_EQ(actual, expected) to EXPECT_EQ(expected, actual)
+
TEST(Mapbox, SourceURL) {
EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "key"), "https://api.mapbox.com/v4/user.map.json?access_token=key&secure");
EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "token"), "https://api.mapbox.com/v4/user.map.json?access_token=token&secure");
@@ -36,110 +38,94 @@ TEST(Mapbox, SpriteURL) {
}
TEST(Mapbox, TileURL) {
- try {
-#if defined(__ANDROID__) || defined(__APPLE__)
- EXPECT_EQ("http://path.png/tile{ratio}.png", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png"));
- EXPECT_EQ("http://path.png/tile{ratio}.png32", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png32"));
- EXPECT_EQ("http://path.png/tile{ratio}.png70", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png70"));
- EXPECT_EQ("http://path.png/tile{ratio}.png?access_token=foo", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png?access_token=foo"));
-#else
- EXPECT_EQ("http://path.png/tile{ratio}.webp", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png"));
- EXPECT_EQ("http://path.png/tile{ratio}.webp32", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png32"));
- EXPECT_EQ("http://path.png/tile{ratio}.webp70", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png70"));
- EXPECT_EQ("http://path.png/tile{ratio}.webp?access_token=foo", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.png?access_token=foo"));
-#endif // defined(__ANDROID__) || defined(__APPLE__)
- EXPECT_EQ("http://path.png/tile{ratio}.pbf", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.pbf"));
- EXPECT_EQ("http://path.png/tile{ratio}.pbf?access_token=foo", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.pbf?access_token=foo"));
- EXPECT_EQ("http://path.png/tile{ratio}.pbf?access_token=foo.png", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.pbf?access_token=foo.png"));
- EXPECT_EQ("http://path.png/tile{ratio}.pbf?access_token=foo.png/bar", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.pbf?access_token=foo.png/bar"));
- EXPECT_EQ("http://path.png/tile{ratio}.pbf?access_token=foo.png/bar.png", mbgl::util::mapbox::normalizeRasterTileURL("http://path.png/tile.pbf?access_token=foo.png/bar.png"));
- } catch (const std::regex_error& e) {
- const char *error = "unknown";
- switch (e.code()) {
- case std::regex_constants::error_collate:
- error = "error_collate"; break;
- case std::regex_constants::error_ctype:
- error = "error_ctype"; break;
- case std::regex_constants::error_escape:
- error = "error_escape"; break;
- case std::regex_constants::error_backref:
- error = "error_backref"; break;
- case std::regex_constants::error_paren:
- error = "error_paren"; break;
- case std::regex_constants::error_brace:
- error = "error_brace"; break;
- case std::regex_constants::error_badbrace:
- error = "error_badbrace"; break;
- case std::regex_constants::error_range:
- error = "error_range"; break;
- case std::regex_constants::error_space:
- error = "error_space"; break;
- case std::regex_constants::error_badrepeat:
- error = "error_badrepeat"; break;
- case std::regex_constants::error_complexity:
- error = "error_complexity"; break;
- case std::regex_constants::error_stack:
- error = "error_stack"; break;
- default:
- break;
- }
- mbgl::Log::Error(mbgl::Event::General, "regex_error caught: %s - %s (%d)", e.what(), error, e.code());
- throw e;
- }
+ EXPECT_EQ(
+ "https://api.mapbox.com/v4/a.b/0/0/0.pbf?access_token=key",
+ mbgl::util::mapbox::normalizeTileURL("mapbox://tiles/a.b/0/0/0.pbf", "key"));
+ EXPECT_EQ(
+ "https://api.mapbox.com/v4/a.b/0/0/0.png?access_token=key",
+ mbgl::util::mapbox::normalizeTileURL("mapbox://tiles/a.b/0/0/0.png", "key"));
+ EXPECT_EQ(
+ "https://api.mapbox.com/v4/a.b/0/0/0@2x.webp?access_token=key",
+ mbgl::util::mapbox::normalizeTileURL("mapbox://tiles/a.b/0/0/0@2x.webp", "key"));
+ EXPECT_EQ(
+ "https://api.mapbox.com/v4/a.b,c.d/0/0/0.pbf?access_token=key",
+ mbgl::util::mapbox::normalizeTileURL("mapbox://tiles/a.b,c.d/0/0/0.pbf", "key"));
+ EXPECT_EQ(
+ "http://path",
+ mbgl::util::mapbox::normalizeSpriteURL("http://path", "key"));
}
TEST(Mapbox, CanonicalURL) {
- using mbgl::util::mapbox::canonicalURL;
EXPECT_EQ(
- canonicalURL("https://a.tiles.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
-
+ "mapbox://tiles/a.b/{z}/{x}/{y}.vector.pbf",
+ mbgl::util::mapbox::canonicalizeTileURL("http://a.tiles.mapbox.com/v4/a.b/{z}/{x}/{y}.vector.pbf", SourceType::Vector, 512));
EXPECT_EQ(
- canonicalURL("http://a.tiles.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
-
+ "mapbox://tiles/a.b/{z}/{x}/{y}.vector.pbf",
+ mbgl::util::mapbox::canonicalizeTileURL("http://b.tiles.mapbox.com/v4/a.b/{z}/{x}/{y}.vector.pbf", SourceType::Vector, 512));
EXPECT_EQ(
- canonicalURL("https://b.tiles.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
-
+ "mapbox://tiles/a.b/{z}/{x}/{y}.vector.pbf",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.vector.pbf", SourceType::Vector, 512));
EXPECT_EQ(
- canonicalURL("http://c.tiles.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
-
+ "mapbox://tiles/a.b/{z}/{x}/{y}.vector.pbf",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.vector.pbf?access_token=key", SourceType::Vector, 512));
EXPECT_EQ(
- canonicalURL("https://api.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
-
+ "mapbox://tiles/a.b,c.d/{z}/{x}/{y}.vector.pbf",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b,c.d/{z}/{x}/{y}.vector.pbf?access_token=key", SourceType::Vector, 512));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.jpg",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.jpg?access_token=key", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.jpg70",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.jpg70?access_token=key", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.jpg",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.jpg?access_token=key", SourceType::Raster, 512));
EXPECT_EQ(
- canonicalURL("http://api.mapbox.com/v4/"
- "mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/"
- "10744.vector.pbf"),
- "mapbox://v4/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6/15/17599/10744.vector.pbf");
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.jpg70",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.jpg70?access_token=key", SourceType::Raster, 512));
- EXPECT_EQ(canonicalURL("https://api.mapbox.com/fonts/v1/mapbox/"
- "DIN%20Offc%20Pro%20Italic%2cArial%20Unicode%20MS%20Regular/"
- "0-255.pbf?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://fonts/v1/mapbox/DIN%20Offc%20Pro%20Italic%2cArial%20Unicode%20MS%20Regular/"
- "0-255.pbf");
+#if defined(__ANDROID__) || defined(__APPLE__)
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.png",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.png",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png?access_token=key", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.png",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png", SourceType::Raster, 512));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.png",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png?access_token=key", SourceType::Raster, 512));
+#else
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.webp",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}{ratio}.webp",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png?access_token=key", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.webp",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png", SourceType::Raster, 512));
+ EXPECT_EQ(
+ "mapbox://tiles/a.b/{z}/{x}/{y}@2x.webp",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.png?access_token=key", SourceType::Raster, 512));
+#endif // defined(__ANDROID__) || defined(__APPLE__)
- EXPECT_EQ(canonicalURL("https://api.mapbox.com/styles/v1/mapbox/streets-v8/"
- "sprite.json?access_token=pk.kAeslEm93Sjf3mXk."
- "vbiF02XnvkPkzlFhGSn2iIm6De3Cxsk5tmips2tvkG8sF"),
- "mapbox://styles/v1/mapbox/streets-v8/sprite.json");
+ // We don't ever expect to see these inputs, but be safe anyway.
+ EXPECT_EQ(
+ "",
+ mbgl::util::mapbox::canonicalizeTileURL("", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "http://path",
+ mbgl::util::mapbox::canonicalizeTileURL("http://path", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "http://api.mapbox.com/v4/",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}.", SourceType::Raster, 256));
+ EXPECT_EQ(
+ "http://api.mapbox.com/v4/a.b/{z}/{x}/{y}/.",
+ mbgl::util::mapbox::canonicalizeTileURL("http://api.mapbox.com/v4/a.b/{z}/{x}/{y}/.", SourceType::Raster, 256));
}
diff --git a/test/util/run_loop.cpp b/test/util/run_loop.cpp
index f00f7248b5..b6e5acca09 100644
--- a/test/util/run_loop.cpp
+++ b/test/util/run_loop.cpp
@@ -29,47 +29,3 @@ TEST(RunLoop, MultipleStop) {
loop.run();
}
-
-TEST(RunLoop, UnrefShouldStop) {
- RunLoop loop(RunLoop::Type::New);
-
- Timer timer;
- timer.start(mbgl::Duration::zero(), mbgl::Duration::zero(), [&] {
- loop.unref();
- });
-
- loop.run();
-}
-
-TEST(RunLoop, RefUnref) {
- RunLoop loop(RunLoop::Type::New);
-
- Timer timer;
- auto zero = mbgl::Duration::zero();
-
- auto cb3 = [&] {
- loop.stop();
- };
-
- auto cb2 = [&] {
- loop.unref();
- loop.unref();
-
- loop.ref();
-
- timer.start(zero, zero, cb3);
- };
-
- auto cb1 = [&] {
- loop.ref();
- loop.ref();
-
- loop.unref();
-
- timer.start(zero, zero, cb2);
- };
-
- timer.start(zero, zero, cb1);
-
- loop.run();
-}
diff --git a/test/util/tile_cover.cpp b/test/util/tile_cover.cpp
new file mode 100644
index 0000000000..d003653fd8
--- /dev/null
+++ b/test/util/tile_cover.cpp
@@ -0,0 +1,118 @@
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/map/tile_id.hpp>
+
+#include <gtest/gtest.h>
+
+#include <unordered_set>
+
+using namespace mbgl;
+using set = std::unordered_set<TileID>;
+
+TEST(TileCover, Empty) {
+ auto result = tileCover(LatLngBounds::empty(), 0, 0);
+ ASSERT_TRUE(result.empty());
+}
+
+TEST(TileCover, Arctic) {
+ auto result = tileCover(LatLngBounds::hull({ 86, -180 }, { 90, 180 }), 0, 0);
+ ASSERT_TRUE(result.empty());
+}
+
+TEST(TileCover, Antarctic) {
+ auto result = tileCover(LatLngBounds::hull({ -86, -180 }, { -90, 180 }), 0, 0);
+ ASSERT_TRUE(result.empty());
+}
+
+TEST(TileCover, WorldZ0) {
+ auto result = tileCover(LatLngBounds::world(), 0, 0);
+ ASSERT_EQ(1, result.size());
+ ASSERT_EQ(0, result[0].z);
+ ASSERT_EQ(0, result[0].x);
+ ASSERT_EQ(0, result[0].y);
+}
+
+TEST(TileCover, WorldZ1) {
+ auto result = tileCover(LatLngBounds::world(), 1, 1);
+ ASSERT_EQ(4, result.size());
+ ASSERT_EQ(
+ (set {{
+ TileID(1, 1, 1, 1),
+ TileID(1, 0, 1, 1),
+ TileID(1, 1, 0, 1),
+ TileID(1, 0, 0, 1)
+ }}),
+ (set {
+ result.begin(),
+ result.end()
+ }));
+}
+
+//TEST(TileCover, SingletonZ0) {
+// auto result = tileCover(LatLngBounds::singleton({0, 0}), 0, 0);
+// ASSERT_EQ(1, result.size());
+// ASSERT_EQ(0, result[0].z);
+// ASSERT_EQ(0, result[0].x);
+// ASSERT_EQ(0, result[0].y);
+//}
+//
+//TEST(TileCover, SingletonZ1) {
+// auto result = tileCover(LatLngBounds::singleton({0, 0}), 1, 1);
+// ASSERT_EQ(1, result.size());
+// ASSERT_EQ(0, result[0].z);
+// ASSERT_EQ(0, result[0].x);
+// ASSERT_EQ(0, result[0].y);
+//}
+
+static const LatLngBounds sanFrancisco = LatLngBounds::hull(
+ { 37.6609, -122.5744 },
+ { 37.8271, -122.3204 });
+
+TEST(TileCover, SanFranciscoZ0) {
+ auto result = tileCover(sanFrancisco, 0, 0);
+ ASSERT_EQ(1, result.size());
+ ASSERT_EQ(0, result[0].w);
+ ASSERT_EQ(0, result[0].z);
+ ASSERT_EQ(0, result[0].x);
+ ASSERT_EQ(0, result[0].y);
+}
+
+TEST(TileCover, SanFranciscoZ10) {
+ auto result = tileCover(sanFrancisco, 10, 10);
+ ASSERT_EQ(4, result.size());
+ ASSERT_EQ(
+ (set {{
+ TileID(10, 163, 395, 10),
+ TileID(10, 164, 395, 10),
+ TileID(10, 163, 396, 10),
+ TileID(10, 164, 396, 10)
+ }}),
+ (set {
+ result.begin(),
+ result.end()
+ }));
+}
+
+//TEST(TileCover, OrderedByDistanceToCenter) {
+// auto result = tileCover(sanFrancisco, 12, 12);
+// ASSERT_EQ(12, result.size());
+// ASSERT_EQ( 12, result[0].z);
+// ASSERT_EQ( 654, result[0].x);
+// ASSERT_EQ(1583, result[0].y);
+// ASSERT_EQ( 12, result[1].z);
+// ASSERT_EQ( 655, result[1].x);
+// ASSERT_EQ(1583, result[1].y);
+//}
+//
+//static const LatLngBounds sanFranciscoWrapped = LatLngBounds::hull(
+// { 37.6609, 238.5744 },
+// { 37.8271, 238.3204 });
+//
+//TEST(TileCover, SanFranciscoZ0Wrapped) {
+// auto result = tileCover(sanFranciscoWrapped, 0, 0);
+// ASSERT_EQ(1, result.size());
+// ASSERT_EQ(1, result[0].w);
+// ASSERT_EQ(0, result[0].z);
+// ASSERT_EQ(0, result[0].x);
+// ASSERT_EQ(0, result[0].y);
+//}