diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java')
-rw-r--r-- | platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java | 748 |
1 files changed, 0 insertions, 748 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java deleted file mode 100644 index a7bb9a9985..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ /dev/null @@ -1,748 +0,0 @@ -package com.mapbox.mapboxsdk.offline; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import com.mapbox.mapboxsdk.LibraryLoader; -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.R; -import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.maps.TelemetryDefinition; -import com.mapbox.mapboxsdk.net.ConnectivityReceiver; -import com.mapbox.mapboxsdk.storage.FileSource; -import com.mapbox.mapboxsdk.utils.FileUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; - -/** - * The offline manager is the main entry point for offline-related functionality. - * <p> - * It'll help you list and create offline regions. - * </p> - * - * @see <a href="https://docs.mapbox.com/help/troubleshooting/mobile-offline/">Offline Maps Information/</a> - */ -@UiThread -public class OfflineManager { - - private static final String TAG = "Mbgl - OfflineManager"; - - // - // Static methods - // - - static { - LibraryLoader.load(); - } - - // Native peer pointer - @Keep - private long nativePtr; - - // Reference to the file source to keep it alive for the - // lifetime of this object - private final FileSource fileSource; - - // Makes sure callbacks come back to the main thread - private final Handler handler = new Handler(Looper.getMainLooper()); - - // This object is implemented as a singleton - @SuppressLint("StaticFieldLeak") - private static OfflineManager instance; - - // The application context - private Context context; - - /** - * This callback receives an asynchronous response containing a list of all - * OfflineRegion in the database or an error message otherwise. - */ - @Keep - public interface ListOfflineRegionsCallback { - /** - * Receives the list of offline regions. - * - * @param offlineRegions the offline region array - */ - void onList(OfflineRegion[] offlineRegions); - - /** - * Receives the error message. - * - * @param error the error message - */ - void onError(String error); - } - - /** - * This callback receives an asynchronous response containing the newly created - * OfflineRegion in the database or an error message otherwise. - */ - @Keep - public interface CreateOfflineRegionCallback { - /** - * Receives the newly created offline region. - * - * @param offlineRegion the offline region to create - */ - void onCreate(OfflineRegion offlineRegion); - - /** - * Receives the error message. - * - * @param error the error message to be shown - */ - void onError(String error); - } - - /** - * This callback receives an asynchronous response containing a list of all - * OfflineRegion added to the database during the merge. - */ - @Keep - public interface MergeOfflineRegionsCallback { - /** - * Receives the list of merged offline regions. - * - * @param offlineRegions the offline region array - */ - void onMerge(OfflineRegion[] offlineRegions); - - /** - * Receives the error message. - * - * @param error the error message - */ - void onError(String error); - } - - /* - * Constructor - */ - private OfflineManager(Context context) { - this.context = context.getApplicationContext(); - this.fileSource = FileSource.getInstance(this.context); - initialize(fileSource); - - // Delete any existing previous ambient cache database - deleteAmbientDatabase(this.context); - } - - private void deleteAmbientDatabase(final Context context) { - final String path = FileSource.getInternalCachePath(context) + File.separator + "mbgl-cache.db"; - FileUtils.deleteFile(path); - } - - /** - * Get the single instance of offline manager. - * - * @param context the context used to host the offline manager - * @return the single instance of offline manager - */ - public static synchronized OfflineManager getInstance(@NonNull Context context) { - if (instance == null) { - instance = new OfflineManager(context); - } - - return instance; - } - - /** - * Retrieve all regions in the offline database. - * <p> - * The query will be executed asynchronously and the results passed to the given - * callback on the main thread. - * </p> - * - * @param callback the callback to be invoked - */ - public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) { - fileSource.activate(); - listOfflineRegions(fileSource, new ListOfflineRegionsCallback() { - - @Override - public void onList(final OfflineRegion[] offlineRegions) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - callback.onList(offlineRegions); - } - }); - } - - @Override - public void onError(final String error) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - callback.onError(error); - } - }); - } - }); - } - - /** - * Merge offline regions from a secondary database into the main offline database. - * <p> - * When the merge is completed, or fails, the {@link MergeOfflineRegionsCallback} will be invoked on the main thread. - * The callback reference is <b>strongly kept</b> throughout the process, - * so it needs to be wrapped in a weak reference or released on the client side if necessary. - * <p> - * The secondary database may need to be upgraded to the latest schema. - * This is done in-place and requires write-access to the provided path. - * If the app's process doesn't have write-access to the provided path, - * the file will be copied to the temporary, internal directory for the duration of the merge. - * <p> - * Only resources and tiles that belong to a region will be copied over. Identical - * regions will be flattened into a single new region in the main database. - * <p> - * The operation will be aborted and {@link MergeOfflineRegionsCallback#onError(String)} with an appropriate message - * will be invoked if the merge would result in the offline tile count limit being exceeded. - * <p> - * Merged regions may not be in a completed status if the secondary database - * does not contain all the tiles or resources required by the region definition. - * - * @param path secondary database writable path - * @param callback completion/error callback - */ - public void mergeOfflineRegions(@NonNull String path, @NonNull final MergeOfflineRegionsCallback callback) { - final File src = new File(path); - new Thread(new Runnable() { - @Override - public void run() { - String errorMessage = null; - if (src.canWrite()) { - handler.post(new Runnable() { - @Override - public void run() { - // path writable, merge and update schema in place if necessary - mergeOfflineDatabaseFiles(src, callback, false); - } - }); - } else if (src.canRead()) { - // path not writable, copy the the file to temp directory - final File dst = new File(FileSource.getInternalCachePath(context), src.getName()); - try { - copyTempDatabaseFile(src, dst); - handler.post(new Runnable() { - @Override - public void run() { - // merge and update schema using the copy - OfflineManager.this.mergeOfflineDatabaseFiles(dst, callback, true); - } - }); - } catch (IOException ex) { - ex.printStackTrace(); - errorMessage = ex.getMessage(); - } - } else { - // path not readable, abort - errorMessage = "Secondary database needs to be located in a readable path."; - } - - if (errorMessage != null) { - final String finalErrorMessage = errorMessage; - handler.post(new Runnable() { - @Override - public void run() { - callback.onError(finalErrorMessage); - } - }); - } - } - }).start(); - } - - /** - * Delete existing database and re-initialize. - * <p> - * 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. - * </p> - * - * @param callback the callback to be invoked when the database was reset or when the operation erred. - */ - public void resetDatabase(@Nullable final FileSourceCallback callback) { - fileSource.activate(); - nativeResetDatabase(new FileSourceCallback() { - @Override - public void onSuccess() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onSuccess(); - } - } - }); - } - - @Override - public void onError(@NonNull final String message) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onError(message); - } - } - }); - } - }); - } - - /** - * Packs the existing database file into a minimal amount of disk space. - * <p> - * This operation has a performance impact as it will vacuum the database, - * forcing it to move pages on the filesystem. - * <p> - * 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. - * </p> - * - * @param callback the callback to be invoked when the database was reset or when the operation erred. - */ - public void packDatabase(@Nullable final FileSourceCallback callback) { - fileSource.activate(); - nativePackDatabase(new FileSourceCallback() { - @Override - public void onSuccess() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onSuccess(); - } - } - }); - } - - @Override - public void onError(@NonNull final String message) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onError(message); - } - } - }); - } - }); - } - - /** - * Forces re-validation of the ambient cache. - * <p> - * Forces Mapbox GL Native to revalidate resources stored in the ambient - * cache with the tile server before using them, making sure they - * are the latest version. This is more efficient than cleaning the - * cache because if the resource is considered valid after the server - * lookup, it will not get downloaded again. - * <p> - * Resources overlapping with offline regions will not be affected - * by this call. - * </p> - * - * @param callback the callback to be invoked when the ambient cache was invalidated or when the operation erred. - */ - public void invalidateAmbientCache(@Nullable final FileSourceCallback callback) { - fileSource.activate(); - nativeInvalidateAmbientCache(new FileSourceCallback() { - @Override - public void onSuccess() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onSuccess(); - } - } - }); - } - - @Override - public void onError(@NonNull final String message) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onError(message); - } - } - }); - } - }); - } - - /** - * Erase resources from the ambient cache, freeing storage space. - * <p> - * Erases the ambient cache, freeing resources. - * <p> - * Note that this operation can be potentially slow if packing the database - * occurs automatically ({@link OfflineManager#runPackDatabaseAutomatically(boolean)}). - * </p> - * <p> - * Resources overlapping with offline regions will not be affected - * by this call. - * </p> - * - * @param callback the callback to be invoked when the ambient cache was cleared or when the operation erred. - */ - public void clearAmbientCache(@Nullable final FileSourceCallback callback) { - fileSource.activate(); - nativeClearAmbientCache(new FileSourceCallback() { - @Override - public void onSuccess() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onSuccess(); - } - } - }); - } - - @Override - public void onError(@NonNull final String message) { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onError(message); - } - } - }); - } - }); - } - - /** - * Sets the maximum size in bytes for the ambient cache. - * <p> - * This call is potentially expensive because it will try - * to trim the data in case the database is larger than the - * size defined. The size of offline regions are not affected - * by this settings, but the ambient cache will always try - * to not exceed the maximum size defined, taking into account - * the current size for the offline regions. - * </p> - * <p> - * Note that if you use the SDK's offline functionality, your ability to set the ambient cache size will be limited. - * Space that offline regions take up detract from the space available for ambient caching, and the ambient cache - * size does not block offline downloads. For example: if the maximum cache size is set to 50 MB and 40 MB are - * already used by offline regions, the ambient cache size will effectively be 10 MB. - * </p> - * <p> - * Setting the size to 0 will disable the cache if there is no - * offline region on the database. - * </p> - * <[ - * <p> - * This method should always be called at the start of an app, before setting the style and loading a map. - * Otherwise, the map will instantiate with the default cache size of 50 MB. - * </p> - * - * @param size the maximum size of the ambient cache - * @param callback the callback to be invoked when the the maximum size has been set or when the operation erred. - */ - public void setMaximumAmbientCacheSize(long size, @Nullable final FileSourceCallback callback) { - fileSource.activate(); - nativeSetMaximumAmbientCacheSize(size, new FileSourceCallback() { - @Override - public void onSuccess() { - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onSuccess(); - } - } - }); - } - - @Override - public void onError(@NonNull final String message) { - fileSource.activate(); - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - if (callback != null) { - callback.onError(message); - } - } - }); - } - }); - } - - /** - * This callback receives an asynchronous response indicating if an operation has succeeded or failed. - */ - @Keep - public interface FileSourceCallback { - - /** - * Receives the success of an operation - */ - void onSuccess(); - - /** - * Receives an error message if an operation was not successful - * - * @param message the error message - */ - void onError(@NonNull String message); - - } - - private static void copyTempDatabaseFile(@NonNull File sourceFile, File destFile) throws IOException { - if (!destFile.exists() && !destFile.createNewFile()) { - throw new IOException("Unable to copy database file for merge."); - } - - FileChannel source = null; - FileChannel destination = null; - - try { - source = new FileInputStream(sourceFile).getChannel(); - destination = new FileOutputStream(destFile).getChannel(); - destination.transferFrom(source, 0, source.size()); - } catch (IOException ex) { - throw new IOException(String.format("Unable to copy database file for merge. %s", ex.getMessage())); - } finally { - if (source != null) { - source.close(); - } - if (destination != null) { - destination.close(); - } - } - } - - private void mergeOfflineDatabaseFiles(@NonNull final File file, @NonNull final MergeOfflineRegionsCallback callback, - final boolean isTemporaryFile) { - fileSource.activate(); - mergeOfflineRegions(fileSource, file.getAbsolutePath(), new MergeOfflineRegionsCallback() { - @Override - public void onMerge(final OfflineRegion[] offlineRegions) { - if (isTemporaryFile) { - file.delete(); - } - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - callback.onMerge(offlineRegions); - } - }); - } - - @Override - public void onError(final String error) { - if (isTemporaryFile) { - file.delete(); - } - handler.post(new Runnable() { - @Override - public void run() { - fileSource.deactivate(); - callback.onError(error); - } - }); - } - }); - } - - /** - * Creates an offline region in the database by downloading the resources needed to use - * the given region offline. - * <p> - * As of version 8.3.0 of the Maps SDK for Android, offline tile requests are no longer exempt from - * billing on mobile. Developers are subject to separate Vector Tile or Raster Tile API pricing for - * offline use. See <a href="https://www.mapbox.com/pricing/">our pricing page</a> for more information. - * </p> - * <p> - * When the initial database queries have completed, the provided callback will be - * executed on the main thread. - * </p> - * <p> - * Note that the resulting region will be in an inactive download state; to begin - * downloading resources, call `OfflineRegion.setDownloadState(DownloadState.STATE_ACTIVE)`, - * optionally registering an `OfflineRegionObserver` beforehand. - * </p> - * - * @param definition the offline region definition - * @param metadata the metadata in bytes - * @param callback the callback to be invoked - */ - public void createOfflineRegion(@NonNull OfflineRegionDefinition definition, @NonNull byte[] metadata, - @NonNull final CreateOfflineRegionCallback callback) { - if (!isValidOfflineRegionDefinition(definition)) { - callback.onError( - String.format(context.getString(R.string.mapbox_offline_error_region_definition_invalid), - definition.getBounds()) - ); - return; - } - - ConnectivityReceiver.instance(context).activate(); - FileSource.getInstance(context).activate(); - createOfflineRegion(fileSource, definition, metadata, new CreateOfflineRegionCallback() { - - @Override - public void onCreate(final OfflineRegion offlineRegion) { - handler.post(new Runnable() { - @Override - public void run() { - ConnectivityReceiver.instance(context).deactivate(); - FileSource.getInstance(context).deactivate(); - callback.onCreate(offlineRegion); - } - }); - } - - @Override - public void onError(final String error) { - handler.post(new Runnable() { - @Override - public void run() { - ConnectivityReceiver.instance(context).deactivate(); - FileSource.getInstance(context).deactivate(); - callback.onError(error); - } - }); - } - }); - - TelemetryDefinition telemetry = Mapbox.getTelemetry(); - if (telemetry != null) { - LatLngBounds bounds = definition.getBounds(); - telemetry.onCreateOfflineRegion(definition); - } - } - - /** - * Validates if the offline region definition bounds is valid for an offline region download. - * - * @param definition the offline region definition - * @return true if the region fits the world bounds. - */ - private boolean isValidOfflineRegionDefinition(OfflineRegionDefinition definition) { - return LatLngBounds.world().contains(definition.getBounds()); - } - - /** - * Sets the maximum number of Mapbox-hosted tiles that may be downloaded and stored on the current device. - * By default, the limit is set to 6,000. - * <p> - * Once this limit is reached, {@link OfflineRegion.OfflineRegionObserver#mapboxTileCountLimitExceeded(long)} - * fires every additional attempt to download additional tiles until already downloaded tiles are removed - * by calling {@link OfflineRegion#delete(OfflineRegion.OfflineRegionDeleteCallback)}. - * </p> - * - * @param limit the maximum number of tiles allowed to be downloaded - */ - @Keep - public native void setOfflineMapboxTileCountLimit(long limit); - - /** - * Sets whether database file packing occurs automatically. - * By default, the automatic database file packing is enabled. - * <p> - * If packing is enabled, database file packing occurs automatically - * after an offline region is deleted by calling - * {@link OfflineRegion#delete(OfflineRegion.OfflineRegionDeleteCallback)} - * or the ambient cache is cleared by calling {@link OfflineManager#clearAmbientCache()}. - * - * If packing is disabled, disk space will not be freed after - * resources are removed unless {@link OfflineManager#packDatabase()} is explicitly called. - * </p> - * - * @param autopack flag setting the automatic database file packing. - */ - @Keep - public native void runPackDatabaseAutomatically(boolean autopack); - - @Keep - private native void initialize(FileSource fileSource); - - @Override - @Keep - protected native void finalize() throws Throwable; - - @Keep - private native void listOfflineRegions(FileSource fileSource, ListOfflineRegionsCallback callback); - - @Keep - private native void createOfflineRegion(FileSource fileSource, OfflineRegionDefinition definition, - byte[] metadata, CreateOfflineRegionCallback callback); - - @Keep - private native void mergeOfflineRegions(FileSource fileSource, String path, MergeOfflineRegionsCallback callback); - - @Keep - private native void nativeResetDatabase(@Nullable FileSourceCallback callback); - - @Keep - private native void nativePackDatabase(@Nullable FileSourceCallback callback); - - @Keep - private native void nativeInvalidateAmbientCache(@Nullable FileSourceCallback callback); - - @Keep - private native void nativeClearAmbientCache(@Nullable FileSourceCallback callback); - - @Keep - private native void nativeSetMaximumAmbientCacheSize(long size, @Nullable FileSourceCallback callback); - - /** - * Insert the provided resource into the ambient cache - * This method mimics the caching that would take place if the equivalent - * resource were requested in the process of map rendering. - * Use this method to pre-warm the cache with resources you know - * will be requested. - * <p> - * This call is asynchronous: the data may not be immediately available - * for in-progress requests, although subsequent requests should have - * access to the cached data. - * - * @param url The URL of the resource to insert - * @param data Response data to store for this resource. Data is expected to be uncompressed; - * internally, the cache will compress data as necessary. - * @param modified Optional "modified" response header, in seconds since 1970, or 0 if not set - * @param expires Optional "expires" response header, in seconds since 1970, or 0 if not set - * @param etag Optional "entity tag" response header - * @param mustRevalidate Indicates whether response can be used after it's stale - */ - @Keep - public native void putResourceWithUrl(String url, byte[] data, long modified, long expires, - String etag, boolean mustRevalidate); -} |