From 82fb45bd55410caf3430ec7e245996b565982c17 Mon Sep 17 00:00:00 2001 From: birdbird <6892457-tzugen@users.noreply.gitlab.com> Date: Sun, 7 May 2023 15:23:57 +0000 Subject: [PATCH] Fix a bunch of Exceptions collected through Play Store reporting --- .../moire/ultrasonic/view/GenreAdapter.java | 2 +- .../fragment/TrackCollectionFragment.kt | 2 ++ .../fragment/legacy/SelectGenreFragment.kt | 4 ++- .../ultrasonic/imageloader/ImageLoader.kt | 2 ++ .../ultrasonic/subsonic/DownloadHandler.kt | 16 +++++++++- .../org/moire/ultrasonic/util/Dialogs.kt | 21 +++++++++----- .../org/moire/ultrasonic/util/StorageFile.kt | 2 +- .../kotlin/org/moire/ultrasonic/util/Util.kt | 29 +++++++++++-------- 8 files changed, 55 insertions(+), 23 deletions(-) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java index 475bb602..eeb1c48b 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java @@ -46,7 +46,7 @@ public class GenreAdapter extends ArrayAdapter implements SectionIndexer private final Object[] sections; private final Integer[] positions; - public GenreAdapter(Context context, List genres) + public GenreAdapter(@NonNull Context context, List genres) { super(context, R.layout.list_item_generic, genres); diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt index b67ec05b..6664f17e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt @@ -401,6 +401,8 @@ open class TrackCollectionFragment( ) { // We are coming back from unknown context // and need to ensure Main Thread in order to manipulate the UI + // If view is null, our view was disposed in the meantime + if (view == null) return viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { val multipleSelection = viewAdapter.hasMultipleSelection() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/legacy/SelectGenreFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/legacy/SelectGenreFragment.kt index 31790ef3..0a876b45 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/legacy/SelectGenreFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/legacy/SelectGenreFragment.kt @@ -102,7 +102,9 @@ class SelectGenreFragment : Fragment() { override fun done(result: List) { emptyView!!.isVisible = result.isEmpty() - genreListView!!.adapter = GenreAdapter(context, result) + if (context != null) { + genreListView!!.adapter = GenreAdapter(context!!, result) + } } } task.execute() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt index c814eeec..06bc30ff 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ImageLoader.kt @@ -240,6 +240,8 @@ class ImageLoader( } finally { inputStream.safeClose() } + } catch (all: Exception) { + Timber.w(all) } finally { cacheInProgress.remove(file)?.countDown() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt index 286ce8f2..ce14c811 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/DownloadHandler.kt @@ -7,11 +7,14 @@ package org.moire.ultrasonic.subsonic +import android.os.Handler +import android.os.Looper import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import java.util.Collections import java.util.LinkedList import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -28,6 +31,7 @@ import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator import org.moire.ultrasonic.util.InfoDialog import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Util +import timber.log.Timber /** * Retrieves a list of songs and adds them to the now playing list @@ -39,6 +43,16 @@ class DownloadHandler( ) : CoroutineScope by CoroutineScope(Dispatchers.IO) { private val maxSongs = 500 + /** + * Exception Handler for Coroutines + */ + val exceptionHandler = CoroutineExceptionHandler { _, exception -> + Handler(Looper.getMainLooper()).post { + Timber.w(exception) + } + } + + // TODO: Use coroutine here (with proper exception handler) fun download( fragment: Fragment, append: Boolean, @@ -210,7 +224,7 @@ class DownloadHandler( isArtist: Boolean ) { // Launch the Job - val job = launch { + val job = launch(exceptionHandler) { val songs: MutableList = getTracksFromServer(isArtist, id, isDirectory, name, isShare) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Dialogs.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Dialogs.kt index a33dae82..7988dc3c 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Dialogs.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Dialogs.kt @@ -10,7 +10,9 @@ package org.moire.ultrasonic.util import android.app.Activity import android.content.Context import com.google.android.material.dialog.MaterialAlertDialogBuilder +import java.lang.ref.WeakReference import org.moire.ultrasonic.R +import timber.log.Timber /* * InfoDialog can be used to show some information to the user. Typically it cannot be cancelled, @@ -19,24 +21,30 @@ import org.moire.ultrasonic.R open class InfoDialog( context: Context, message: CharSequence?, - private val activity: Activity? = null, + activity: Activity? = null, private val finishActivityOnClose: Boolean = false ) { - - open var builder: MaterialAlertDialogBuilder = Builder(activity ?: context, message) + private val activityRef: WeakReference = WeakReference(activity) + open var builder: MaterialAlertDialogBuilder = Builder(activityRef.get() ?: context, message) fun show() { builder.setOnCancelListener { if (finishActivityOnClose) { - activity!!.finish() + activityRef.get()?.finish() } } builder.setPositiveButton(R.string.common_ok) { _, _ -> if (finishActivityOnClose) { - activity!!.finish() + activityRef.get()?.finish() } } - builder.create().show() + + // If the app was put into the background in the meantime this would fail + try { + builder.create().show() + } catch (all: Exception) { + Timber.w(all, "Failed to create dialog") + } } class Builder(context: Context) : MaterialAlertDialogBuilder(context) { @@ -93,7 +101,6 @@ class ConfirmationDialog( activity: Activity? = null, finishActivityOnClose: Boolean = false ) : InfoDialog(context, message, activity, finishActivityOnClose) { - override var builder: MaterialAlertDialogBuilder = Builder(activity ?: context, message) class Builder(context: Context) : MaterialAlertDialogBuilder(context) { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/StorageFile.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/StorageFile.kt index 09b12f3c..5d1eb983 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/StorageFile.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/StorageFile.kt @@ -273,7 +273,7 @@ class StorageFile( } private fun getStorageFileForParentDirectory(path: String): StorageFile? { - val parentPath = FileUtil.getParentPath(path)!! + val parentPath = FileUtil.getParentPath(path) ?: return null if (storageFilePathDictionary.containsKey(parentPath)) return storageFilePathDictionary[parentPath]!! if (notExistingPathDictionary.contains(parentPath)) return null diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt index cdcd5443..b9f2368f 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt @@ -133,19 +133,24 @@ object Util { @JvmStatic @SuppressLint("ShowToast") // Invalid warning fun toast(context: Context?, message: CharSequence?, shortDuration: Boolean) { - if (toast == null) { - toast = Toast.makeText( - context, - message, - if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG - ) - toast!!.setGravity(Gravity.CENTER, 0, 0) - } else { - toast!!.setText(message) - toast!!.duration = - if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG + // If called after doing some background processing, our context might have expired! + try { + if (toast == null) { + toast = Toast.makeText( + context, + message, + if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG + ) + toast!!.setGravity(Gravity.CENTER, 0, 0) + } else { + toast!!.setText(message) + toast!!.duration = + if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG + } + toast!!.show() + } catch (_: Exception) { + // Ignore } - toast!!.show() } /**