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