diff options
20 files changed, 449 insertions, 71 deletions
diff --git a/package.json b/package.json index 991b115446..e239c60864 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mapbox/mapbox-gl-native", - "version": "4.0.0", + "version": "4.2.0", "description": "Renders map tiles with Mapbox GL", "keywords": [ "mapbox", diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt index e295b5b10b..5044c077a8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotterTest.kt @@ -2,25 +2,51 @@ package com.mapbox.mapboxsdk.snapshotter import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 -import com.mapbox.mapboxsdk.testapp.activity.snapshot.MapSnapshotterMarkerActivity +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity +import junit.framework.Assert.assertNotNull import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException /** - * Integration test that validates if a snapshot is created with MapSnapshotterMarkerActivity + * Integration test that validates if a snapshotter creation */ @RunWith(AndroidJUnit4::class) class MapSnapshotterTest { @Rule @JvmField - var rule = ActivityTestRule(MapSnapshotterMarkerActivity::class.java) + var rule = ActivityTestRule(FeatureOverviewActivity::class.java) - @Test(timeout = 10000) + private val countDownLatch = CountDownLatch(1) + + @Test fun mapSnapshotter() { - while (rule.activity.mapSnapshot == null) { - Thread.sleep(250) + rule.activity.runOnUiThread { + val options = MapSnapshotter.Options(512, 512) + .withPixelRatio(1.0f) + .withStyle(Style.SATELLITE_STREETS) + .withCameraPosition( + CameraPosition.Builder() + .zoom(12.0) + .target(LatLng(51.145495, 5.742234)) + .build() + ) + val mapSnapshotter = MapSnapshotter(rule.activity, options) + mapSnapshotter.start { + assertNotNull(it) + assertNotNull(it.bitmap) + countDownLatch.countDown() + } + } + if (!countDownLatch.await(30, TimeUnit.SECONDS)) { + throw TimeoutException() } } }
\ No newline at end of file diff --git a/platform/darwin/src/MGLNetworkConfiguration.m b/platform/darwin/src/MGLNetworkConfiguration.m index 40993c97b5..0e5046e7a3 100644 --- a/platform/darwin/src/MGLNetworkConfiguration.m +++ b/platform/darwin/src/MGLNetworkConfiguration.m @@ -11,6 +11,7 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; @property (strong) NSURLSessionConfiguration *sessionConfig; @property (nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary*> *events; @property (nonatomic, weak) id<MGLNetworkConfigurationMetricsDelegate> metricsDelegate; +@property (nonatomic) dispatch_queue_t eventsQueue; @end @@ -20,6 +21,7 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; if (self = [super init]) { self.sessionConfiguration = nil; _events = [NSMutableDictionary dictionary]; + _eventsQueue = dispatch_queue_create("com.mapbox.network-configuration", DISPATCH_QUEUE_CONCURRENT); } return self; @@ -65,8 +67,9 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; } - (void)startDownloadEvent:(NSString *)urlString type:(NSString *)resourceType { - if (urlString && ![self.events objectForKey:urlString]) { - [self.events setObject:@{ MGLStartTime: [NSDate date], MGLResourceType: resourceType } forKey:urlString]; + if (urlString && ![self eventDictionaryForKey:urlString]) { + NSDate *startDate = [NSDate date]; + [self setEventDictionary:@{ MGLStartTime: startDate, MGLResourceType: resourceType } forKey:urlString]; } } @@ -82,10 +85,13 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; { if ([response isKindOfClass:[NSURLResponse class]]) { NSString *urlString = response.URL.relativePath; - if (urlString && [self.events objectForKey:urlString]) { + if (urlString && [self eventDictionaryForKey:urlString]) { NSDictionary *eventAttributes = [self eventAttributesForURL:response withAction:action]; - [self.metricsDelegate networkConfiguration:self didGenerateMetricEvent:eventAttributes]; - [self.events removeObjectForKey:urlString]; + [self removeEventDictionaryForKey:urlString]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.metricsDelegate networkConfiguration:self didGenerateMetricEvent:eventAttributes]; + }); } } @@ -94,7 +100,7 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; - (NSDictionary *)eventAttributesForURL:(NSURLResponse *)response withAction:(NSString *)action { NSString *urlString = response.URL.relativePath; - NSDictionary *parameters = [self.events objectForKey:urlString]; + NSDictionary *parameters = [self eventDictionaryForKey:urlString]; NSDate *startDate = [parameters objectForKey:MGLStartTime]; NSDate *endDate = [NSDate date]; NSTimeInterval elapsedTime = [endDate timeIntervalSinceDate:startDate]; @@ -129,4 +135,28 @@ NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace"; }; } +#pragma mark - Events dictionary access + +- (nullable NSDictionary*)eventDictionaryForKey:(nonnull NSString*)key { + __block NSDictionary *dictionary; + + dispatch_sync(self.eventsQueue, ^{ + dictionary = [self.events objectForKey:key]; + }); + + return dictionary; +} + +- (void)setEventDictionary:(nonnull NSDictionary*)dictionary forKey:(nonnull NSString*)key { + dispatch_barrier_async(self.eventsQueue, ^{ + [self.events setObject:dictionary forKey:key]; + }); +} + +- (void)removeEventDictionaryForKey:(nonnull NSString*)key { + dispatch_barrier_async(self.eventsQueue, ^{ + [self.events removeObjectForKey:key]; + }); +} + @end diff --git a/platform/darwin/src/MGLOfflineRegion.h b/platform/darwin/src/MGLOfflineRegion.h index 0bb1981d61..f873424c93 100644 --- a/platform/darwin/src/MGLOfflineRegion.h +++ b/platform/darwin/src/MGLOfflineRegion.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN See `MGLIdeographicFontFamilyName` setting. Also, for regions outside of China, Japan, and Korea, these glyphs will rarely appear for non-CJK users. - By default, this property is set to `YES`, so that the offline pack will + By default, this property is set to `NO`, so that the offline pack will include ideographic glyphs. */ @property (nonatomic) BOOL includesIdeographicGlyphs; diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h index b48f2ebf2c..c6a51df80c 100644 --- a/platform/darwin/src/MGLOfflineStorage.h +++ b/platform/darwin/src/MGLOfflineStorage.h @@ -171,9 +171,9 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) { /** MGLOfflineStorage implements a singleton (shared object) that manages offline - packs. All of this class’s instance methods are asynchronous, reflecting the - fact that offline resources are stored in a database. The shared object - maintains a canonical collection of offline packs in its `packs` property. + packs and ambient caching. All of this class’s instance methods are asynchronous, + reflecting the fact that offline resources are stored in a database. The shared + object maintains a canonical collection of offline packs in its `packs` property. #### Related examples See the <a href="https://docs.mapbox.com/ios/maps/examples/offline-pack/"> @@ -304,6 +304,21 @@ MGL_EXPORT - (void)removePack:(MGLOfflinePack *)pack withCompletionHandler:(nullable MGLOfflinePackRemovalCompletionHandler)completion; /** + Invalidates the specified offline pack. This method checks that the tiles + in the specified offline pack match those from the server. Local tiles that + do not match the latest version on the server are updated. + + This is more efficient than deleting the offline pack and downloading it + again. If the data stored locally matches that on the server, new data will + not be downloaded. + + @param pack The offline pack to be invalidated. + @param completion The completion handler to call once the pack has been + removed. This handler is executed asynchronously on the main queue. + */ + +- (void)invalidatePack:(MGLOfflinePack *)pack withCompletionHandler:(void (^)(NSError * _Nullable))completion; +/** Forcibly, asynchronously reloads the `packs` property. At some point after this method is called, the pointer values of the `MGLOfflinePack` objects in the `packs` property change, even if the underlying data for these packs has not @@ -341,6 +356,72 @@ MGL_EXPORT */ @property (nonatomic, readonly) unsigned long long countOfBytesCompleted; + +#pragma mark - Managing Ambient Cache + +/** + Sets the maximum ambient cache size in megabytes. The default maximum cache + size is 50 MB. To disable ambient caching, set the maximum ambient cache size + to `0`. Setting the maximum ambient cache size does not impact the maximum size + of offline packs. + + While this method does not limit the space available to offline packs, + data in offline packs count towards this limit. If the maximum ambient + cache size is set to 30 MB and 20 MB of offline packs are downloaded, + there may be only 10 MB reserved for the ambient cache. + + This method should be called before the map and map style have been loaded. + + This method is potentially expensive, as the database will trim cached data + in order to prevent the ambient cache from being larger than the + specified amount. + + @param cacheSize The maximum size in bytes for the ambient cache. + @param completion The completion handler to call once the maximum ambient cache size + has been set. This handler is executed synchronously on the main queue. + */ + +- (void)setMaximumAmbientCacheSize:(NSUInteger)cacheSize withCompletionHandler:(void (^)(NSError *_Nullable error))completion; + +/** + Invalidates the ambient cache. This method checks that the tiles in the + ambient cache match those from the server. If the local tiles do not match + those on the server, they are re-downloaded. + + This is recommended over clearing the cache or resetting the database + because valid local tiles will not be downloaded again. + + Resources shared with offline packs will not be affected by this method. + + @param completion The completion handler to call once the ambient cache has + been revalidated. This handler is executed asynchronously on the main queue. + */ + +- (void)invalidateAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion; + +/** + Clears the ambient cache by deleting resources. This method does not + affect resources shared with offline regions. + + @param completion The completion handler to call once resources from + the ambient cache have been cleared. This handler is executed + asynchronously on the main queue. + */ + +- (void)clearAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion; + +/** + Deletes the existing database, which includes both the ambient cache and offline packs, + then reinitializes it. + + You typically do not need to call this method. + + @param completion The completion handler to call once the pack has database has + been reset. This handler is executed asynchronously on the main queue. + */ + +- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion; + /* Inserts the provided resource into the ambient cache. diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index 6effd8c3ce..93f986a518 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -48,7 +48,6 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio @property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource; @property (nonatomic) std::string mbglCachePath; @property (nonatomic, getter=isPaused) BOOL paused; - @end @implementation MGLOfflineStorage { @@ -341,10 +340,11 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio NSMutableArray *packs; if (!result) { NSString *description = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"ADD_FILE_CONTENTS_FAILED_DESC", @"Foundation", nil, @"Unable to add offline packs from the file at %@.", @"User-friendly error description"), filePath]; - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ - NSLocalizedDescriptionKey: description, - NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(result.error()).c_str()) - }]; + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed + userInfo:@{ + NSLocalizedDescriptionKey: description, + NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(result.error()).c_str()) + }]; } else { auto& regions = result.value(); packs = [NSMutableArray arrayWithCapacity:regions.size()]; @@ -401,7 +401,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio NSError *error; if (!mbglOfflineRegion) { NSString *errorDescription = @(mbgl::util::toString(mbglOfflineRegion.error()).c_str()); - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:errorDescription ? @{ + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:errorDescription ? @{ NSLocalizedDescriptionKey: errorDescription, } : nil]; } @@ -431,11 +431,10 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio completion(nil); return; } - _mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) { NSError *error; if (exception) { - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{ NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), }]; } @@ -445,6 +444,29 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio }); } }); + +} + +- (void)invalidatePack:(MGLOfflinePack *)pack withCompletionHandler:(void (^)(NSError * _Nullable))completion { + mbgl::OfflineRegion& region = *pack.mbglOfflineRegion; + NSError *error; + if (!pack.mbglOfflineRegion) { + completion(nil); + return; + } + + _mbglFileSource->invalidateOfflineRegion(region, [&](std::exception_ptr exception) { + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + }); + if (completion) { + dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) { + completion(error); + }); + } } - (void)reloadPacks { @@ -462,7 +484,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio NSError *error; NSMutableArray *packs; if (!result) { - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{ NSLocalizedDescriptionKey: @(mbgl::util::toString(result.error()).c_str()), }]; } else { @@ -486,6 +508,72 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio _mbglFileSource->setOfflineMapboxTileCountLimit(maximumCount); } +#pragma mark - Ambient Cache management + +- (void)setMaximumAmbientCacheSize:(NSUInteger)cacheSize withCompletionHandler:(void (^)(NSError * _Nullable))completion { + _mbglFileSource->setMaximumAmbientCacheSize(cacheSize, [&, completion](std::exception_ptr exception) { + NSError *error; + if (completion) { + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + dispatch_sync(dispatch_get_main_queue(), ^ { + completion(error); + }); + } + }); +} + +- (void)invalidateAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable))completion { + _mbglFileSource->invalidateAmbientCache([&, completion](std::exception_ptr exception){ + NSError *error; + if (completion) { + if (exception) { + // Convert std::exception_ptr to an NSError. + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + dispatch_async(dispatch_get_main_queue(), ^ { + completion(error); + }); + } + }); +} + +- (void)clearAmbientCacheWithCompletionHandler:(void (^)(NSError *_Nullable error))completion { + _mbglFileSource->clearAmbientCache([&, completion](std::exception_ptr exception){ + NSError *error; + if (completion) { + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeModifyingOfflineStorageFailed userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) { + completion(error); + }); + } + }); +} + +- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion { + _mbglFileSource->resetDatabase([&, completion](std::exception_ptr exception) { + NSError *error; + if (completion) { + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }); +} #pragma mark - - (unsigned long long)countOfBytesCompleted { diff --git a/platform/darwin/src/MGLShapeOfflineRegion.mm b/platform/darwin/src/MGLShapeOfflineRegion.mm index 25b6b8e166..b4f4b5e92a 100644 --- a/platform/darwin/src/MGLShapeOfflineRegion.mm +++ b/platform/darwin/src/MGLShapeOfflineRegion.mm @@ -72,7 +72,7 @@ _shape = shape; _minimumZoomLevel = minimumZoomLevel; _maximumZoomLevel = maximumZoomLevel; - _includesIdeographicGlyphs = YES; + _includesIdeographicGlyphs = NO; } return self; } diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm index a398d6baa4..73fcaa91d8 100644 --- a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm @@ -68,7 +68,7 @@ _bounds = bounds; _minimumZoomLevel = minimumZoomLevel; _maximumZoomLevel = maximumZoomLevel; - _includesIdeographicGlyphs = YES; + _includesIdeographicGlyphs = NO; } return self; } diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h index b8354d2e83..7e0dd27141 100644 --- a/platform/darwin/src/MGLTypes.h +++ b/platform/darwin/src/MGLTypes.h @@ -53,7 +53,9 @@ typedef NS_ENUM(NSInteger, MGLErrorCode) { /** Source is in use and cannot be removed */ MGLErrorCodeSourceIsInUseCannotRemove = 7, /** Source is in use and cannot be removed */ - MGLErrorCodeSourceIdentifierMismatch = 8 + MGLErrorCodeSourceIdentifierMismatch = 8, + /** An error occurred while modifying the offline storage database */ + MGLErrorCodeModifyingOfflineStorageFailed = 9 }; /** Options for enabling debugging features in an `MGLMapView` instance. */ diff --git a/platform/darwin/test/MGLOfflineRegionTests.m b/platform/darwin/test/MGLOfflineRegionTests.m index 4d5767a8d2..0af9ebb5fa 100644 --- a/platform/darwin/test/MGLOfflineRegionTests.m +++ b/platform/darwin/test/MGLOfflineRegionTests.m @@ -12,7 +12,7 @@ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(kCLLocationCoordinate2DInvalid, kCLLocationCoordinate2DInvalid); MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:nil bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX]; XCTAssertEqualObjects(region.styleURL, [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion], @"Streets isn’t the default style."); - + NSURL *localURL = [NSURL URLWithString:@"beautiful.style"]; XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, MGLInvalidStyleURLException, @"No exception raised when initializing region with a local file URL as the style URL."); } @@ -22,7 +22,7 @@ MGLTilePyramidOfflineRegion *original = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] bounds:bounds fromZoomLevel:5 toZoomLevel:10]; MGLTilePyramidOfflineRegion *copy = [original copy]; XCTAssertEqualObjects(original, copy, @"Tile pyramid region should be equal to its copy."); - + XCTAssertEqualObjects(original.styleURL, copy.styleURL, @"Style URL has changed."); XCTAssert(MGLCoordinateBoundsEqualToCoordinateBounds(original.bounds, copy.bounds), @"Bounds have changed."); XCTAssertEqual(original.minimumZoomLevel, copy.minimumZoomLevel, @"Minimum zoom level has changed."); @@ -48,4 +48,24 @@ XCTAssertEqual(original.includesIdeographicGlyphs, copy.includesIdeographicGlyphs, @"Include ideographs has changed."); } +- (void)testIncludesIdeographicGlyphsByDefault { + + // Tile pyramid offline region + { + MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(kCLLocationCoordinate2DInvalid, kCLLocationCoordinate2DInvalid); + MGLTilePyramidOfflineRegion *tilePyramidOfflineRegion = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] bounds:bounds fromZoomLevel:5 toZoomLevel:10]; + XCTAssertFalse(tilePyramidOfflineRegion.includesIdeographicGlyphs, @"tile pyramid offline region should not include ideographic glyphs"); + } + + // Shape offline region + { + NSString *geojson = @"{\"type\": \"Point\", \"coordinates\": [-3.8671874999999996, 52.482780222078226] }"; + NSError *error; + MGLShape *shape = [MGLShape shapeWithData: [geojson dataUsingEncoding:NSUTF8StringEncoding] encoding: NSUTF8StringEncoding error:&error]; + XCTAssertNil(error); + MGLShapeOfflineRegion *shapeOfflineRegion = [[MGLShapeOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] shape:shape fromZoomLevel:5 toZoomLevel:10]; + XCTAssertFalse(shapeOfflineRegion.includesIdeographicGlyphs, @"tile pyramid offline region should not include ideographic glyphs"); + } +} + @end diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm index 5551d8889b..ee4bcc2c65 100644 --- a/platform/darwin/test/MGLOfflineStorageTests.mm +++ b/platform/darwin/test/MGLOfflineStorageTests.mm @@ -201,6 +201,68 @@ pack = nil; } +- (void)testInvalidatePack { + XCTestExpectation *expectation = [self expectationWithDescription:@"Expect offline pack to be invalidated without an error."]; + MGLCoordinateBounds bounds = { + { .latitude = 48.8660, .longitude = 2.3306 }, + { .latitude = 48.8603, .longitude = 2.3213 }, + }; + + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:styleURL bounds:bounds fromZoomLevel:10 toZoomLevel:11]; + + NSString *nameKey = @"Name"; + NSString *name = @"Paris square"; + + NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{nameKey: name}]; + [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) { + XCTAssertNotNil(pack); + [[MGLOfflineStorage sharedOfflineStorage] invalidatePack:pack withCompletionHandler:^(NSError * _Nullable) { + XCTAssertNotNil(pack); + XCTAssertNil(error); + [expectation fulfill]; + }]; + }]; + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + +- (void)testSetMaximumAmbientCache { + XCTestExpectation *expectation = [self expectationWithDescription:@"Expect maximum cache size to be raised without an error."]; + [[MGLOfflineStorage sharedOfflineStorage] setMaximumAmbientCacheSize:0 withCompletionHandler:^(NSError * _Nullable error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + +- (void)testInvalidateAmbientCache { + XCTestExpectation *expectation = [self expectationWithDescription:@"Expect cache to be invalidated without an error."]; + [[MGLOfflineStorage sharedOfflineStorage] invalidateAmbientCacheWithCompletionHandler:^(NSError * _Nullable error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + +- (void)testClearCache { + XCTestExpectation *expectation = [self expectationWithDescription:@"Expect cache to be cleared without an error."]; + [[MGLOfflineStorage sharedOfflineStorage] clearAmbientCacheWithCompletionHandler:^(NSError * _Nullable error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + +- (void)testResetDatabase { + XCTestExpectation *expectation = [self expectationWithDescription:@"Expect database to be reset without an error."]; + [[MGLOfflineStorage sharedOfflineStorage] resetDatabaseWithCompletionHandler:^(NSError * _Nullable error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + - (void)testBackupExclusion { NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index cdb853ebb6..ed815cc141 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -10,6 +10,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Other changes * Updated "map ID" to the more accurate term "tileset ID" in documentation; updated "style's Map ID" to the more accurate term "style URL". ([#15116](https://github.com/mapbox/mapbox-gl-native/pull/15116)) +* Ideographic glyphs from Chinese, Japanese, and Korean are no longer downloaded by default as part of offline packs; they are instead rendered on-device, saving bandwidth and storage while improving performance. ([#14176](https://github.com/mapbox/mapbox-gl-native/pull/14176)) ## 5.2.0 @@ -44,6 +45,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Deprecated variants of the above methods without completion handlers. ([#14959](https://github.com/mapbox/mapbox-gl-native/pull/14959)) * Fixed an issue where the two-finger tilt gesture would continue after lifting one finger. ([#14969](https://github.com/mapbox/mapbox-gl-native/pull/14969)) * Added `MGLMapView.compassView.visibility` and `MGLOrnamentVisibility` to allow configuration of compass visibility behavior. ([#15055](https://github.com/mapbox/mapbox-gl-native/pull/15055)) +* Fixed a bug where using the pinch gesture could result in an incorrect map center coordinate. ([#15097](https://github.com/mapbox/mapbox-gl-native/pull/15097)) +* Fixed a crash during network access. ([#15113](https://github.com/mapbox/mapbox-gl-native/pull/15113)) ## 5.1.0 - June 19, 2019 diff --git a/platform/ios/app/MBXOfflinePacksTableViewController.m b/platform/ios/app/MBXOfflinePacksTableViewController.m index e237df4019..90497ca939 100644 --- a/platform/ios/app/MBXOfflinePacksTableViewController.m +++ b/platform/ios/app/MBXOfflinePacksTableViewController.m @@ -103,8 +103,10 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac } MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:mapView.styleURL bounds:mapView.visibleCoordinateBounds fromZoomLevel:mapView.zoomLevel toZoomLevel:mapView.maximumZoomLevel]; - BOOL hasIdeographicFontFamilyName = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLIdeographicFontFamilyName"]; - region.includesIdeographicGlyphs = hasIdeographicFontFamilyName; + id ideographicFontFamilyName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLIdeographicFontFamilyName"]; + if([ideographicFontFamilyName isKindOfClass:[NSNumber class]] && ![ideographicFontFamilyName boolValue]){ + region.includesIdeographicGlyphs = YES; + } NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{ MBXOfflinePackContextNameKey: name, }]; @@ -126,6 +128,19 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac [self presentViewController:alertController animated:YES completion:nil]; } +- (IBAction)invalidatePacks:(id)sender { + for (MGLOfflinePack *pack in [MGLOfflineStorage sharedOfflineStorage].packs) { + + CFTimeInterval start = CACurrentMediaTime(); + [[MGLOfflineStorage sharedOfflineStorage] invalidatePack:pack withCompletionHandler:^(NSError * _Nullable error) { + CFTimeInterval end = CACurrentMediaTime(); + CFTimeInterval difference = end - start; + NSLog(@"invalidatePack Started: %f Ended: %f Total Time: %f", start, end, difference); + }]; + } +} + + #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard index f4e535a56c..28316745a1 100644 --- a/platform/ios/app/Main.storyboard +++ b/platform/ios/app/Main.storyboard @@ -1,11 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff"> - <device id="retina4_7" orientation="portrait"> - <adaptation id="fullscreen"/> - </device> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff"> + <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -15,14 +13,14 @@ <objects> <viewController id="WaX-pd-UZQ" userLabel="Map View Controller" customClass="MBXViewController" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="Z9X-fc-PUC"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <rect key="frame" x="0.0" y="0.0" width="203" height="33"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <rect key="frame" x="0.0" y="0.0" width="203" height="33"/> <subviews> <button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB"> - <rect key="frame" x="8" y="102" width="40" height="20"/> + <rect key="frame" x="8" y="82" width="40" height="20"/> <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <accessibility key="accessibilityConfiguration"> <accessibilityTraits key="traits" button="YES" notEnabled="YES"/> @@ -40,7 +38,7 @@ </userDefinedRuntimeAttributes> </button> <view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView"> - <rect key="frame" x="0.0" y="467" width="375" height="200"/> + <rect key="frame" x="0.0" y="-167" width="203" height="200"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <accessibility key="accessibilityConfiguration"> <accessibilityTraits key="traits" notEnabled="YES"/> @@ -143,7 +141,7 @@ <rect key="frame" x="0.0" y="28" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fGu-Ys-Eh1" id="sUf-bc-8xG"> - <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Inactive Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JtH-Ce-MI5"> @@ -167,7 +165,7 @@ <rect key="frame" x="0.0" y="72" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mKB-tz-Zfl" id="nS3-aU-nBr"> - <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Active Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9ZK-gS-wJ4"> @@ -194,11 +192,18 @@ </connections> </tableView> <navigationItem key="navigationItem" title="Offline Packs" id="UcK-PK-eQA"> - <barButtonItem key="rightBarButtonItem" systemItem="add" id="gCV-hl-Mzc"> - <connections> - <action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/> - </connections> - </barButtonItem> + <rightBarButtonItems> + <barButtonItem systemItem="add" id="gCV-hl-Mzc"> + <connections> + <action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/> + </connections> + </barButtonItem> + <barButtonItem style="plain" systemItem="refresh" id="2fx-iS-Veb"> + <connections> + <action selector="invalidatePacks:" destination="7q0-lI-zqb" id="5lx-FY-aTt"/> + </connections> + </barButtonItem> + </rightBarButtonItems> </navigationItem> <connections> <segue destination="x2D-ga-sM5" kind="unwind" identifier="ReturnToMap" unwindAction="unwindToMapViewController:" id="6MZ-Ed-tu2"/> @@ -215,7 +220,7 @@ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="PSe-Ot-7Ff" sceneMemberID="viewController"> <toolbarItems/> <navigationBar key="navigationBar" contentMode="scaleToFill" id="ONr-CS-J5X"> - <rect key="frame" x="0.0" y="20" width="375" height="44"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> </navigationBar> <nil name="viewControllers"/> @@ -257,7 +262,7 @@ </constraints> </scrollView> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="l5l-w7-P80" userLabel="Control Panel View"> - <rect key="frame" x="0.0" y="20" width="375" height="64"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="64"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Zoom" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DgB-BD-Ltx"> <rect key="frame" x="29.5" y="6" width="35" height="16"/> @@ -381,22 +386,22 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="miZ-Fw-EWq" userLabel="Image View TL"> - <rect key="frame" x="0.0" y="64" width="125" height="301.5"/> + <rect key="frame" x="0.0" y="44" width="125" height="311.5"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="XuN-T4-Z83" userLabel="Image View TM"> - <rect key="frame" x="125" y="64" width="125" height="301.5"/> + <rect key="frame" x="125" y="44" width="125" height="311.5"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ykR-Ku-i9l" userLabel="Image View TR"> - <rect key="frame" x="250" y="64" width="125" height="301.5"/> + <rect key="frame" x="250" y="44" width="125" height="311.5"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TL0-V8-T2F" userLabel="Image View BL"> - <rect key="frame" x="0.0" y="365.5" width="125" height="301.5"/> + <rect key="frame" x="0.0" y="355.5" width="125" height="311.5"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eMy-JU-rq4" userLabel="Image View BM"> - <rect key="frame" x="125" y="365.5" width="125" height="301.5"/> + <rect key="frame" x="125" y="355.5" width="125" height="311.5"/> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zT0-3J-0xw" userLabel="Image View BR"> - <rect key="frame" x="250" y="365.5" width="125" height="301.5"/> + <rect key="frame" x="250" y="355.5" width="125" height="311.5"/> </imageView> </subviews> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 670e78a46c..98a651f13f 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -516,6 +516,7 @@ CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */; }; CA7766832229C10E0008DE9E /* MGLCompactCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */; }; CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; }; + CA86FF0E22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */; }; CA88DC3021C85D900059ED5A /* MGLStyleURLIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */; }; CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */; }; CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; }; @@ -1198,6 +1199,7 @@ CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestUtility.h; path = ../../darwin/test/MGLTestUtility.h; sourceTree = "<group>"; }; CA65C4F721E9BB080068B0D4 /* MGLCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCluster.h; sourceTree = "<group>"; }; CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationViewIntegrationTests.m; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.m"; sourceTree = "<group>"; }; + CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = "<group>"; }; CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = "<group>"; }; CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; }; CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = "<group>"; }; @@ -2071,6 +2073,7 @@ 357579811D502AD4000B822E /* Styling */, 409F43FB1E9E77D10048729D /* Swift Integration */, 4031ACFD1E9FD26900A3EA26 /* Test Helpers */, + CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */, ); name = "SDK Tests"; path = test; @@ -3250,6 +3253,7 @@ DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */, DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */, DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */, + CA86FF0E22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m in Sources */, 4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */, DAEDC4341D603417000224FF /* MGLAttributionInfoTests.m in Sources */, 1F7454A91ED08AB400021D39 /* MGLLightTest.mm in Sources */, diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index d027f616bd..d77f94d8ba 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -297,8 +297,8 @@ public: NSInteger _changeDelimiterSuppressionDepth; - /// Center coordinate of the pinch gesture on the previous iteration of the gesture. - CLLocationCoordinate2D _previousPinchCenterCoordinate; + /// Center of the pinch gesture on the previous iteration of the gesture. + CGPoint _previousPinchCenterPoint; NSUInteger _previousPinchNumberOfTouches; CLLocationDistance _distanceFromOldUserLocation; @@ -1643,11 +1643,7 @@ public: // meaningless. if (self.userTrackingMode == MGLUserTrackingModeNone && pinch.numberOfTouches == _previousPinchNumberOfTouches) { - CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate; - mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x }; - self.mbglMap.jumpTo(mbgl::CameraOptions() - .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate)) - .withPadding(padding)); + self.mbglMap.moveBy({centerPoint.x - _previousPinchCenterPoint.x, centerPoint.y - _previousPinchCenterPoint.y}); } } [self cameraIsChanging]; @@ -1705,7 +1701,7 @@ public: [self unrotateIfNeededForGesture]; } - _previousPinchCenterCoordinate = [self convertPoint:centerPoint toCoordinateFromView:self]; + _previousPinchCenterPoint = centerPoint; _previousPinchNumberOfTouches = pinch.numberOfTouches; } diff --git a/platform/ios/test/MGLNetworkConfigurationTests.m b/platform/ios/test/MGLNetworkConfigurationTests.m new file mode 100644 index 0000000000..bfb63f57af --- /dev/null +++ b/platform/ios/test/MGLNetworkConfigurationTests.m @@ -0,0 +1,43 @@ +#import <Mapbox/Mapbox.h> +#import <XCTest/XCTest.h> +#import "MGLNetworkConfiguration_Private.h" + +@interface MGLNetworkConfigurationTests : XCTestCase +@end + +@implementation MGLNetworkConfigurationTests + +// Regression test for https://github.com/mapbox/mapbox-gl-native/issues/14982 +- (void)testAccessingEventsFromMultipleThreads { + MGLNetworkConfiguration *configuration = [[MGLNetworkConfiguration alloc] init]; + + // Concurrent + dispatch_queue_t queue = dispatch_queue_create("com.mapbox.testAccessingEventsFromMultipleThreads", DISPATCH_QUEUE_CONCURRENT); + + NSUInteger numberOfConcurrentBlocks = 20; + + XCTestExpectation *expectation = [self expectationWithDescription:@"wait-for-threads"]; + expectation.expectedFulfillmentCount = numberOfConcurrentBlocks; + + for (NSUInteger i = 0; i < numberOfConcurrentBlocks; i++) { + + NSString *event = [NSString stringWithFormat:@"test://event-%ld", i]; + NSString *resourceType = @"test"; + + dispatch_async(queue, ^{ + [configuration startDownloadEvent:event type:resourceType]; + + NSURL *url = [NSURL URLWithString:event]; + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:url MIMEType:nil expectedContentLength:0 textEncodingName:nil]; + + [configuration stopDownloadEventForResponse:response]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [expectation fulfill]; + }); + }); + } + + [self waitForExpectations:@[expectation] timeout:10.0]; +} +@end diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 17ea823784..88fa37052b 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -4,11 +4,11 @@ * Added an `MGLMapView.prefetchesTiles` property to configure lower-resolution tile prefetching behavior. ([#14816](https://github.com/mapbox/mapbox-gl-native/pull/14816)) * Fixed queryRenderedFeatues bug caused by incorrect sort feature index calculation. ([#14884](https://github.com/mapbox/mapbox-gl-native/pull/14884)) -* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862)) +* Ideographic glyphs from Chinese, Japanese, and Korean are no longer downloaded by default as part of offline packs; they are instead rendered on-device, saving bandwidth and storage while improving performance. ([#14176](https://github.com/mapbox/mapbox-gl-native/pull/14176)) +* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862)) * Performance improvements for queryRenderedFeatures API and optimization that allocates containers based on a number of rendered layers. ([#14930](https://github.com/mapbox/mapbox-gl-native/pull/14930)) * Fixed rendering layers after fill-extrusion regression caused by optimization of fill-extrusion rendering. ([#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065)) - ### Styles and rendering * Setting `MGLMapView.contentInset` now moves the map’s focal point to the center of the content frame after insetting. ([#14664](https://github.com/mapbox/mapbox-gl-native/pull/14664)) diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index 213aa33107..1ab8b690b9 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -932,8 +932,8 @@ NSArray<id <MGLAnnotation>> *MBXFlattenedShapes(NSArray<id <MGLAnnotation>> *sha self.minimumOfflinePackZoomLevelFormatter.maximum = @(ceil(self.mapView.maximumZoomLevel)); self.maximumOfflinePackZoomLevelFormatter.maximum = @(ceil(self.mapView.maximumZoomLevel)); - NSString *fontFamilyName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLIdeographicFontFamilyName"]; - self.includesIdeographicGlyphsBox.state = fontFamilyName ? NSOffState : NSOnState; + id ideographicFontFamilyName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLIdeographicFontFamilyName"]; + self.includesIdeographicGlyphsBox.state = ([ideographicFontFamilyName isKindOfClass:[NSNumber class]] && ![ideographicFontFamilyName boolValue]) ? NSOffState : NSOnState; [self.addOfflinePackWindow makeFirstResponder:self.offlinePackNameField]; __weak __typeof__(self) weakSelf = self; diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md index e03a64b049..2999a70f05 100644 --- a/platform/node/CHANGELOG.md +++ b/platform/node/CHANGELOG.md @@ -1,9 +1,12 @@ -# master +# 4.2.0 +- Add an option to set whether or not an image should be treated as a SDF ([#15054](https://github.com/mapbox/mapbox-gl-native/issues/15054)) +- Fix problems associated with node 10 and NAN [#14847](https://github.com/mapbox/mapbox-gl-native/pull/14847) + +# 4.1.0 - Add `symbol-z-order` symbol layout property to style spec [#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783) - Add `crossSourceCollisions` map option, with default of `true`. When set to `false`, cross-source collision detection is disabled. ([#12820] (https://github.com/mapbox/mapbox-gl-native/issues/12820)) - Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) [#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864) - Fixed an issue where fill and line layers would occasionally flicker on zoom ([#12982](https://github.com/mapbox/mapbox-gl-native/pull/12982)) -- Add an option to set whether or not an image should be treated as a SDF ([#15054](https://github.com/mapbox/mapbox-gl-native/issues/15054)) # 4.0.0 - Many new features and enhancements, including: |