diff --git a/application/resources/src/main/java/org/videolan/resources/Constants.kt b/application/resources/src/main/java/org/videolan/resources/Constants.kt index e2b5bf591..d0108e2e5 100644 --- a/application/resources/src/main/java/org/videolan/resources/Constants.kt +++ b/application/resources/src/main/java/org/videolan/resources/Constants.kt @@ -27,6 +27,7 @@ const val EXTRA_FIRST_RUN = "extra_first_run" const val EXTRA_UPGRADE = "extra_upgrade" const val EXTRA_PARSE = "extra_parse" const val EXTRA_TARGET = "extra_parse" +const val EXTRA_REMOVE_DEVICE = "extra_remove_device" //UI Navigation const val ID_VIDEO = "video" diff --git a/application/resources/src/main/java/org/videolan/resources/util/Extensions.kt b/application/resources/src/main/java/org/videolan/resources/util/Extensions.kt index b6507acc4..110682426 100644 --- a/application/resources/src/main/java/org/videolan/resources/util/Extensions.kt +++ b/application/resources/src/main/java/org/videolan/resources/util/Extensions.kt @@ -36,7 +36,7 @@ suspend inline fun Context.getFromMl(crossinline block: Medialibrary } } -fun Context.startMedialibrary(firstRun: Boolean = false, upgrade: Boolean = false, parse: Boolean = true, coroutineContextProvider: CoroutineContextProvider = CoroutineContextProvider()) = AppScope.launch { +fun Context.startMedialibrary(firstRun: Boolean = false, upgrade: Boolean = false, parse: Boolean = true, removeDevices:Boolean = false, coroutineContextProvider: CoroutineContextProvider = CoroutineContextProvider()) = AppScope.launch { if (Medialibrary.getInstance().isStarted || !canReadStorage(this@startMedialibrary)) return@launch val prefs = withContext(coroutineContextProvider.IO) { Settings.getInstance(this@startMedialibrary) } val scanOpt = if (Settings.showTvUi) ML_SCAN_ON else prefs.getInt(KEY_MEDIALIBRARY_SCAN, -1) @@ -47,6 +47,7 @@ fun Context.startMedialibrary(firstRun: Boolean = false, upgrade: Boolean = fals ContextCompat.startForegroundService(this@startMedialibrary, intent .putExtra(EXTRA_FIRST_RUN, firstRun) .putExtra(EXTRA_UPGRADE, upgrade) + .putExtra(EXTRA_REMOVE_DEVICE, removeDevices) .putExtra(EXTRA_PARSE, parse && scanOpt != ML_SCAN_OFF)) } diff --git a/application/vlc-android/src/org/videolan/vlc/MediaParsingService.kt b/application/vlc-android/src/org/videolan/vlc/MediaParsingService.kt index f8bb28e18..e8f8d1601 100644 --- a/application/vlc-android/src/org/videolan/vlc/MediaParsingService.kt +++ b/application/vlc-android/src/org/videolan/vlc/MediaParsingService.kt @@ -173,7 +173,8 @@ class MediaParsingService : LifecycleService(), DevicesDiscoveryCb { ACTION_INIT -> { val upgrade = intent.getBooleanExtra(EXTRA_UPGRADE, false) val parse = intent.getBooleanExtra(EXTRA_PARSE, true) - setupMedialibrary(upgrade, parse) + val removeDevices = intent.getBooleanExtra(EXTRA_REMOVE_DEVICE, false) + setupMedialibrary(upgrade, parse, removeDevices) } ACTION_RELOAD -> actions.safeOffer(Reload(intent.getStringExtra(EXTRA_PATH))) ACTION_FORCE_RELOAD -> actions.safeOffer(ForceReload) @@ -239,22 +240,23 @@ class MediaParsingService : LifecycleService(), DevicesDiscoveryCb { else medialibrary.reload(path) } - private fun setupMedialibrary(upgrade: Boolean, parse: Boolean) { + private fun setupMedialibrary(upgrade: Boolean, parse: Boolean, removeDevices:Boolean) { if (medialibrary.isInitiated) { medialibrary.resumeBackgroundOperations() if (parse && !scanActivated) actions.safeOffer(StartScan(upgrade)) - } else actions.safeOffer(Init(upgrade, parse)) + } else actions.safeOffer(Init(upgrade, parse, removeDevices)) } - private suspend fun initMedialib(parse: Boolean, context: Context, shouldInit: Boolean, upgrade: Boolean) { - addDevices(context, parse) + private suspend fun initMedialib(parse: Boolean, context: Context, shouldInit: Boolean, upgrade: Boolean, removeDevices: Boolean) { + addDevices(context, parse, removeDevices) if (upgrade) medialibrary.forceParserRetry() medialibrary.start() if (parse) startScan(shouldInit, upgrade) else exitCommand() } - private suspend fun addDevices(context: Context, addExternal: Boolean) { + private suspend fun addDevices(context: Context, addExternal: Boolean, removeDevices: Boolean) { + if (removeDevices) medialibrary.deleteRemovableDevices() val devices = DirectoryRepository.getInstance(context).getMediaDirectories() val knownDevices = if (AndroidDevices.watchDevices) medialibrary.devices else null for (device in devices) { @@ -450,14 +452,14 @@ class MediaParsingService : LifecycleService(), DevicesDiscoveryCb { val initCode = medialibrary.init(context) if (initCode != Medialibrary.ML_INIT_ALREADY_INITIALIZED) { shouldInit = shouldInit or (initCode == Medialibrary.ML_INIT_DB_RESET) or (initCode == Medialibrary.ML_INIT_DB_CORRUPTED) - if (initCode != Medialibrary.ML_INIT_FAILED) initMedialib(action.parse, context, shouldInit, action.upgrade) + if (initCode != Medialibrary.ML_INIT_FAILED) initMedialib(action.parse, context, shouldInit, action.upgrade, action.removeDevices) else exitCommand() } else exitCommand() } } is StartScan -> { scanActivated = true - addDevices(this@MediaParsingService, true) + addDevices(this@MediaParsingService, addExternal = true, removeDevices = false) startScan(false, action.upgrade) } UpdateStorages -> updateStorages() @@ -513,7 +515,7 @@ fun Context.rescan() { private sealed class MLAction private class DiscoverStorage(val path: String) : MLAction() private class DiscoverFolder(val path: String) : MLAction() -private class Init(val upgrade: Boolean, val parse: Boolean) : MLAction() +private class Init(val upgrade: Boolean, val parse: Boolean, val removeDevices:Boolean) : MLAction() private class StartScan(val upgrade: Boolean) : MLAction() private object UpdateStorages : MLAction() private class Reload(val path: String?) : MLAction() diff --git a/application/vlc-android/src/org/videolan/vlc/StartActivity.kt b/application/vlc-android/src/org/videolan/vlc/StartActivity.kt index f51d77bc8..b53342d55 100644 --- a/application/vlc-android/src/org/videolan/vlc/StartActivity.kt +++ b/application/vlc-android/src/org/videolan/vlc/StartActivity.kt @@ -143,6 +143,7 @@ class StartActivity : FragmentActivity() { val upgrade = firstRun || savedVersionNumber != currentVersionNumber val tv = showTvUi() if (upgrade && (tv || !firstRun)) settings.putSingle(PREF_FIRST_RUN, currentVersionNumber) + val removeOldDevices = savedVersionNumber == 3028200 || savedVersionNumber == 3028100 // Route search query if (Intent.ACTION_SEARCH == action || ACTION_SEARCH_GMS == action) { intent.setClassName(applicationContext, if (tv) TV_SEARCH_ACTIVITY else MOBILE_SEARCH_ACTIVITY) @@ -157,7 +158,7 @@ class StartActivity : FragmentActivity() { val data = intent.data val path = data!!.path if (TextUtils.equals(path, "/$TV_CHANNEL_PATH_APP")) - startApplication(tv, firstRun, upgrade, 0) + startApplication(tv, firstRun, upgrade, 0, removeOldDevices) else if (TextUtils.equals(path, "/$TV_CHANNEL_PATH_VIDEO")) { val id = java.lang.Long.valueOf(data.getQueryParameter(TV_CHANNEL_QUERY_VIDEO_ID)!!) MediaUtils.openMediaNoUi(this, id) @@ -167,7 +168,7 @@ class StartActivity : FragmentActivity() { if (target == R.id.ml_menu_last_playlist) PlaybackService.loadLastAudio(this) else - startApplication(tv, firstRun, upgrade, target) + startApplication(tv, firstRun, upgrade, target, removeOldDevices) } FileUtils.copyLua(applicationContext, upgrade) FileUtils.copyHrtfs(applicationContext, upgrade) @@ -182,7 +183,7 @@ class StartActivity : FragmentActivity() { } } - private fun startApplication(tv: Boolean, firstRun: Boolean, upgrade: Boolean, target: Int) { + private fun startApplication(tv: Boolean, firstRun: Boolean, upgrade: Boolean, target: Int, removeDevices:Boolean = false) { val settings = Settings.getInstance(this@StartActivity) val onboarding = !tv && !settings.getBoolean(ONBOARDING_DONE_KEY, false) // Start Medialibrary from background to workaround Dispatchers.Main causing ANR @@ -195,7 +196,7 @@ class StartActivity : FragmentActivity() { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P && !awaitAppIsForegroung()) { return@launch } - this@StartActivity.startMedialibrary(firstRun, upgrade, true) + this@StartActivity.startMedialibrary(firstRun, upgrade, true, removeDevices) if (onboarding) settings.putSingle(ONBOARDING_DONE_KEY, true) } }.start() diff --git a/medialibrary/jni/AndroidMediaLibrary.cpp b/medialibrary/jni/AndroidMediaLibrary.cpp index 5f0cb88fc..ea93d5e32 100644 --- a/medialibrary/jni/AndroidMediaLibrary.cpp +++ b/medialibrary/jni/AndroidMediaLibrary.cpp @@ -78,6 +78,12 @@ AndroidMediaLibrary::isDeviceKnown(const std::string& uuid, const std::string& p return p_ml->isDeviceKnown(uuid, path, removable); } +bool +AndroidMediaLibrary::deleteRemovableDevices() +{ + return p_ml->deleteRemovableDevices(); +} + std::vector> AndroidMediaLibrary::devices() { diff --git a/medialibrary/jni/AndroidMediaLibrary.h b/medialibrary/jni/AndroidMediaLibrary.h index af42a72e6..29d65aa1f 100644 --- a/medialibrary/jni/AndroidMediaLibrary.h +++ b/medialibrary/jni/AndroidMediaLibrary.h @@ -33,6 +33,7 @@ public: medialibrary::InitializeResult initML(const std::string& dbPath, const std::string& thumbsPath); void start(); bool isDeviceKnown(const std::string& uuid, const std::string& path, bool removable); + bool deleteRemovableDevices(); void addDevice(const std::string& uuid, const std::string& path, bool removable); void clearDatabase(bool restorePlaylists); std::vector> devices(); diff --git a/medialibrary/jni/medialibrary.cpp b/medialibrary/jni/medialibrary.cpp index bbbfd3b2b..9d92d1f18 100644 --- a/medialibrary/jni/medialibrary.cpp +++ b/medialibrary/jni/medialibrary.cpp @@ -102,6 +102,14 @@ isDeviceKnown(JNIEnv* env, jobject thiz, jstring uuid, jstring storagePath, jboo return isNew; } +jboolean +deleteRemovableDevices(JNIEnv* env, jobject thiz) +{ + AndroidMediaLibrary *aml = MediaLibrary_getInstance(env, thiz); + jboolean isDeleted = aml->deleteRemovableDevices(); + return isDeleted; +} + jobjectArray devices(JNIEnv* env, jobject thiz) { @@ -2038,6 +2046,7 @@ static JNINativeMethod methods[] = { {"nativeClearDatabase", "(Z)V", (void*)clearDatabase }, {"nativeAddDevice", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)addDevice }, {"nativeIsDeviceKnown", "(Ljava/lang/String;Ljava/lang/String;Z)Z", (void*)isDeviceKnown }, + {"nativeDeleteRemovableDevices", "()Z", (void*)deleteRemovableDevices }, {"nativeDevices", "()[Ljava/lang/String;", (void*)devices }, {"nativeDiscover", "(Ljava/lang/String;)V", (void*)discover }, {"nativeRemoveEntryPoint", "(Ljava/lang/String;)V", (void*)removeEntryPoint }, diff --git a/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java b/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java index b92da91fd..0eca3dc92 100644 --- a/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java +++ b/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java @@ -121,6 +121,10 @@ public class MedialibraryImpl extends Medialibrary { return mIsInitiated && nativeIsDeviceKnown(VLCUtil.encodeVLCString(uuid), Tools.encodeVLCMrl(path), removable); } + public boolean deleteRemovableDevices() { + return mIsInitiated && nativeDeleteRemovableDevices(); + } + public void addDevice(@NonNull String uuid, @NonNull String path, boolean removable) { if (!mIsInitiated) return; nativeAddDevice(VLCUtil.encodeVLCString(uuid), Tools.encodeVLCMrl(path), removable); @@ -576,6 +580,7 @@ public class MedialibraryImpl extends Medialibrary { private native void nativeUnbanFolder(String path); private native void nativeAddDevice(String uuid, String path, boolean removable); private native boolean nativeIsDeviceKnown(String uuid, String path, boolean removable); + private native boolean nativeDeleteRemovableDevices(); private native String[] nativeDevices(); private native void nativeDiscover(String path); private native void nativeRemoveEntryPoint(String path); diff --git a/medialibrary/src/org/videolan/medialibrary/interfaces/Medialibrary.java b/medialibrary/src/org/videolan/medialibrary/interfaces/Medialibrary.java index dea5e3f2d..769c081c4 100644 --- a/medialibrary/src/org/videolan/medialibrary/interfaces/Medialibrary.java +++ b/medialibrary/src/org/videolan/medialibrary/interfaces/Medialibrary.java @@ -677,6 +677,7 @@ abstract public class Medialibrary { abstract public String[] getDevices(); abstract public void addDevice(@NonNull String uuid, @NonNull String path, boolean removable); abstract public boolean isDeviceKnown(@NonNull String uuid, @NonNull String path, boolean removable); + abstract public boolean deleteRemovableDevices(); abstract public void discover(@NonNull String path); abstract public void removeFolder(@NonNull String mrl); abstract public String[] getFoldersList(); diff --git a/medialibrary/src/org/videolan/medialibrary/stubs/StubMedialibrary.java b/medialibrary/src/org/videolan/medialibrary/stubs/StubMedialibrary.java index 03be5e817..a2ad387a2 100644 --- a/medialibrary/src/org/videolan/medialibrary/stubs/StubMedialibrary.java +++ b/medialibrary/src/org/videolan/medialibrary/stubs/StubMedialibrary.java @@ -67,6 +67,11 @@ public class StubMedialibrary extends Medialibrary { return false; } + @Override + public boolean deleteRemovableDevices() { + return false; + } + public void loadJsonData(String jsonContent) { dt.loadJsonData(jsonContent); reload();