summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java190
1 files changed, 161 insertions, 29 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
index d3dba6f90c..8df527657c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -1,26 +1,30 @@
package com.mapbox.mapboxsdk.storage;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.os.Environment;
+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.MapStrictMode;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.log.Logger;
+import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.utils.ThreadUtils;
+import java.io.File;
+import java.lang.ref.WeakReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import com.mapbox.mapboxsdk.log.Logger;
-
/**
* Holds a central reference to the core's DefaultFileSource for as long as
* there are active mapviews / offline managers
@@ -28,6 +32,8 @@ import com.mapbox.mapboxsdk.log.Logger;
public class FileSource {
private static final String TAG = "Mbgl-FileSource";
+ private static final String MAPBOX_SHARED_PREFERENCES = "MapboxSharedPreferences";
+ private static final String MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH = "fileSourceResourcesCachePath";
private static final Lock resourcesCachePathLoaderLock = new ReentrantLock();
private static final Lock internalCachePathLoaderLock = new ReentrantLock();
@Nullable
@@ -53,6 +59,29 @@ public class FileSource {
}
+ /**
+ * This callback receives an asynchronous response containing the new path of the
+ * resources cache database.
+ */
+ @Keep
+ public interface SetResourcesCachePathCallback {
+
+ /**
+ * Receives the new database path
+ *
+ * @param path the path of the current resources cache database
+ */
+ void onSuccess(String path);
+
+ /**
+ * Receives an error message if setting the path was not successful
+ *
+ * @param message the error message
+ */
+ void onError(String message);
+
+ }
+
// File source instance is kept alive after initialization
private static FileSource INSTANCE;
@@ -79,17 +108,51 @@ public class FileSource {
*/
@NonNull
private static String getCachePath(@NonNull Context context) {
+ SharedPreferences preferences = context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ String cachePath = preferences.getString(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH, null);
+
+ if (!isPathWritable(cachePath)) {
+ // Use default path
+ cachePath = getDefaultCachePath(context);
+
+ // Reset stored cache path
+ SharedPreferences.Editor editor =
+ context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
+ editor.remove(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH).apply();
+ }
+
+ return cachePath;
+ }
+
+ /**
+ * Get the default resources cache path depending on the external storage configuration
+ *
+ * @param context the context to derive the files directory path from
+ * @return the default directory path
+ */
+ @NonNull
+ private static String getDefaultCachePath(@NonNull Context context) {
+ if (isExternalStorageConfiguration(context) && isExternalStorageReadable()) {
+ File externalFilesDir = context.getExternalFilesDir(null);
+ if (externalFilesDir != null) {
+ return externalFilesDir.getAbsolutePath();
+ }
+ }
+ return context.getFilesDir().getAbsolutePath();
+ }
+
+ private static boolean isExternalStorageConfiguration(@NonNull Context context) {
// Default value
boolean isExternalStorageConfiguration = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
try {
// Try getting a custom value from the app Manifest
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(),
- PackageManager.GET_META_DATA);
+ PackageManager.GET_META_DATA);
if (appInfo.metaData != null) {
isExternalStorageConfiguration = appInfo.metaData.getBoolean(
- MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
- MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL
+ MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
+ MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL
);
}
} catch (PackageManager.NameNotFoundException exception) {
@@ -99,24 +162,7 @@ public class FileSource {
Logger.e(TAG, "Failed to read the storage key: ", exception);
MapStrictMode.strictModeViolation(exception);
}
-
- String cachePath = null;
- if (isExternalStorageConfiguration && isExternalStorageReadable()) {
- try {
- // Try getting the external storage path
- cachePath = context.getExternalFilesDir(null).getAbsolutePath();
- } catch (NullPointerException exception) {
- Logger.e(TAG, "Failed to obtain the external storage path: ", exception);
- MapStrictMode.strictModeViolation(exception);
- }
- }
-
- if (cachePath == null) {
- // Default to internal storage
- cachePath = context.getFilesDir().getAbsolutePath();
- }
-
- return cachePath;
+ return isExternalStorageConfiguration;
}
/**
@@ -136,8 +182,8 @@ public class FileSource {
}
Logger.w(TAG, "External storage was requested but it isn't readable. For API level < 18"
- + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
- + " permissions in your app Manifest (defaulting to internal storage).");
+ + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
+ + " permissions in your app Manifest (defaulting to internal storage).");
return false;
}
@@ -166,9 +212,9 @@ public class FileSource {
@NonNull
@Override
protected String[] doInBackground(Context... contexts) {
- return new String[] {
- getCachePath(contexts[0]),
- contexts[0].getCacheDir().getAbsolutePath()
+ return new String[]{
+ getCachePath(contexts[0]),
+ contexts[0].getCacheDir().getAbsolutePath()
};
}
@@ -217,6 +263,92 @@ public class FileSource {
}
}
+ /**
+ * Changes the path of the resources cache database.
+ * Note that the external storage setting needs to be activated in the manifest.
+ *
+ * @param context the context of the path
+ * @param path the new database path
+ * @param callback the callback to obtain the result
+ */
+ public static void setResourcesCachePath(@NonNull Context context,
+ @NonNull final String path,
+ @NonNull final SetResourcesCachePathCallback callback) {
+
+ if (getInstance(context).isActivated()) {
+ final String activatedMessage = "Cannot set path, file source is activated!";
+ Logger.w(TAG, activatedMessage);
+ callback.onError(activatedMessage);
+ } else {
+ if (path.equals(resourcesCachePath)) {
+ // no need to change the path
+ callback.onSuccess(path);
+ } else {
+ final WeakReference<Context> contextWeakReference = new WeakReference<>(context);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ final Context context = contextWeakReference.get();
+ final String message;
+ if (context != null) {
+ if (!isPathWritable(path)) {
+ message = "Path is not writable: " + path;
+ } else {
+ message = null;
+
+ final SharedPreferences.Editor editor =
+ context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
+ if (!editor.putString(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH, path).commit()) {
+ Logger.w(TAG, "Cannot store cache path in shared preferences.");
+ }
+
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ setResourcesCachePath(context, path);
+ callback.onSuccess(path);
+ }
+ });
+ }
+ } else {
+ message = "Context is null";
+ }
+
+ if (message != null) {
+ Logger.w(TAG, message);
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(message);
+ }
+ });
+ }
+ }
+ }).start();
+ }
+ }
+ }
+
+ private static void setResourcesCachePath(@NonNull Context context, @NonNull String path) {
+ resourcesCachePathLoaderLock.lock();
+ resourcesCachePath = path;
+ reinitializeOfflineManager(context);
+ resourcesCachePathLoaderLock.unlock();
+ }
+
+ private static boolean isPathWritable(String path) {
+ if (path == null || path.isEmpty()) {
+ return false;
+ }
+ return new File(path).canWrite();
+ }
+
+ private static void reinitializeOfflineManager(@NonNull Context context) {
+ final FileSource fileSource = FileSource.getInstance(context);
+ fileSource.initialize(Mapbox.getAccessToken(), resourcesCachePath, context.getResources().getAssets());
+ OfflineManager.clear();
+ }
+
private static void lockPathLoaders() {
internalCachePathLoaderLock.lock();
resourcesCachePathLoaderLock.lock();