1 #pragma once 2 3 #include <mbgl/util/geo.hpp> 4 #include <mbgl/util/range.hpp> 5 #include <mbgl/util/optional.hpp> 6 #include <mbgl/style/types.hpp> 7 #include <mbgl/storage/response.hpp> 8 9 #include <string> 10 #include <vector> 11 #include <functional> 12 13 namespace mbgl { 14 15 class TileID; 16 17 /* 18 * An offline region defined by a style URL, geographic bounding box, zoom range, and 19 * device pixel ratio. 20 * 21 * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. 22 * 23 * maxZoom may be ∞, in which case for each tile source, the region will include 24 * tiles from minZoom up to the maximum zoom level provided by that source. 25 * 26 * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. 27 */ 28 class OfflineTilePyramidRegionDefinition { 29 public: 30 OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float); 31 32 /* Private */ 33 std::vector<CanonicalTileID> tileCover(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const; 34 uint64_t tileCount(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const; 35 const std::string styleURL; 36 const LatLngBounds bounds; 37 const double minZoom; 38 const double maxZoom; 39 const float pixelRatio; 40 private: 41 Range<uint8_t> coveringZoomRange(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const; 42 }; 43 44 /* 45 * For the present, a tile pyramid is the only type of offline region. In the future, 46 * other definition types will be available and this will be a variant type. 47 */ 48 using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition; 49 50 /* 51 * The encoded format is private. 52 */ 53 std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition&); 54 OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string&); 55 56 /* 57 * Arbitrary binary region metadata. The contents are opaque to the mbgl implementation; 58 * it just stores and retrieves a BLOB. SDK bindings should leave the interpretation of 59 * this data up to the application; they _should not_ enforce a higher-level data format. 60 * In the future we want offline database to be portable across target platforms, and a 61 * platform-specific metadata format would prevent that. 62 */ 63 using OfflineRegionMetadata = std::vector<uint8_t>; 64 65 /* 66 * A region is either inactive (not downloading, but previously-downloaded 67 * resources are available for use), or active (resources are being downloaded 68 * or will be downloaded, if necessary, when network access is available). 69 * 70 * This state is independent of whether or not the complete set of resources 71 * is currently available for offline use. To check if that is the case, use 72 * `OfflineRegionStatus::complete()`. 73 */ 74 enum class OfflineRegionDownloadState { 75 Inactive, 76 Active 77 }; 78 79 /* 80 * A region's status includes its active/inactive state as well as counts 81 * of the number of resources that have completed downloading, their total 82 * size in bytes, and the total number of resources that are required. 83 * 84 * Note that the total required size in bytes is not currently available. A 85 * future API release may provide an estimate of this number. 86 */ 87 class OfflineRegionStatus { 88 public: 89 OfflineRegionDownloadState downloadState = OfflineRegionDownloadState::Inactive; 90 91 /** 92 * The number of resources that have been fully downloaded and are ready for 93 * offline access. 94 */ 95 uint64_t completedResourceCount = 0; 96 97 /** 98 * The cumulative size, in bytes, of all resources (inclusive of tiles) that have 99 * been fully downloaded. 100 */ 101 uint64_t completedResourceSize = 0; 102 103 /** 104 * The number of tiles that are known to be required for this region. This is a 105 * subset of `completedResourceCount`. 106 */ 107 uint64_t completedTileCount = 0; 108 109 /** 110 * The cumulative size, in bytes, of all tiles that have been fully downloaded. 111 * This is a subset of `completedResourceSize`. 112 */ 113 uint64_t completedTileSize = 0; 114 115 /** 116 * The number of resources that are known to be required for this region. See the 117 * documentation for `requiredResourceCountIsPrecise` for an important caveat 118 * about this number. 119 */ 120 uint64_t requiredResourceCount = 0; 121 122 /** 123 * This property is true when the value of requiredResourceCount is a precise 124 * count of the number of required resources, and false when it is merely a lower 125 * bound. 126 * 127 * Specifically, it is false during early phases of an offline download. Once 128 * style and tile sources have been downloaded, it is possible to calculate the 129 * precise number of required resources, at which point it is set to true. 130 */ 131 bool requiredResourceCountIsPrecise = false; 132 complete() const133 bool complete() const { 134 return completedResourceCount == requiredResourceCount; 135 } 136 }; 137 138 /* 139 * A region can have a single observer, which gets notified whenever a change 140 * to the region's status occurs. 141 */ 142 class OfflineRegionObserver { 143 public: 144 virtual ~OfflineRegionObserver() = default; 145 146 /* 147 * Implement this method to be notified of a change in the status of an 148 * offline region. Status changes include any change in state of the members 149 * of OfflineRegionStatus. 150 * 151 * Note that this method will be executed on the database thread; it is the 152 * responsibility of the SDK bindings to wrap this object in an interface that 153 * re-executes the user-provided implementation on the main thread. 154 */ statusChanged(OfflineRegionStatus)155 virtual void statusChanged(OfflineRegionStatus) {} 156 157 /* 158 * Implement this method to be notified of errors encountered while downloading 159 * regional resources. Such errors may be recoverable; for example the implementation 160 * will attempt to re-request failed resources based on an exponential backoff 161 * algorithm, or when it detects that network access has been restored. 162 * 163 * Note that this method will be executed on the database thread; it is the 164 * responsibility of the SDK bindings to wrap this object in an interface that 165 * re-executes the user-provided implementation on the main thread. 166 */ responseError(Response::Error)167 virtual void responseError(Response::Error) {} 168 169 /* 170 * Implement this method to be notified when the limit on the number of Mapbox 171 * tiles stored for offline regions has been reached. 172 * 173 * Once the limit has been reached, the SDK will not download further offline 174 * tiles from Mapbox APIs until existing tiles have been removed. Contact your 175 * Mapbox sales representative to raise the limit. 176 * 177 * This limit does not apply to non-Mapbox tile sources. 178 * 179 * Note that this method will be executed on the database thread; it is the 180 * responsibility of the SDK bindings to wrap this object in an interface that 181 * re-executes the user-provided implementation on the main thread. 182 */ mapboxTileCountLimitExceeded(uint64_t)183 virtual void mapboxTileCountLimitExceeded(uint64_t /* limit */) {} 184 }; 185 186 class OfflineRegion { 187 public: 188 // Move-only; not publicly constructible. 189 OfflineRegion(OfflineRegion&&); 190 OfflineRegion& operator=(OfflineRegion&&); 191 ~OfflineRegion(); 192 193 OfflineRegion() = delete; 194 OfflineRegion(const OfflineRegion&) = delete; 195 OfflineRegion& operator=(const OfflineRegion&) = delete; 196 197 int64_t getID() const; 198 const OfflineRegionDefinition& getDefinition() const; 199 const OfflineRegionMetadata& getMetadata() const; 200 201 private: 202 friend class OfflineDatabase; 203 204 OfflineRegion(int64_t id, 205 OfflineRegionDefinition, 206 OfflineRegionMetadata); 207 208 const int64_t id; 209 const OfflineRegionDefinition definition; 210 const OfflineRegionMetadata metadata; 211 }; 212 213 } // namespace mbgl 214