Merge pull request #652 from nitehu/fix/isUri

Updated custom cache location handling to remove isUri
This commit is contained in:
tzugen 2021-12-20 22:02:36 +01:00 committed by GitHub
commit d66de5955b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 54 deletions

View File

@ -38,7 +38,6 @@ import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.service.RxBus import org.moire.ultrasonic.service.RxBus
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.ErrorDialog import org.moire.ultrasonic.util.ErrorDialog
import org.moire.ultrasonic.util.FileUtil.defaultMusicDirectory
import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory
import org.moire.ultrasonic.util.InfoDialog import org.moire.ultrasonic.util.InfoDialog
import org.moire.ultrasonic.util.MediaSessionHandler import org.moire.ultrasonic.util.MediaSessionHandler
@ -50,7 +49,6 @@ import org.moire.ultrasonic.util.Storage
import org.moire.ultrasonic.util.TimeSpanPreference import org.moire.ultrasonic.util.TimeSpanPreference
import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat
import org.moire.ultrasonic.util.Util.toast import org.moire.ultrasonic.util.Util.toast
import org.moire.ultrasonic.util.isUri
import timber.log.Timber import timber.log.Timber
/** /**
@ -171,31 +169,36 @@ class SettingsFragment :
*/ */
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if ( if (
requestCode != SELECT_CACHE_ACTIVITY || requestCode == SELECT_CACHE_ACTIVITY &&
resultCode != Activity.RESULT_OK || resultCode == Activity.RESULT_OK &&
resultData == null resultData != null
) return ) {
val read = (resultData.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0 val read = (resultData.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
val write = (resultData.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0 val write = (resultData.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
val persist = (resultData.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0 val persist = (resultData.flags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0
if (!read || !write || !persist) { if (read && write && persist) {
ErrorDialog.Builder(context) if (resultData.data != null) {
.setMessage(R.string.settings_cache_location_error)
.show()
return
}
// The result data contains a URI for the document or directory that // The result data contains a URI for the document or directory that
// the user selected. // the user selected.
resultData.data?.also { uri -> val uri = resultData.data!!
// Perform operations on the document using its URI.
val contentResolver = UApp.applicationContext().contentResolver val contentResolver = UApp.applicationContext().contentResolver
contentResolver.takePersistableUriPermission(uri, RW_FLAG) contentResolver.takePersistableUriPermission(uri, RW_FLAG)
setCacheLocation(uri.toString()) setCacheLocation(uri.toString())
setupCacheLocationPreference()
return
}
}
ErrorDialog.Builder(context)
.setMessage(R.string.settings_cache_location_error)
.show()
}
if (Settings.cacheLocationUri == "") {
Settings.customCacheLocation = false
customCacheLocation?.isChecked = false
setupCacheLocationPreference()
} }
} }
@ -234,10 +237,15 @@ class SettingsFragment :
RxBus.themeChangedEventPublisher.onNext(Unit) RxBus.themeChangedEventPublisher.onNext(Unit)
} }
Constants.PREFERENCES_KEY_CUSTOM_CACHE_LOCATION -> { Constants.PREFERENCES_KEY_CUSTOM_CACHE_LOCATION -> {
if (Settings.customCacheLocation) {
selectCacheLocation()
} else {
if (Settings.cacheLocationUri != "") setCacheLocation("")
setupCacheLocationPreference() setupCacheLocationPreference()
} }
} }
} }
}
override fun onDisplayPreferenceDialog(preference: Preference) { override fun onDisplayPreferenceDialog(preference: Preference) {
var dialogFragment: DialogFragment? = null var dialogFragment: DialogFragment? = null
@ -259,34 +267,32 @@ class SettingsFragment :
} }
private fun setupCacheLocationPreference() { private fun setupCacheLocationPreference() {
val isDefault = Settings.cacheLocation == defaultMusicDirectory.path
if (!Settings.customCacheLocation) { if (!Settings.customCacheLocation) {
cacheLocation?.isVisible = false cacheLocation?.isVisible = false
if (!isDefault) setCacheLocation(defaultMusicDirectory.path)
return return
} }
cacheLocation?.isVisible = true cacheLocation?.isVisible = true
val uri = Uri.parse(Settings.cacheLocation) val uri = Uri.parse(Settings.cacheLocationUri)
cacheLocation!!.summary = uri.path cacheLocation!!.summary = uri.path
cacheLocation!!.onPreferenceClickListener = cacheLocation!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
Preference.OnPreferenceClickListener { selectCacheLocation()
true
}
}
private fun selectCacheLocation() {
// Choose a directory using the system's file picker. // Choose a directory using the system's file picker.
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
if (!isDefault && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Settings.cacheLocationUri != "" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, defaultMusicDirectory.path) intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Settings.cacheLocationUri)
} }
intent.addFlags(RW_FLAG) intent.addFlags(RW_FLAG)
intent.addFlags(PERSISTABLE_FLAG) intent.addFlags(PERSISTABLE_FLAG)
startActivityForResult(intent, SELECT_CACHE_ACTIVITY) startActivityForResult(intent, SELECT_CACHE_ACTIVITY)
true
}
} }
private fun setupBluetoothDevicePreferences() { private fun setupBluetoothDevicePreferences() {
@ -393,7 +399,6 @@ class SettingsFragment :
sharingDefaultExpiration!!.summary = sharingDefaultExpiration!!.text sharingDefaultExpiration!!.summary = sharingDefaultExpiration!!.text
sharingDefaultDescription!!.summary = sharingDefaultDescription!!.text sharingDefaultDescription!!.summary = sharingDefaultDescription!!.text
sharingDefaultGreeting!!.summary = sharingDefaultGreeting!!.text sharingDefaultGreeting!!.summary = sharingDefaultGreeting!!.text
cacheLocation!!.summary = Settings.cacheLocation
if (!mediaButtonsEnabled!!.isChecked) { if (!mediaButtonsEnabled!!.isChecked) {
lockScreenEnabled!!.isChecked = false lockScreenEnabled!!.isChecked = false
lockScreenEnabled!!.isEnabled = false lockScreenEnabled!!.isEnabled = false
@ -438,15 +443,16 @@ class SettingsFragment :
} }
private fun setCacheLocation(path: String) { private fun setCacheLocation(path: String) {
if (path.isUri()) { if (path != "") {
val uri = Uri.parse(path) val uri = Uri.parse(path)
cacheLocation!!.summary = uri.path ?: "" cacheLocation!!.summary = uri.path ?: ""
} }
Settings.cacheLocation = path Settings.cacheLocationUri = path
// Clear download queue. // Clear download queue.
mediaPlayerControllerLazy.value.clear() mediaPlayerControllerLazy.value.clear()
mediaPlayerControllerLazy.value.clearCaches()
Storage.reset() Storage.reset()
} }

View File

@ -44,6 +44,7 @@ class Downloader(
private val jukeboxMediaPlayer: JukeboxMediaPlayer by inject() private val jukeboxMediaPlayer: JukeboxMediaPlayer by inject()
// This cache helps us to avoid creating duplicate DownloadFile instances when showing Entries
private val downloadFileCache = LRUCache<MusicDirectory.Entry, DownloadFile>(100) private val downloadFileCache = LRUCache<MusicDirectory.Entry, DownloadFile>(100)
private var executorService: ScheduledExecutorService? = null private var executorService: ScheduledExecutorService? = null
@ -281,6 +282,11 @@ class Downloader(
@Synchronized @Synchronized
fun getPlaylist(): List<DownloadFile> = playlist fun getPlaylist(): List<DownloadFile> = playlist
@Synchronized
fun clearDownloadFileCache() {
downloadFileCache.clear()
}
@Synchronized @Synchronized
fun clearPlaylist() { fun clearPlaylist() {
playlist.clear() playlist.clear()

View File

@ -280,6 +280,11 @@ class MediaPlayerController(
jukeboxMediaPlayer.updatePlaylist() jukeboxMediaPlayer.updatePlaylist()
} }
@Synchronized
fun clearCaches() {
downloader.clearDownloadFileCache()
}
@Synchronized @Synchronized
fun clearIncomplete() { fun clearIncomplete() {
reset() reset()

View File

@ -112,9 +112,8 @@ object Settings {
) )
@JvmStatic @JvmStatic
var cacheLocation by StringSetting( var cacheLocationUri by StringSetting(
Constants.PREFERENCES_KEY_CACHE_LOCATION, Constants.PREFERENCES_KEY_CACHE_LOCATION, ""
FileUtil.defaultMusicDirectory.path
) )
@JvmStatic @JvmStatic

View File

@ -31,7 +31,8 @@ object Storage {
Timber.i("StorageFile caches were reset") Timber.i("StorageFile caches were reset")
val root = getRoot() val root = getRoot()
if (root == null) { if (root == null) {
Settings.cacheLocation = FileUtil.defaultMusicDirectory.path Settings.customCacheLocation = false
Settings.cacheLocationUri = ""
Util.toast(UApp.applicationContext(), R.string.settings_cache_location_error) Util.toast(UApp.applicationContext(), R.string.settings_cache_location_error)
} }
} }
@ -70,22 +71,16 @@ object Storage {
} }
private fun getRoot(): AbstractFile? { private fun getRoot(): AbstractFile? {
return if (Settings.cacheLocation.isUri()) { return if (Settings.customCacheLocation) {
val documentFile = DocumentFile.fromTreeUri( val documentFile = DocumentFile.fromTreeUri(
UApp.applicationContext(), UApp.applicationContext(),
Uri.parse(Settings.cacheLocation) Uri.parse(Settings.cacheLocationUri)
) ?: return null ) ?: return null
if (!documentFile.exists()) return null if (!documentFile.exists()) return null
StorageFile(null, documentFile.uri, documentFile.name!!, documentFile.isDirectory) StorageFile(null, documentFile.uri, documentFile.name!!, documentFile.isDirectory)
} else { } else {
val file = File(Settings.cacheLocation) val file = File(FileUtil.defaultMusicDirectory.path)
if (!file.exists()) return null
JavaFile(null, file) JavaFile(null, file)
} }
} }
} }
fun String.isUri(): Boolean {
// TODO is there a better way to tell apart a path and an URI?
return this.contains(':')
}