summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2019-02-19 13:23:49 +0100
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2019-03-13 18:28:04 +0100
commitb7702995fc60bfe9d5c3ddcff8b38deca97d2ced (patch)
tree44de8cf84856f5d71cbb792de3d7f89941035fa7
parent3f7b70fdb0e40d0cbbaea17505878c72491e3cd2 (diff)
downloadqtlocation-mapboxgl-b7702995fc60bfe9d5c3ddcff8b38deca97d2ced.tar.gz
[android] when changing the resource path, recreate database instead of the whole FileSource
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java135
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt55
-rw-r--r--platform/android/src/file_source.cpp12
-rw-r--r--platform/android/src/file_source.hpp3
5 files changed, 121 insertions, 107 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
index 0d85be18a5..01ac098d16 100644
--- 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
@@ -8,7 +8,6 @@ import android.os.Looper;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.R;
@@ -134,14 +133,6 @@ public class OfflineManager {
deleteAmbientDatabase(this.context);
}
- /**
- * Clears the current instance of the offline manager.
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- public static void clear() {
- instance = null;
- }
-
private void deleteAmbientDatabase(final Context context) {
final String path = FileSource.getInternalCachePath(context) + File.separator + "mbgl-cache.db";
FileUtils.deleteFile(path);
@@ -461,17 +452,17 @@ public class OfflineManager {
* 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 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
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 8df527657c..5c70d23899 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
@@ -7,17 +7,16 @@ 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.FileUtils;
import com.mapbox.mapboxsdk.utils.ThreadUtils;
import java.io.File;
@@ -64,7 +63,7 @@ public class FileSource {
* resources cache database.
*/
@Keep
- public interface SetResourcesCachePathCallback {
+ public interface ResourcesCachePathChangeCallback {
/**
* Receives the new database path
@@ -117,7 +116,7 @@ public class FileSource {
// Reset stored cache path
SharedPreferences.Editor editor =
- context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
+ context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
editor.remove(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH).apply();
}
@@ -148,11 +147,11 @@ public class FileSource {
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) {
@@ -182,8 +181,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;
}
@@ -212,9 +211,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()
};
}
@@ -273,67 +272,66 @@ public class FileSource {
*/
public static void setResourcesCachePath(@NonNull Context context,
@NonNull final String path,
- @NonNull final SetResourcesCachePathCallback callback) {
-
+ @NonNull ResourcesCachePathChangeCallback callback) {
+ final String fileSourceActivatedMessage = "Cannot set path, file source is activated."
+ + " Make sure that the map or a resources download is not running.";
if (getInstance(context).isActivated()) {
- final String activatedMessage = "Cannot set path, file source is activated!";
- Logger.w(TAG, activatedMessage);
- callback.onError(activatedMessage);
+ Logger.w(TAG, fileSourceActivatedMessage);
+ callback.onError(fileSourceActivatedMessage);
+ } else if (path.equals(resourcesCachePath)) {
+ // no need to change the path
+ callback.onSuccess(path);
} 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);
- }
- });
- }
+ final WeakReference<Context> contextWeakReference = new WeakReference<>(context);
+ final WeakReference<ResourcesCachePathChangeCallback> callbackWeakReference = new WeakReference<>(callback);
+ new FileUtils.CheckFileWritePermissionTask(new FileUtils.OnCheckFileWritePermissionListener() {
+ @Override
+ public void onWritePermissionGranted() {
+ final Context context = contextWeakReference.get();
+ final ResourcesCachePathChangeCallback callback = callbackWeakReference.get();
+
+ if (callback == null) {
+ Logger.w(TAG, "Lost callback reference.");
+ return;
+ } else if (context == null) {
+ String lostContextMessage = "Lost context reference.";
+ Logger.w(TAG, lostContextMessage);
+ callback.onError(lostContextMessage);
+ return;
}
- }).start();
- }
+
+ // verify fileSource's activation again after the async task returns
+ if (getInstance(context).isActivated()) {
+ Logger.w(TAG, fileSourceActivatedMessage);
+ callback.onError(fileSourceActivatedMessage);
+ } else {
+ final SharedPreferences.Editor editor =
+ context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
+ editor.putString(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH, path);
+ editor.apply();
+ setResourcesCachePath(context, path);
+ callback.onSuccess(path);
+ }
+ }
+
+ @Override
+ public void onError() {
+ final ResourcesCachePathChangeCallback callback = callbackWeakReference.get();
+ if (callback != null) {
+ String message = "Path is not writable: " + path;
+ Logger.e(TAG, message);
+ callback.onError(message);
+ }
+ }
+ }).execute(new File(path));
}
}
private static void setResourcesCachePath(@NonNull Context context, @NonNull String path) {
resourcesCachePathLoaderLock.lock();
resourcesCachePath = path;
- reinitializeOfflineManager(context);
resourcesCachePathLoaderLock.unlock();
+ getInstance(context).setResourceCachePath(path);
}
private static boolean isPathWritable(String path) {
@@ -343,12 +341,6 @@ public class FileSource {
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();
@@ -397,6 +389,9 @@ public class FileSource {
public native void setResourceTransform(final ResourceTransformCallback callback);
@Keep
+ private native void setResourceCachePath(String path);
+
+ @Keep
private native void initialize(String accessToken, String cachePath, AssetManager assetManager);
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt
index 2c429e829d..75ea9f6970 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChangeResourcesCachePathActivity.kt
@@ -12,27 +12,36 @@ import android.widget.AdapterView
import android.widget.BaseAdapter
import android.widget.TextView
import android.widget.Toast
+import com.mapbox.mapboxsdk.log.Logger
+import com.mapbox.mapboxsdk.offline.OfflineManager
+import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_change_resources_cache_path.*
import java.io.File
class ChangeResourcesCachePathActivity : AppCompatActivity(),
- AdapterView.OnItemClickListener,
- FileSource.SetResourcesCachePathCallback {
+ AdapterView.OnItemClickListener,
+ FileSource.ResourcesCachePathChangeCallback {
- lateinit var adapter: PathAdapter
+ companion object {
+ private const val TAG = "Mbgl-ChangeResourcesCachePathActivity"
+ }
+
+ private lateinit var adapter: PathAdapter
+
+ private lateinit var offlineManager: OfflineManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_resources_cache_path)
- Thread(Runnable {
- adapter = PathAdapter(this, obtainFilesPaths(this))
- listView.adapter = adapter
- listView.emptyView = empty
- listView.onItemClickListener = this
- }).start()
+ adapter = PathAdapter(this, obtainExternalFilesPaths())
+ listView.adapter = adapter
+ listView.emptyView = empty
+ listView.onItemClickListener = this
+
+ offlineManager = OfflineManager.getInstance(this)
}
override fun onStart() {
@@ -55,23 +64,33 @@ class ChangeResourcesCachePathActivity : AppCompatActivity(),
override fun onSuccess(path: String?) {
listView.onItemClickListener = this
Toast.makeText(this, "New path: $path", Toast.LENGTH_LONG).show()
+
+ offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
+ override fun onList(offlineRegions: Array<out OfflineRegion>?) {
+ Logger.i(TAG, "Number of saved offline regions in the new path: ${offlineRegions?.size.toString()}")
+ }
+
+ override fun onError(error: String?) {
+ Logger.e(TAG, error)
+ }
+ })
}
- private fun obtainFilesPaths(context: Context): List<String> {
+ private fun Context.obtainExternalFilesPaths(): List<String> {
val paths = ArrayList<String>()
- paths.add(context.filesDir.absolutePath)
+ paths.add(this.filesDir.absolutePath)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- paths.addAll(obtainExternalFilesPathsKitKat(context))
+ paths.addAll(obtainExternalFilesPathsKitKat())
} else {
- paths.addAll(obtainExternalFilesPathsLegacy(context))
+ paths.addAll(obtainExternalFilesPathsLegacy())
}
paths.add("${File.separator}invalid${File.separator}cache${File.separator}path")
return paths
}
- private fun obtainExternalFilesPathsLegacy(context: Context): List<String> {
+ private fun Context.obtainExternalFilesPathsLegacy(): List<String> {
val postFix =
- "${File.separator}Android${File.separator}data${File.separator}${context.packageName}${File.separator}files"
+ "${File.separator}Android${File.separator}data${File.separator}${this.packageName}${File.separator}files"
val paths = ArrayList<String>()
val externalStorage = System.getenv("EXTERNAL_STORAGE")
val secondaryStorage = System.getenv("SECONDARY_STORAGE")
@@ -88,9 +107,9 @@ class ChangeResourcesCachePathActivity : AppCompatActivity(),
}
@TargetApi(Build.VERSION_CODES.KITKAT)
- private fun obtainExternalFilesPathsKitKat(context: Context): List<String> {
+ private fun Context.obtainExternalFilesPathsKitKat(): List<String> {
val paths = ArrayList<String>()
- val extDirs = context.getExternalFilesDirs(null)
+ val extDirs = this.getExternalFilesDirs(null)
for (dir in extDirs) {
if (dir != null) {
paths.add(dir.absolutePath)
@@ -105,12 +124,10 @@ class ChangeResourcesCachePathActivity : AppCompatActivity(),
return paths[position]
}
-
override fun getItemId(position: Int): Long {
return position.toLong()
}
-
override fun getCount(): Int {
return paths.size
}
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index daddd0b9cd..4cfb545b84 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -19,11 +19,12 @@ FileSource::FileSource(jni::JNIEnv& _env,
const jni::String& accessToken,
const jni::String& _cachePath,
const jni::Object<AssetManager>& assetManager) {
- mapbox::sqlite::setTempPath(jni::Make<std::string>(_env, _cachePath));
+ std::string path = jni::Make<std::string>(_env, _cachePath);
+ mapbox::sqlite::setTempPath(path);
// Create a core default file source
fileSource = std::make_unique<mbgl::DefaultFileSource>(
- jni::Make<std::string>(_env, _cachePath) + "/mbgl-offline.db",
+ path + DATABASE_FILE,
std::make_unique<AssetManagerFileSource>(_env, assetManager));
// Set access token
@@ -69,6 +70,12 @@ void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object<FileSo
}
}
+void FileSource::setResourceCachePath(jni::JNIEnv& env, const jni::String& path) {
+ std::string newPath = jni::Make<std::string>(env, path);
+ mapbox::sqlite::setTempPath(newPath);
+ fileSource->setResourceCachePath(newPath + DATABASE_FILE);
+}
+
void FileSource::resume(jni::JNIEnv&) {
if (!activationCounter) {
activationCounter = optional<int>(1) ;
@@ -129,6 +136,7 @@ void FileSource::registerNative(jni::JNIEnv& env) {
METHOD(&FileSource::setAccessToken, "setAccessToken"),
METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
METHOD(&FileSource::setResourceTransform, "setResourceTransform"),
+ METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"),
METHOD(&FileSource::resume, "activate"),
METHOD(&FileSource::pause, "deactivate"),
METHOD(&FileSource::isResumed, "isActivated")
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 572ac647b7..575702120e 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -39,6 +39,8 @@ public:
void setResourceTransform(jni::JNIEnv&, const jni::Object<FileSource::ResourceTransformCallback>&);
+ void setResourceCachePath(jni::JNIEnv&, const jni::String&);
+
void resume(jni::JNIEnv&);
void pause(jni::JNIEnv&);
@@ -52,6 +54,7 @@ public:
static void registerNative(jni::JNIEnv&);
private:
+ const std::string DATABASE_FILE = "/mbgl-offline.db";
optional<int> activationCounter;
std::unique_ptr<Actor<ResourceTransform>> resourceTransform;
std::unique_ptr<mbgl::DefaultFileSource> fileSource;