From f8f888ccad1ad127cb5f111b4ebc95dd70317f08 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Wed, 12 Oct 2022 11:48:49 +0000 Subject: [PATCH] Fix crashes --- .../ultrasonic/activity/NavigationActivity.kt | 20 ++-- .../ultrasonic/fragment/PlayerFragment.kt | 9 +- .../ultrasonic/service/DownloadService.kt | 23 +++- .../moire/ultrasonic/service/DownloadTask.kt | 103 ++++++++---------- 4 files changed, 79 insertions(+), 76 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index ee625720..6206816e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -22,7 +22,6 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ImageView -import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat @@ -221,8 +220,6 @@ class NavigationActivity : AppCompatActivity() { cachedServerCount = count ?: 0 updateNavigationHeaderForServer() } - - onBackPressedDispatcher.addCallback(this, callback) } override fun onResume() { @@ -340,16 +337,13 @@ class NavigationActivity : AppCompatActivity() { setupActionBarWithNavController(navController, appBarConfig) } - val callback: OnBackPressedCallback = object : OnBackPressedCallback( - true - ) { - override fun handleOnBackPressed() { - if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true) { - drawerLayout?.closeDrawer(GravityCompat.START) - } else { - val currentFragment = host!!.childFragmentManager.fragments.last() - if (currentFragment is OnBackPressedHandler) currentFragment.onBackPressed() - } + override fun onBackPressed() { + if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true) { + this.drawerLayout?.closeDrawer(GravityCompat.START) + } else { + val currentFragment = host!!.childFragmentManager.fragments.last() + if (currentFragment is OnBackPressedHandler) currentFragment.onBackPressed() + else super.onBackPressed() } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt index 6881fe95..6a79f080 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -775,11 +775,12 @@ class PlayerFragment : Util.toast(context, resources.getString(R.string.download_playlist_saving, playlistName)) mediaPlayerController.suggestedPlaylistName = playlistName - ioScope.launch { + // The playlist can be acquired only from the main thread + val entries = mediaPlayerController.playlist.map { + it.toTrack() + } - val entries = mediaPlayerController.playlist.map { - it.toTrack() - } + ioScope.launch { val musicService = getMusicService() musicService.createPlaylist(null, playlistName, entries) }.invokeOnCompletion { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt index d473bc54..91f19fed 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt @@ -266,7 +266,7 @@ class DownloadService : Service(), KoinComponent { return notificationBuilder.build() } - @Suppress("MagicNumber") + @Suppress("MagicNumber", "NestedBlockDepth") companion object { private var startFuture: SettableFuture? = null @@ -291,7 +291,12 @@ class DownloadService : Service(), KoinComponent { if (save) { tracks.filter { Storage.isPathExists(it.getCompleteFile()) }.forEach { track -> Storage.getFromPath(track.getCompleteFile())?.let { - Storage.rename(it, track.getPinnedFile()) + try { + Storage.rename(it, track.getPinnedFile()) + } catch (ignored: FileAlreadyExistsException) { + // Play console has revealed a crash when for some reason both files exist + Storage.delete(it.path) + } postState(track, DownloadState.PINNED) } } @@ -299,7 +304,12 @@ class DownloadService : Service(), KoinComponent { } else { tracks.filter { Storage.isPathExists(it.getPinnedFile()) }.forEach { track -> Storage.getFromPath(track.getPinnedFile())?.let { - Storage.rename(it, track.getCompleteFile()) + try { + Storage.rename(it, track.getCompleteFile()) + } catch (ignored: FileAlreadyExistsException) { + // Play console has revealed a crash when for some reason both files exist + Storage.delete(it.path) + } postState(track, DownloadState.DONE) } } @@ -367,7 +377,12 @@ class DownloadService : Service(), KoinComponent { val pinnedFile = track.getPinnedFile() if (!Storage.isPathExists(pinnedFile)) return val file = Storage.getFromPath(track.getPinnedFile()) ?: return - Storage.rename(file, track.getCompleteFile()) + try { + Storage.rename(file, track.getCompleteFile()) + } catch (ignored: FileAlreadyExistsException) { + // Play console has revealed a crash when for some reason both files exist + Storage.delete(file.path) + } postState(track, DownloadState.DONE) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt index a192f598..883e8816 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt @@ -81,73 +81,66 @@ class DownloadTask( stateChangedCallback(item, DownloadState.DOWNLOADING, null) - // Some devices seem to throw error on partial file which doesn't exist - val needsDownloading: Boolean - val duration = item.track.duration val fileLength = Storage.getFromPath(item.partialFile)?.length ?: 0 - needsDownloading = (duration == null || duration == 0 || fileLength == 0L) + // Attempt partial HTTP GET, appending to the file if it exists. + val (inStream, isPartial) = musicService.getDownloadInputStream( + item.track, fileLength, + Settings.maxBitRate, + item.pinned + ) - if (needsDownloading) { - // Attempt partial HTTP GET, appending to the file if it exists. - val (inStream, isPartial) = musicService.getDownloadInputStream( - item.track, fileLength, - Settings.maxBitRate, - item.pinned - ) + inputStream = inStream - inputStream = inStream + if (isPartial) { + Timber.i("Executed partial HTTP GET, skipping %d bytes", fileLength) + } - if (isPartial) { - Timber.i("Executed partial HTTP GET, skipping %d bytes", fileLength) - } + outputStream = Storage.getOrCreateFileFromPath(item.partialFile) + .getFileOutputStream(isPartial) - outputStream = Storage.getOrCreateFileFromPath(item.partialFile) - .getFileOutputStream(isPartial) + var lastPostTime: Long = 0 + val len = inputStream.copyTo(outputStream) { totalBytesCopied -> + // Manual throttling to avoid overloading Rx + if (SystemClock.elapsedRealtime() - lastPostTime > REFRESH_INTERVAL) { + lastPostTime = SystemClock.elapsedRealtime() - var lastPostTime: Long = 0 - val len = inputStream.copyTo(outputStream) { totalBytesCopied -> - // Manual throttling to avoid overloading Rx - if (SystemClock.elapsedRealtime() - lastPostTime > REFRESH_INTERVAL) { - lastPostTime = SystemClock.elapsedRealtime() - - // If the file size is unknown we can only provide null as the progress - val size = item.track.size ?: 0 - val progress = if (size <= 0) { - null - } else { - (totalBytesCopied * 100 / (size)).toInt() - } - - stateChangedCallback( - item, - DownloadState.DOWNLOADING, - progress - ) + // If the file size is unknown we can only provide null as the progress + val size = item.track.size ?: 0 + val progress = if (size <= 0) { + null + } else { + (totalBytesCopied * 100 / (size)).toInt() } - } - Timber.i("Downloaded %d bytes to %s", len, item.partialFile) - - inputStream.close() - outputStream.flush() - outputStream.close() - - if (isCancelled) { - stateChangedCallback(item, DownloadState.CANCELLED, null) - throw RuntimeException( - String.format( - Locale.ROOT, "Download of '%s' was cancelled", - item - ) + stateChangedCallback( + item, + DownloadState.DOWNLOADING, + progress ) } + } - try { - item.track.cacheMetadataAndArtwork() - } catch (ignore: Exception) { - Timber.w(ignore) - } + Timber.i("Downloaded %d bytes to %s", len, item.partialFile) + + inputStream.close() + outputStream.flush() + outputStream.close() + + if (isCancelled) { + stateChangedCallback(item, DownloadState.CANCELLED, null) + throw RuntimeException( + String.format( + Locale.ROOT, "Download of '%s' was cancelled", + item + ) + ) + } + + try { + item.track.cacheMetadataAndArtwork() + } catch (ignore: Exception) { + Timber.w(ignore) } if (item.pinned) {