diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt index e2d08c794..4fef918b9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheExtractor.kt @@ -26,6 +26,7 @@ import androidx.core.database.getStringOrNull import androidx.core.database.sqlite.transaction import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.queryAll import org.oxycblt.auxio.util.requireBackgroundThread import java.io.File @@ -42,7 +43,12 @@ class CacheExtractor(private val context: Context) { private var shouldWriteCache = false fun init() { - cacheMap = CacheDatabase.getInstance(context).read() + try { + cacheMap = CacheDatabase.getInstance(context).read() + } catch (e: Exception) { + logE("Unable to load cache database.") + logE(e.stackTraceToString()) + } } /** @@ -55,16 +61,21 @@ class CacheExtractor(private val context: Context) { // If the entire library could not be loaded from the cache, we need to re-write it // with the new library. logD("Cache was invalidated during loading, rewriting") - CacheDatabase.getInstance(context).write(rawSongs) + try { + CacheDatabase.getInstance(context).write(rawSongs) + } catch (e: Exception) { + logE("Unable to save cache database.") + logE(e.stackTraceToString()) + } } } /** * Maybe copy a cached raw song into this instance, assuming that it has not changed - * since it was last saved. + * since it was last saved. Returns true if a song was loaded. */ fun populateFromCache(rawSong: Song.Raw): Boolean { - val map = requireNotNull(cacheMap) { "CacheExtractor was not properly initialized" } + val map = cacheMap ?: return false val cachedRawSong = map[rawSong.mediaStoreId] if (cachedRawSong != null && cachedRawSong.dateAdded == rawSong.dateAdded && cachedRawSong.dateModified == rawSong.dateModified) { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index f82086459..bfc4fcb1d 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -248,26 +248,32 @@ class PlaybackViewModel(application: Application) : // --- SAVE/RESTORE FUNCTIONS --- - /** Force save the current [PlaybackStateManager] state to the database. */ - fun savePlaybackState(onDone: () -> Unit) { + /** + * Force save the current [PlaybackStateManager] state to the database. [onDone] + * will be called with true if it was done, or false if an error occurred. + */ + fun savePlaybackState(onDone: (Boolean) -> Unit) { viewModelScope.launch { - playbackManager.saveState(PlaybackStateDatabase.getInstance(application)) - onDone() + val saved = playbackManager.saveState(PlaybackStateDatabase.getInstance(application)) + onDone(saved) } } - /** Wipe the saved playback state (if any). */ - fun wipePlaybackState(onDone: () -> Unit) { + /** + * Wipe the saved playback state (if any). [onDone] will be called with true if it was + * successfully done, or false if an error occurred. + */ + fun wipePlaybackState(onDone: (Boolean) -> Unit) { viewModelScope.launch { - playbackManager.wipeState(PlaybackStateDatabase.getInstance(application)) - onDone() + val wiped = playbackManager.wipeState(PlaybackStateDatabase.getInstance(application)) + onDone(wiped) } } /** * Force restore the last [PlaybackStateManager] saved state, regardless of if a library exists * or not. [onDone] will be called with true if it was successfully done, or false if there was - * no state or if a library was not present. + * no state, a library was not present, or there was an error. */ fun tryRestorePlaybackState(onDone: (Boolean) -> Unit) { viewModelScope.launch { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 8eb0f202a..7992a1d82 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -29,6 +29,7 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.state.PlaybackStateManager.Callback import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.logW import kotlin.math.max @@ -368,7 +369,13 @@ class PlaybackStateManager private constructor() { val library = musicStore.library ?: return false val internalPlayer = internalPlayer ?: return false - val state = withContext(Dispatchers.IO) { database.read(library) } + val state = try { + withContext(Dispatchers.IO) { database.read(library) } + } catch (e: Exception) { + logE("Unable to restore playback state.") + logE(e.stackTraceToString()) + return false + } synchronized(this) { if (state != null && (!isInitialized || force)) { @@ -397,15 +404,32 @@ class PlaybackStateManager private constructor() { } /** Save the current state to the [database]. */ - suspend fun saveState(database: PlaybackStateDatabase) { + suspend fun saveState(database: PlaybackStateDatabase): Boolean { logD("Saving state to DB") + val state = synchronized(this) { makeStateImpl() } - withContext(Dispatchers.IO) { database.write(state) } + return try { + withContext(Dispatchers.IO) { database.write(state) } + true + } catch (e: Exception) { + logE("Unable to save playback state.") + logE(e.stackTraceToString()) + false + } } - suspend fun wipeState(database: PlaybackStateDatabase) { + /** Wipe the current state. */ + suspend fun wipeState(database: PlaybackStateDatabase): Boolean { logD("Wiping state") - withContext(Dispatchers.IO) { database.write(null) } + + return try { + withContext(Dispatchers.IO) { database.write(null) } + true + } catch (e: Exception) { + logE("Unable to wipe playback state.") + logE(e.stackTraceToString()) + false + } } /** Sanitize the state with [newLibrary]. */ diff --git a/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt index 06ab07128..690448e5a 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt @@ -113,13 +113,21 @@ class PreferenceFragment : PreferenceFragmentCompat() { when (preference.key) { context.getString(R.string.set_key_save_state) -> { - playbackModel.savePlaybackState { - this.context?.showToast(R.string.lbl_state_saved) + playbackModel.savePlaybackState { saved -> + if (saved) { + this.context?.showToast(R.string.lbl_state_saved) + } else { + this.context?.showToast(R.string.err_did_not_save) + } } } context.getString(R.string.set_key_wipe_state) -> { - playbackModel.wipePlaybackState { - this.context?.showToast(R.string.lbl_state_wiped) + playbackModel.wipePlaybackState { wiped -> + if (wiped) { + this.context?.showToast(R.string.lbl_state_wiped) + } else { + this.context?.showToast(R.string.err_did_not_wipe) + } } } context.getString(R.string.set_key_restore_state) -> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a369b11f5..6c31654e1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -251,7 +251,11 @@ No folders This folder is not supported - No state could be restored + Unable to restore state + + Unable to clear state + + Unable to save state