summaryrefslogtreecommitdiff
path: root/include/mbgl/storage/offline.hpp
blob: 818cfe2ba5c5a11127c716e279bdb7af9c880c3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#pragma once

#include <mbgl/util/geo.hpp>
#include <mbgl/util/range.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;

/*
 * 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(std::string, LatLngBounds, double, double, float);

    /* Private */
    std::vector<CanonicalTileID> tileCover(SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) 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 (inclusive of tiles) that have
     * been fully downloaded.
     */
    uint64_t completedResourceSize = 0;

    /**
     * The number of tiles that are known to be required for this region. This is a
     * subset of `completedResourceCount`.
     */
    uint64_t completedTileCount = 0;

    /**
     * The cumulative size, in bytes, of all tiles that have been fully downloaded.
     * This is a subset of `completedResourceSize`.
     */
    uint64_t completedTileSize = 0;

    /**
     * The number of resources that are known to be required for this region. See the
     * documentation for `requiredResourceCountIsPrecise` for an important caveat
     * about this number.
     */
    uint64_t requiredResourceCount = 0;

    /**
     * This property is true when the value of requiredResourceCount is a precise
     * count of the number of required resources, and false when it is merely a lower
     * bound.
     *
     * Specifically, it is false during early phases of an offline download. Once
     * style and tile sources have been downloaded, it is possible to calculate the
     * precise number of required resources, at which point it is set to true.
     */
    bool requiredResourceCountIsPrecise = false;

    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) {}

    /*
     * Implement this method to be notified when the limit on the number of Mapbox
     * tiles stored for offline regions has been reached.
     *
     * Once the limit has been reached, the SDK will not download further offline
     * tiles from Mapbox APIs until existing tiles have been removed. Contact your
     * Mapbox sales representative to raise the limit.
     *
     * This limit does not apply to non-Mapbox tile sources.
     *
     * 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 mapboxTileCountLimitExceeded(uint64_t /* limit */) {}
};

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,
                  OfflineRegionDefinition,
                  OfflineRegionMetadata);

    const int64_t id;
    const OfflineRegionDefinition definition;
    const OfflineRegionMetadata metadata;
};

} // namespace mbgl