From 1ed9360bc7b35f74113bc25200414b45c909f20c Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 13 Nov 2021 13:43:41 +0100 Subject: [PATCH] CommunicationError to Object with static methods --- .../moire/ultrasonic/util/BackgroundTask.java | 5 +- .../ultrasonic/fragment/GenericListModel.kt | 4 +- .../ultrasonic/fragment/PlayerFragment.kt | 26 ++--- .../fragment/TrackCollectionFragment.kt | 4 +- .../service/CommunicationErrorUtil.kt | 104 ------------------ .../ultrasonic/util/CommunicationError.kt | 91 +++++++++++++++ 6 files changed, 110 insertions(+), 124 deletions(-) delete mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/CommunicationErrorUtil.kt create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/CommunicationError.kt diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/BackgroundTask.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/BackgroundTask.java index 73fb2ff2..8ae51dee 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/BackgroundTask.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/BackgroundTask.java @@ -20,7 +20,6 @@ package org.moire.ultrasonic.util; import android.app.Activity; import android.os.Handler; -import org.moire.ultrasonic.service.CommunicationErrorUtil; /** * @author Sindre Mehus @@ -54,12 +53,12 @@ public abstract class BackgroundTask implements ProgressListener protected void error(Throwable error) { - CommunicationErrorUtil.Companion.handleError(error, activity); + CommunicationError.handleError(error, activity); } protected String getErrorMessage(Throwable error) { - return CommunicationErrorUtil.Companion.getErrorMessage(error, activity); + return CommunicationError.getErrorMessage(error, activity); } @Override diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericListModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericListModel.kt index c1e5cc40..5ec1db0e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericListModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/GenericListModel.kt @@ -18,9 +18,9 @@ import org.koin.core.component.inject import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ServerSetting import org.moire.ultrasonic.domain.MusicFolder -import org.moire.ultrasonic.service.CommunicationErrorUtil import org.moire.ultrasonic.service.MusicService import org.moire.ultrasonic.service.MusicServiceFactory +import org.moire.ultrasonic.util.CommunicationError import org.moire.ultrasonic.util.Settings /** @@ -94,7 +94,7 @@ open class GenericListModel(application: Application) : private fun handleException(exception: Exception, context: Context) { Handler(Looper.getMainLooper()).post { - CommunicationErrorUtil.handleError(exception, context) + CommunicationError.handleError(exception, context) } } 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 7c879a6b..d20f7cc5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -46,6 +46,7 @@ import java.util.ArrayList import java.util.Date import java.util.LinkedList import java.util.Locale +import java.util.concurrent.CancellationException import java.util.concurrent.Executors import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit @@ -67,7 +68,6 @@ import org.moire.ultrasonic.domain.RepeatMode import org.moire.ultrasonic.featureflags.Feature import org.moire.ultrasonic.featureflags.FeatureStorage import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle -import org.moire.ultrasonic.service.CommunicationErrorUtil import org.moire.ultrasonic.service.DownloadFile import org.moire.ultrasonic.service.LocalMediaPlayer import org.moire.ultrasonic.service.MediaPlayerController @@ -77,6 +77,7 @@ import org.moire.ultrasonic.subsonic.ImageLoaderProvider import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker import org.moire.ultrasonic.subsonic.ShareHandler import org.moire.ultrasonic.util.CancellationToken +import org.moire.ultrasonic.util.CommunicationError import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Util @@ -84,7 +85,6 @@ import org.moire.ultrasonic.view.AutoRepeatButton import org.moire.ultrasonic.view.SongListAdapter import org.moire.ultrasonic.view.VisualizerView import timber.log.Timber -import java.util.concurrent.CancellationException /** * Contains the Music Player screen of Ultrasonic with playback controls and the playlist @@ -236,7 +236,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon previousButton.setOnClickListener { networkAndStorageChecker.warnIfNetworkOrStorageUnavailable() - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.previous() onCurrentChanged() onSliderProgressChanged() @@ -250,7 +250,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon nextButton.setOnClickListener { networkAndStorageChecker.warnIfNetworkOrStorageUnavailable() - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.next() onCurrentChanged() onSliderProgressChanged() @@ -262,14 +262,14 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon changeProgress(incrementTime) } pauseButton.setOnClickListener { - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.pause() onCurrentChanged() onSliderProgressChanged() } } stopButton.setOnClickListener { - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.reset() onCurrentChanged() onSliderProgressChanged() @@ -277,7 +277,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon } startButton.setOnClickListener { networkAndStorageChecker.warnIfNetworkOrStorageUnavailable() - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { start() onCurrentChanged() onSliderProgressChanged() @@ -309,7 +309,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon progressBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { override fun onStopTrackingTouch(seekBar: SeekBar) { - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.seekTo(progressBar.progress) onSliderProgressChanged() } @@ -321,7 +321,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon playlistView.setOnItemClickListener { _, _, position, _ -> networkAndStorageChecker.warnIfNetworkOrStorageUnavailable() - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { mediaPlayerController.play(position) onCurrentChanged() onSliderProgressChanged() @@ -388,7 +388,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon } // Query the Jukebox state off-thread - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { try { jukeboxAvailable = mediaPlayerController.isJukeboxAvailable } catch (all: Exception) { @@ -795,7 +795,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon Locale.ROOT, "%s %s", resources.getString(R.string.download_playlist_error), - CommunicationErrorUtil.getErrorMessage(it, context) + CommunicationError.getErrorMessage(it, context) ) Util.toast(context, msg) } @@ -934,7 +934,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon return } - onProgressChangedTask = scope.launch(CommunicationErrorUtil.handler(context)) { + onProgressChangedTask = scope.launch(CommunicationError.getHandler(context)) { val isJukeboxEnabled: Boolean = mediaPlayerController.isJukeboxEnabled val millisPlayed = max(0, mediaPlayerController.playerPosition) @@ -1016,7 +1016,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon } private fun changeProgress(ms: Int) { - scope.launch(CommunicationErrorUtil.handler(context)) { + scope.launch(CommunicationError.getHandler(context)) { val msPlayed: Int = max(0, mediaPlayerController.playerPosition) val duration = mediaPlayerController.playerDuration val seekTo = (msPlayed + ms).coerceAtMost(duration) 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 e8f6d534..6394b08a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/TrackCollectionFragment.kt @@ -38,7 +38,6 @@ import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle -import org.moire.ultrasonic.service.CommunicationErrorUtil import org.moire.ultrasonic.service.MediaPlayerController import org.moire.ultrasonic.subsonic.DownloadHandler import org.moire.ultrasonic.subsonic.ImageLoaderProvider @@ -47,6 +46,7 @@ import org.moire.ultrasonic.subsonic.ShareHandler import org.moire.ultrasonic.subsonic.VideoPlayer import org.moire.ultrasonic.util.AlbumHeader import org.moire.ultrasonic.util.CancellationToken +import org.moire.ultrasonic.util.CommunicationError import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator import org.moire.ultrasonic.util.Settings @@ -211,7 +211,7 @@ class TrackCollectionFragment : Fragment() { val handler = CoroutineExceptionHandler { _, exception -> Handler(Looper.getMainLooper()).post { - CommunicationErrorUtil.handleError(exception, context) + CommunicationError.handleError(exception, context) } refreshAlbumListView!!.isRefreshing = false } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/CommunicationErrorUtil.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/CommunicationErrorUtil.kt deleted file mode 100644 index de3f9c84..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/CommunicationErrorUtil.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2020 (C) Jozsef Varga - */ -package org.moire.ultrasonic.service - -import android.app.AlertDialog -import android.content.Context -import android.os.Handler -import android.os.Looper -import com.fasterxml.jackson.core.JsonParseException -import java.io.FileNotFoundException -import java.io.IOException -import java.security.cert.CertPathValidatorException -import java.security.cert.CertificateException -import javax.net.ssl.SSLException -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.CoroutineExceptionHandler -import org.moire.ultrasonic.R -import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException -import org.moire.ultrasonic.api.subsonic.SubsonicRESTException -import org.moire.ultrasonic.subsonic.getLocalizedErrorMessage -import org.moire.ultrasonic.util.Util -import timber.log.Timber - -/** - * Contains helper functions to handle the exceptions - * thrown during the communication with a Subsonic server - */ -@Suppress("ReturnCount", "UtilityClassWithPublicConstructor") -class CommunicationErrorUtil { - companion object { - fun handler(context: Context?, handler: ((CoroutineContext, Throwable) -> Unit)? = null): - CoroutineExceptionHandler { - return CoroutineExceptionHandler { coroutineContext, exception -> - Handler(Looper.getMainLooper()).post { - handleError(exception, context) - handler?.invoke(coroutineContext, exception) - } - } - } - - fun handleError(error: Throwable?, context: Context?) { - Timber.w(error) - - if (context == null) return - - AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.error_label) - .setMessage(getErrorMessage(error!!, context)) - .setCancelable(true) - .setPositiveButton(R.string.common_ok) { _, _ -> } - .create().show() - } - - fun getErrorMessage(error: Throwable, context: Context?): String { - if (context == null) return "Couldn't get Error message, Context is null" - if (error is IOException && !Util.isNetworkConnected()) { - return context.resources.getString(R.string.background_task_no_network) - } else if (error is FileNotFoundException) { - return context.resources.getString(R.string.background_task_not_found) - } else if (error is JsonParseException) { - return context.resources.getString(R.string.background_task_parse_error) - } else if (error is SSLException) { - return if ( - error.cause is CertificateException && - error.cause?.cause is CertPathValidatorException - ) { - context.resources - .getString( - R.string.background_task_ssl_cert_error, error.cause?.cause?.message - ) - } else { - context.resources.getString(R.string.background_task_ssl_error) - } - } else if (error is ApiNotSupportedException) { - return context.resources.getString( - R.string.background_task_unsupported_api, error.serverApiVersion - ) - } else if (error is IOException) { - return context.resources.getString(R.string.background_task_network_error) - } else if (error is SubsonicRESTException) { - return error.getLocalizedErrorMessage(context) - } - val message = error.message - return message ?: error.javaClass.simpleName - } - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/CommunicationError.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/CommunicationError.kt new file mode 100644 index 00000000..2a722e26 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/CommunicationError.kt @@ -0,0 +1,91 @@ +/* + * CommunicationErrorUtil.kt + * Copyright (C) 2009-2021 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ +package org.moire.ultrasonic.util + +import android.app.AlertDialog +import android.content.Context +import android.os.Handler +import android.os.Looper +import com.fasterxml.jackson.core.JsonParseException +import java.io.FileNotFoundException +import java.io.IOException +import java.security.cert.CertPathValidatorException +import java.security.cert.CertificateException +import javax.net.ssl.SSLException +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.CoroutineExceptionHandler +import org.moire.ultrasonic.R +import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException +import org.moire.ultrasonic.api.subsonic.SubsonicRESTException +import org.moire.ultrasonic.subsonic.getLocalizedErrorMessage +import timber.log.Timber + +/** + * Contains helper functions to handle the exceptions + * thrown during the communication with a Subsonic server + */ +object CommunicationError { + fun getHandler(context: Context?, handler: ((CoroutineContext, Throwable) -> Unit)? = null): + CoroutineExceptionHandler { + return CoroutineExceptionHandler { coroutineContext, exception -> + Handler(Looper.getMainLooper()).post { + handleError(exception, context) + handler?.invoke(coroutineContext, exception) + } + } + } + + @JvmStatic + fun handleError(error: Throwable?, context: Context?) { + Timber.w(error) + + if (context == null) return + + AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.error_label) + .setMessage(getErrorMessage(error!!, context)) + .setCancelable(true) + .setPositiveButton(R.string.common_ok) { _, _ -> } + .create().show() + } + + @JvmStatic + @Suppress("ReturnCount") + fun getErrorMessage(error: Throwable, context: Context?): String { + if (context == null) return "Couldn't get Error message, Context is null" + if (error is IOException && !Util.isNetworkConnected()) { + return context.resources.getString(R.string.background_task_no_network) + } else if (error is FileNotFoundException) { + return context.resources.getString(R.string.background_task_not_found) + } else if (error is JsonParseException) { + return context.resources.getString(R.string.background_task_parse_error) + } else if (error is SSLException) { + return if ( + error.cause is CertificateException && + error.cause?.cause is CertPathValidatorException + ) { + context.resources + .getString( + R.string.background_task_ssl_cert_error, error.cause?.cause?.message + ) + } else { + context.resources.getString(R.string.background_task_ssl_error) + } + } else if (error is ApiNotSupportedException) { + return context.resources.getString( + R.string.background_task_unsupported_api, error.serverApiVersion + ) + } else if (error is IOException) { + return context.resources.getString(R.string.background_task_network_error) + } else if (error is SubsonicRESTException) { + return error.getLocalizedErrorMessage(context) + } + val message = error.message + return message ?: error.javaClass.simpleName + } +}