diff options
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 |
commit | b7702995fc60bfe9d5c3ddcff8b38deca97d2ced (patch) | |
tree | 44de8cf84856f5d71cbb792de3d7f89941035fa7 /platform/android | |
parent | 3f7b70fdb0e40d0cbbaea17505878c72491e3cd2 (diff) | |
download | qtlocation-mapboxgl-b7702995fc60bfe9d5c3ddcff8b38deca97d2ced.tar.gz |
[android] when changing the resource path, recreate database instead of the whole FileSource
Diffstat (limited to 'platform/android')
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; |