From 72b4aea35a027aad1ee14985e07158978fa772cc Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sun, 14 Aug 2022 15:19:04 -0700 Subject: [PATCH 01/13] Resolve deprecation warning in MediaSession. Remove setting of MediaSession flags that are now mandatory and assumed set. --- app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt index 8898309..4747a2e 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt @@ -9,7 +9,6 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import audio.funkwhale.ffa.utils.Command import audio.funkwhale.ffa.utils.CommandBus -import com.google.android.exoplayer2.ControlDispatcher import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector @@ -31,7 +30,6 @@ class MediaSession(private val context: Context) { val session: MediaSessionCompat by lazy { MediaSessionCompat(context, context.packageName).apply { - setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS) setPlaybackState(playbackStateBuilder.build()) isActive = true From 6d1ad9cd78b262945a89c035f1a48afae337f8d5 Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 20 Aug 2022 01:05:42 -0700 Subject: [PATCH 02/13] ProgressBus: replace deprecated implementation. Convert Progress from deprecated BroadcastChannel to a StateFlow. --- app/src/main/java/audio/funkwhale/ffa/FFA.kt | 2 -- app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/FFA.kt b/app/src/main/java/audio/funkwhale/ffa/FFA.kt index 0b8fe9d..863dae4 100644 --- a/app/src/main/java/audio/funkwhale/ffa/FFA.kt +++ b/app/src/main/java/audio/funkwhale/ffa/FFA.kt @@ -12,7 +12,6 @@ import audio.funkwhale.ffa.utils.FFACache import audio.funkwhale.ffa.utils.Request import com.preference.PowerPreference import kotlinx.coroutines.channels.BroadcastChannel -import kotlinx.coroutines.channels.ConflatedBroadcastChannel import org.koin.core.context.startKoin import java.text.SimpleDateFormat import java.util.Date @@ -31,7 +30,6 @@ class FFA : Application() { val eventBus: BroadcastChannel = BroadcastChannel(10) val commandBus: BroadcastChannel = BroadcastChannel(10) val requestBus: BroadcastChannel = BroadcastChannel(10) - val progressBus: BroadcastChannel> = ConflatedBroadcastChannel() override fun onCreate() { super.onCreate() diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt index 49e836c..7e24559 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt @@ -8,8 +8,9 @@ import com.google.android.exoplayer2.offline.DownloadCursor import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.launch sealed class Command { @@ -105,13 +106,13 @@ object RequestBus { } object ProgressBus { + private var _progress = MutableStateFlow(Triple(0, 0, 0)) + val progress = _progress.asStateFlow() fun send(current: Int, duration: Int, percent: Int) { - GlobalScope.launch(IO) { - FFA.get().progressBus.send(Triple(current, duration, percent)) - } + _progress.value = Triple(current, duration, percent) } - fun get() = FFA.get().progressBus.asFlow().conflate() + fun get() = progress } suspend inline fun Channel.wait(): T? { From be8901390e04214adfabfc23f1d8799dc5371ec7 Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 20 Aug 2022 15:20:26 -0700 Subject: [PATCH 03/13] EventBus: replace deprecated implementation. Convert EventBus from deprecated BroadcastChannel to a SharedFlow. --- app/src/main/java/audio/funkwhale/ffa/FFA.kt | 2 -- app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/FFA.kt b/app/src/main/java/audio/funkwhale/ffa/FFA.kt index 863dae4..bae0713 100644 --- a/app/src/main/java/audio/funkwhale/ffa/FFA.kt +++ b/app/src/main/java/audio/funkwhale/ffa/FFA.kt @@ -7,7 +7,6 @@ import audio.funkwhale.ffa.koin.authModule import audio.funkwhale.ffa.koin.exoplayerModule import audio.funkwhale.ffa.utils.AppContext import audio.funkwhale.ffa.utils.Command -import audio.funkwhale.ffa.utils.Event import audio.funkwhale.ffa.utils.FFACache import audio.funkwhale.ffa.utils.Request import com.preference.PowerPreference @@ -27,7 +26,6 @@ class FFA : Application() { var defaultExceptionHandler: Thread.UncaughtExceptionHandler? = null - val eventBus: BroadcastChannel = BroadcastChannel(10) val commandBus: BroadcastChannel = BroadcastChannel(10) val requestBus: BroadcastChannel = BroadcastChannel(10) diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt index 7e24559..8820bc5 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt @@ -8,7 +8,9 @@ import com.google.android.exoplayer2.offline.DownloadCursor import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.launch @@ -72,13 +74,15 @@ sealed class Response { } object EventBus { + private var _events = MutableSharedFlow() + val events = _events.asSharedFlow() fun send(event: Event) { GlobalScope.launch(IO) { - FFA.get().eventBus.trySend(event).isSuccess + _events.emit(event) } } - fun get() = FFA.get().eventBus.asFlow() + fun get() = events } object CommandBus { From 1a038b235575d941d484009b32f032f48cb165da Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 20 Aug 2022 17:04:54 -0700 Subject: [PATCH 04/13] CommandBus: replace deprecated implementation. Convert CommandBus from deprecated BroadcastChannel to a SharedFlow. --- app/src/main/java/audio/funkwhale/ffa/FFA.kt | 2 -- app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/FFA.kt b/app/src/main/java/audio/funkwhale/ffa/FFA.kt index bae0713..cdac362 100644 --- a/app/src/main/java/audio/funkwhale/ffa/FFA.kt +++ b/app/src/main/java/audio/funkwhale/ffa/FFA.kt @@ -6,7 +6,6 @@ import androidx.appcompat.app.AppCompatDelegate import audio.funkwhale.ffa.koin.authModule import audio.funkwhale.ffa.koin.exoplayerModule import audio.funkwhale.ffa.utils.AppContext -import audio.funkwhale.ffa.utils.Command import audio.funkwhale.ffa.utils.FFACache import audio.funkwhale.ffa.utils.Request import com.preference.PowerPreference @@ -26,7 +25,6 @@ class FFA : Application() { var defaultExceptionHandler: Thread.UncaughtExceptionHandler? = null - val commandBus: BroadcastChannel = BroadcastChannel(10) val requestBus: BroadcastChannel = BroadcastChannel(10) override fun onCreate() { diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt index 8820bc5..22d368d 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt @@ -86,13 +86,15 @@ object EventBus { } object CommandBus { + private var _commands = MutableSharedFlow() + var commands = _commands.asSharedFlow() fun send(command: Command) { GlobalScope.launch(IO) { - FFA.get().commandBus.trySend(command).isSuccess + _commands.emit(command) } } - fun get() = FFA.get().commandBus.asFlow() + fun get() = commands } object RequestBus { From 4827fbccc16da3ccefc7ed9750df6e02b3b80fcf Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 20 Aug 2022 17:18:47 -0700 Subject: [PATCH 05/13] RequentBus: replace deprecated implementation. Convert RequestBus from deprecated BroadcastChannel to a SharedFlow. --- app/src/main/java/audio/funkwhale/ffa/FFA.kt | 4 ---- app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/FFA.kt b/app/src/main/java/audio/funkwhale/ffa/FFA.kt index cdac362..29af3b7 100644 --- a/app/src/main/java/audio/funkwhale/ffa/FFA.kt +++ b/app/src/main/java/audio/funkwhale/ffa/FFA.kt @@ -7,9 +7,7 @@ import audio.funkwhale.ffa.koin.authModule import audio.funkwhale.ffa.koin.exoplayerModule import audio.funkwhale.ffa.utils.AppContext import audio.funkwhale.ffa.utils.FFACache -import audio.funkwhale.ffa.utils.Request import com.preference.PowerPreference -import kotlinx.coroutines.channels.BroadcastChannel import org.koin.core.context.startKoin import java.text.SimpleDateFormat import java.util.Date @@ -25,8 +23,6 @@ class FFA : Application() { var defaultExceptionHandler: Thread.UncaughtExceptionHandler? = null - val requestBus: BroadcastChannel = BroadcastChannel(10) - override fun onCreate() { super.onCreate() diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt index 22d368d..b7e4828 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt @@ -1,6 +1,5 @@ package audio.funkwhale.ffa.utils -import audio.funkwhale.ffa.FFA import audio.funkwhale.ffa.model.Radio import audio.funkwhale.ffa.model.Track import com.google.android.exoplayer2.offline.Download @@ -12,7 +11,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.launch sealed class Command { @@ -98,17 +96,19 @@ object CommandBus { } object RequestBus { + private var _requests = MutableSharedFlow() + var requests = _requests.asSharedFlow() fun send(request: Request): Channel { return Channel().also { GlobalScope.launch(IO) { request.channel = it - FFA.get().requestBus.trySend(request).isSuccess + _requests.emit(request) } } } - fun get() = FFA.get().requestBus.asFlow() + fun get() = requests } object ProgressBus { From 7d4981945061993b50c199e8ee90e4f5bbc77347 Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Tue, 23 Aug 2022 21:41:11 -0700 Subject: [PATCH 06/13] Resolve warning "Unnecessary safe call". --- .../java/audio/funkwhale/ffa/activities/SettingsActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt index 2e990d5..28c11a5 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt @@ -59,7 +59,7 @@ class SettingsFragment : } override fun onPreferenceTreeClick(preference: Preference): Boolean { - when (preference?.key) { + when (preference.key) { "oss_licences" -> startActivity(Intent(activity, LicencesActivity::class.java)) "crash" -> { From 8878e3e68f72bf3b9d41a410f6b85852199bc050 Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Tue, 23 Aug 2022 21:44:52 -0700 Subject: [PATCH 07/13] Resolve warning: ExoDatabaseProvider deprecated. Replace ExoDatabaseProvider with StandaloneDatabaseProvider. --- app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt b/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt index d06ac33..0569a52 100644 --- a/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt +++ b/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt @@ -6,7 +6,7 @@ import audio.funkwhale.ffa.playback.MediaSession import audio.funkwhale.ffa.utils.AuthorizationServiceFactory import audio.funkwhale.ffa.utils.OAuth import com.google.android.exoplayer2.database.DatabaseProvider -import com.google.android.exoplayer2.database.ExoDatabaseProvider +import com.google.android.exoplayer2.database.StandaloneDatabaseProvider import com.google.android.exoplayer2.offline.DownloadManager import com.google.android.exoplayer2.upstream.cache.Cache import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor @@ -19,7 +19,7 @@ import org.koin.dsl.module fun exoplayerModule(context: Context) = module { single(named("exoDatabase")) { - ExoDatabaseProvider(context) + StandaloneDatabaseProvider(context) } single { From 38a3183b9d86ff48adcd6a30cef9f1f0989d381f Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Thu, 25 Aug 2022 04:21:04 -0700 Subject: [PATCH 08/13] Resolve warning: FragmentPagerAdapter deprecated. Replace FragmentPagerAdapter with FragmentStateAdapter in BrowseTabsAdapter.kt. Refactored getPageTitle as a function that returns tab name. Tab text update moved to BrowseFragment. This requires replacement of setupWithViewPager with TabMediator.attach in BrowseFragment. Also requires replacing widget declaration androidx.viewpager.widget.ViewPager with androidx.viewpager2.widget.ViewPager2 in fragment_browwse.xml. --- .../funkwhale/ffa/adapters/BrowseTabsAdapter.kt | 13 ++++++------- .../audio/funkwhale/ffa/fragments/BrowseFragment.kt | 7 +++++-- app/src/main/res/layout/fragment_browse.xml | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt index 272f24f..b8cb5ba 100644 --- a/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt +++ b/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt @@ -1,8 +1,7 @@ package audio.funkwhale.ffa.adapters import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager2.adapter.FragmentStateAdapter import audio.funkwhale.ffa.R import audio.funkwhale.ffa.fragments.AlbumsGridFragment import audio.funkwhale.ffa.fragments.ArtistsFragment @@ -10,13 +9,13 @@ import audio.funkwhale.ffa.fragments.FavoritesFragment import audio.funkwhale.ffa.fragments.PlaylistsFragment import audio.funkwhale.ffa.fragments.RadiosFragment -class BrowseTabsAdapter(val context: Fragment, manager: FragmentManager) : - FragmentPagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { +class BrowseTabsAdapter(val context: Fragment) : + FragmentStateAdapter(context) { var tabs = mutableListOf() - override fun getCount() = 5 + override fun getItemCount() = 5 - override fun getItem(position: Int): Fragment { + override fun createFragment(position: Int): Fragment { tabs.getOrNull(position)?.let { return it } @@ -35,7 +34,7 @@ class BrowseTabsAdapter(val context: Fragment, manager: FragmentManager) : return fragment } - override fun getPageTitle(position: Int): String { + fun tabText(position: Int): String { return when (position) { 0 -> context.getString(R.string.artists) 1 -> context.getString(R.string.albums) diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/BrowseFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/BrowseFragment.kt index f0a78a1..996c622 100644 --- a/app/src/main/java/audio/funkwhale/ffa/fragments/BrowseFragment.kt +++ b/app/src/main/java/audio/funkwhale/ffa/fragments/BrowseFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import audio.funkwhale.ffa.adapters.BrowseTabsAdapter import audio.funkwhale.ffa.databinding.FragmentBrowseBinding +import com.google.android.material.tabs.TabLayoutMediator class BrowseFragment : Fragment() { @@ -17,7 +18,7 @@ class BrowseFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - adapter = BrowseTabsAdapter(this, childFragmentManager) + adapter = BrowseTabsAdapter(this) } override fun onCreateView( @@ -27,11 +28,13 @@ class BrowseFragment : Fragment() { ): View { _binding = FragmentBrowseBinding.inflate(inflater) return binding.root.apply { - binding.tabs.setupWithViewPager(binding.pager) binding.tabs.getTabAt(0)?.select() binding.pager.adapter = adapter binding.pager.offscreenPageLimit = 3 + TabLayoutMediator(binding.tabs, binding.pager) { tab, position -> + tab.text = adapter?.tabText(position) + }.attach() } } diff --git a/app/src/main/res/layout/fragment_browse.xml b/app/src/main/res/layout/fragment_browse.xml index b58b4d1..afc7ccb 100644 --- a/app/src/main/res/layout/fragment_browse.xml +++ b/app/src/main/res/layout/fragment_browse.xml @@ -17,7 +17,7 @@ app:tabSelectedTextColor="@color/controlColor" app:tabTextColor="@color/colorPrimary" /> - Date: Fri, 26 Aug 2022 14:19:53 -0700 Subject: [PATCH 09/13] LoginActivity: startActivityForResult deprecated. Migrate startActivityForResult/onActivityResult to StartActivityForResult/registerForActivityResult in LoginActivity/OAuth. This moves responsibility for scheduling the starting Intent from OAuth to LoginActivity. OAuth still generates the Intent. But instead of starting the intent directly in OAuth, the intent is returned to LoginActivity. This better associates processing the activity result with its invocation. OAuthTest module updated to accommodate internal API change. --- .../funkwhale/ffa/activities/LoginActivity.kt | 32 ++++++++----------- .../java/audio/funkwhale/ffa/utils/OAuth.kt | 7 ++-- .../audio/funkwhale/ffa/utils/OAuthTest.kt | 7 ++-- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt index 333123f..de6e936 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt @@ -5,6 +5,7 @@ import android.content.res.Configuration import android.net.Uri import android.os.Bundle import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.appcompat.app.AppCompatActivity import androidx.core.view.doOnLayout import androidx.lifecycle.lifecycleScope @@ -40,26 +41,21 @@ class LoginActivity : AppCompatActivity() { limitContainerWidth() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) + private var resultLauncher = + registerForActivityResult(StartActivityForResult()) { result -> + result.data?.let { + oAuth.exchange(this, it) { + PowerPreference + .getFileByName(AppContext.PREFS_CREDENTIALS) + .setBoolean("anonymous", false) - data?.let { - when (requestCode) { - 0 -> { - oAuth.exchange(this, data) { - PowerPreference - .getFileByName(AppContext.PREFS_CREDENTIALS) - .setBoolean("anonymous", false) + lifecycleScope.launch(Main) { + Userinfo.get(this@LoginActivity, oAuth)?.let { + startActivity(Intent(this@LoginActivity, MainActivity::class.java)) - lifecycleScope.launch(Main) { - Userinfo.get(this@LoginActivity, oAuth)?.let { - startActivity(Intent(this@LoginActivity, MainActivity::class.java)) - - return@launch finish() - } - throw Exception(getString(R.string.login_error_userinfo)) - } + return@launch finish() } + throw Exception(getString(R.string.login_error_userinfo)) } } } @@ -134,7 +130,7 @@ class LoginActivity : AppCompatActivity() { oAuth.init(hostname) return oAuth.register { PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).setString("hostname", hostname) - oAuth.authorize(this) + resultLauncher.launch(oAuth.authorizeIntent(this)) } } diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt index 9e21669..19560ed 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt @@ -184,11 +184,10 @@ class OAuth(private val authorizationServiceFactory: AuthorizationServiceFactory ) } - fun authorize(activity: Activity) { + fun authorizeIntent(activity: Activity): Intent? { val authService = service(activity) - authorizationRequest()?.let { it -> - val intent = authService.getAuthorizationRequestIntent(it) - activity.startActivityForResult(intent, 0) + return authorizationRequest()?.let { it -> + authService.getAuthorizationRequestIntent(it) } } diff --git a/app/src/test/java/audio/funkwhale/ffa/utils/OAuthTest.kt b/app/src/test/java/audio/funkwhale/ffa/utils/OAuthTest.kt index b5fb3ef..ca0d498 100644 --- a/app/src/test/java/audio/funkwhale/ffa/utils/OAuthTest.kt +++ b/app/src/test/java/audio/funkwhale/ffa/utils/OAuthTest.kt @@ -27,6 +27,7 @@ import org.junit.Before import org.junit.Test import strikt.api.expectThat import strikt.api.expectThrows +import strikt.assertions.isA import strikt.assertions.isEqualTo import strikt.assertions.isFalse import strikt.assertions.isNotNull @@ -282,7 +283,7 @@ class OAuthTest { } @Test - fun `authorize() should start activity for result`() { + fun `authorizeIntent() should return an Intent`() { mockkStatic(PowerPreference::class) every { PowerPreference.getFileByName(any()) } returns mockPreference @@ -302,9 +303,7 @@ class OAuthTest { val activity = mockk(relaxed = true) - oAuth.authorize(activity) - - verify { activity.startActivityForResult(mockkIntent, 0) } + expectThat(oAuth.authorizeIntent(activity)).isNotNull().isA() } private fun deserializeJson( From 24de54c7e004bcf6ce07e01f4fe663d063a63f77 Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 27 Aug 2022 00:05:38 -0700 Subject: [PATCH 10/13] MainActivity: startActivityForResult deprecated. Migrate startActivityForResult/onActivityResult to StartActivityForResult/registerForActivityResult in MainActivity. --- .../funkwhale/ffa/activities/MainActivity.kt | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt index 14d8939..b3e2d68 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt @@ -16,6 +16,7 @@ import android.view.View import android.view.ViewGroup import android.view.animation.AccelerateDecelerateInterpolator import android.widget.SeekBar +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat @@ -207,6 +208,21 @@ class MainActivity : AppCompatActivity() { return true } + var resultLauncher = registerForActivityResult(StartActivityForResult()) { result -> + if (result.resultCode == ResultCode.LOGOUT.code) { + Intent(this, LoginActivity::class.java).apply { + FFA.get().deleteAllData(this@MainActivity) + + flags = + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + + stopService(Intent(this@MainActivity, PlayerService::class.java)) + startActivity(this) + finish() + } + } + } + override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { android.R.id.home -> { @@ -279,29 +295,12 @@ class MainActivity : AppCompatActivity() { } } R.id.nav_downloads -> startActivity(Intent(this, DownloadsActivity::class.java)) - R.id.settings -> startActivityForResult(Intent(this, SettingsActivity::class.java), 0) + R.id.settings -> resultLauncher.launch(Intent(this, SettingsActivity::class.java)) } return true } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - if (resultCode == ResultCode.LOGOUT.code) { - Intent(this, LoginActivity::class.java).apply { - FFA.get().deleteAllData(this@MainActivity) - - flags = - Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP - - stopService(Intent(this@MainActivity, PlayerService::class.java)) - startActivity(this) - finish() - } - } - } - private fun launchFragment(fragment: Fragment) { supportFragmentManager.fragments.lastOrNull()?.also { oldFragment -> oldFragment.enterTransition = null From d734953b54e2506bbdf12c8164f0c94ccc82022f Mon Sep 17 00:00:00 2001 From: Hugh Daschbach Date: Sat, 27 Aug 2022 00:21:03 -0700 Subject: [PATCH 11/13] Replace deprecated SimpleExoPlayer with ExoPlayer. This is part of an effort to resolve deprecation warnings. Most of this is simple refactoring of interfaces that change between the two Player implementations. There are a few other changes that deserve further explanation. Testing indicated that the play/pause button was being reset to pause in MainActivity:refreshCurrentTrack. In the past this was likely masked by the ordering of other callbacks. We have removed the nowPlayingToggle.icon update from MainActivity, leaving that UI update to PlayerService. One of the bigger refactorings in PlayerService was forced by the deprecation of Player.EventListener.onPlayerStateChanged. That forced separation of handling playWhenReady and playbackState transitions. In the SimpleExoPlayer implementations, where these transitions were combined, the module attempted to work out playing state from a combination of these two state variables. In addition to separating the reaction to these state changes, we have added a listener to onIsPlayingChanged, eliminating the need for some of the earlier logic in Player.EventListener.onPlayerStateChanged. This addition, along with the separation of state transition processing, seems to provide a simpler implementation. But it is, certainly, a possible source of bugs. --- app/build.gradle.kts | 10 +- .../funkwhale/ffa/activities/MainActivity.kt | 2 - .../funkwhale/ffa/playback/MediaSession.kt | 14 +-- .../funkwhale/ffa/playback/PinService.kt | 6 +- .../funkwhale/ffa/playback/PlayerService.kt | 105 +++++++++--------- .../funkwhale/ffa/playback/QueueManager.kt | 15 ++- 6 files changed, 76 insertions(+), 76 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f93b57f..2ff9843 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -167,18 +167,18 @@ dependencies { implementation("com.google.android.material:material:1.6.1") implementation("com.android.support.constraint:constraint-layout:2.0.4") - implementation("com.google.android.exoplayer:exoplayer-core:2.14.2") - implementation("com.google.android.exoplayer:exoplayer-ui:2.14.2") - implementation("com.google.android.exoplayer:extension-mediasession:2.14.2") + implementation("com.google.android.exoplayer:exoplayer-core:2.18.1") + implementation("com.google.android.exoplayer:exoplayer-ui:2.18.1") + implementation("com.google.android.exoplayer:extension-mediasession:2.18.1") implementation("io.insert-koin:koin-core:3.1.2") implementation("io.insert-koin:koin-android:3.1.2") testImplementation("io.insert-koin:koin-test:3.1.2") - implementation("com.github.PaulWoitaschek.ExoPlayer-Extensions:extension-opus:2.14.0") { + implementation("com.github.PaulWoitaschek.ExoPlayer-Extensions:extension-opus:789a4f83169cff5c7a91655bb828fde2cfde671a") { isTransitive = false } - implementation("com.github.PaulWoitaschek.ExoPlayer-Extensions:extension-flac:2.14.0") { + implementation("com.github.PaulWoitaschek.ExoPlayer-Extensions:extension-flac:789a4f83169cff5c7a91655bb828fde2cfde671a") { isTransitive = false } diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt index b3e2d68..efe6eb6 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt @@ -473,11 +473,9 @@ class MainActivity : AppCompatActivity() { binding.nowPlayingContainer?.nowPlayingTitle?.text = track.title binding.nowPlayingContainer?.nowPlayingAlbum?.text = track.artist.name - binding.nowPlayingContainer?.nowPlayingToggle?.icon = getDrawable(R.drawable.pause) binding.nowPlayingContainer?.nowPlayingDetailsTitle?.text = track.title binding.nowPlayingContainer?.nowPlayingDetailsArtist?.text = track.artist.name - binding.nowPlayingContainer?.nowPlayingDetailsToggle?.icon = getDrawable(R.drawable.pause) Picasso.get() .maybeLoad(maybeNormalizeUrl(track.album?.cover?.urls?.original)) diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt index 4747a2e..ce3d88c 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt @@ -41,7 +41,7 @@ class MediaSession(private val context: Context) { MediaSessionConnector(session).also { it.setQueueNavigator(FFAQueueNavigator()) - it.setMediaButtonEventHandler { _, _, intent -> + it.setMediaButtonEventHandler { _, intent -> if (!active) { Intent(context, PlayerService::class.java).let { player -> player.action = intent.action @@ -65,13 +65,11 @@ class MediaSession(private val context: Context) { } class FFAQueueNavigator : MediaSessionConnector.QueueNavigator { - override fun onSkipToQueueItem(player: Player, controlDispatcher: ControlDispatcher, id: Long) { + override fun onSkipToQueueItem(player: Player, id: Long) { CommandBus.send(Command.PlayTrack(id.toInt())) } - override fun onCurrentWindowIndexChanged(player: Player) {} - - override fun onCommand(player: Player, controlDispatcher: ControlDispatcher, command: String, extras: Bundle?, cb: ResultReceiver?) = true + override fun onCommand(player: Player, command: String, extras: Bundle?, cb: ResultReceiver?) = true override fun getSupportedQueueNavigatorActions(player: Player): Long { return PlaybackStateCompat.ACTION_PLAY_PAUSE or @@ -80,13 +78,13 @@ class FFAQueueNavigator : MediaSessionConnector.QueueNavigator { PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM } - override fun onSkipToNext(player: Player, controlDispatcher: ControlDispatcher) { + override fun onSkipToNext(player: Player) { CommandBus.send(Command.NextTrack) } - override fun getActiveQueueItemId(player: Player?) = player?.currentWindowIndex?.toLong() ?: 0 + override fun getActiveQueueItemId(player: Player?) = player?.currentMediaItemIndex?.toLong() ?: 0 - override fun onSkipToPrevious(player: Player, controlDispatcher: ControlDispatcher) { + override fun onSkipToPrevious(player: Player) { CommandBus.send(Command.PreviousTrack) } diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt index f3bd1ce..321c125 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt @@ -80,14 +80,16 @@ class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) { override fun getScheduler(): Scheduler? = null - override fun getForegroundNotification(downloads: MutableList): Notification { + override fun getForegroundNotification(downloads: MutableList, + notMetRequirements: Int): Notification { val description = resources.getQuantityString(R.plurals.downloads_description, downloads.size, downloads.size) return DownloadNotificationHelper( this, AppContext.NOTIFICATION_CHANNEL_DOWNLOADS - ).buildProgressNotification(this, R.drawable.downloads, null, description, downloads) + ).buildProgressNotification(this, R.drawable.downloads, null, description, + downloads, notMetRequirements) } private fun getDownloads() = downloadManager.downloadIndex.getDownloads() diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt index 9c74da5..68adff5 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt @@ -31,11 +31,10 @@ import audio.funkwhale.ffa.utils.log import audio.funkwhale.ffa.utils.maybeNormalizeUrl import audio.funkwhale.ffa.utils.onApi import com.google.android.exoplayer2.C -import com.google.android.exoplayer2.ExoPlaybackException +import com.google.android.exoplayer2.ExoPlayer +import com.google.android.exoplayer2.PlaybackException import com.google.android.exoplayer2.Player -import com.google.android.exoplayer2.SimpleExoPlayer -import com.google.android.exoplayer2.source.TrackGroupArray -import com.google.android.exoplayer2.trackselection.TrackSelectionArray +import com.google.android.exoplayer2.Tracks import com.squareup.picasso.Picasso import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO @@ -65,7 +64,7 @@ class PlayerService : Service() { private lateinit var queue: QueueManager private lateinit var mediaControlsManager: MediaControlsManager - private lateinit var player: SimpleExoPlayer + private lateinit var player: ExoPlayer private val mediaMetadataBuilder = MediaMetadataCompat.Builder() @@ -132,12 +131,13 @@ class PlayerService : Service() { mediaControlsManager = MediaControlsManager(this, scope, mediaSession.session) - player = SimpleExoPlayer.Builder(this).build().apply { + player = ExoPlayer.Builder(this).build().apply { playWhenReady = false playerEventListener = PlayerEventListener().also { addListener(it) } + EventBus.send(Event.StateChanged(this.isPlaying())) } mediaSession.active = true @@ -151,7 +151,8 @@ class PlayerService : Service() { } if (queue.current > -1) { - player.prepare(queue.dataSources) + player.setMediaSource(queue.dataSources) + player.prepare() FFACache.getLine(this, "progress")?.let { player.seekTo(queue.current, it.toLong()) @@ -180,7 +181,8 @@ class PlayerService : Service() { if (!command.fromRadio) radioPlayer.stop() queue.replace(command.queue) - player.prepare(queue.dataSources, true, true) + player.setMediaSource(queue.dataSources) + player.prepare() setPlaybackState(true) @@ -307,7 +309,8 @@ class PlayerService : Service() { } if (state && player.playbackState == Player.STATE_IDLE) { - player.prepare(queue.dataSources) + player.setMediaSource(queue.dataSources) + player.prepare() } if (hasAudioFocus(state)) { @@ -318,7 +321,7 @@ class PlayerService : Service() { } private fun togglePlayback() { - setPlaybackState(!player.playWhenReady) + setPlaybackState(!player.isPlaying) } private fun skipToPreviousTrack() { @@ -326,11 +329,11 @@ class PlayerService : Service() { return player.seekTo(0) } - player.previous() + player.seekToPrevious() } private fun skipToNextTrack() { - player.next() + player.seekToNext() FFACache.set(this@PlayerService, "progress", "0") ProgressBus.send(0, 0, 0) @@ -419,9 +422,14 @@ class PlayerService : Service() { } @SuppressLint("NewApi") - inner class PlayerEventListener : Player.EventListener { - override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { - super.onPlayerStateChanged(playWhenReady, playbackState) + inner class PlayerEventListener : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + super.onIsPlayingChanged(isPlaying) + mediaControlsManager.updateNotification(queue.current(), isPlaying) + } + + override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) { + super.onPlayWhenReadyChanged(playWhenReady, reason) EventBus.send(Event.StateChanged(playWhenReady)) @@ -429,55 +437,45 @@ class PlayerService : Service() { CommandBus.send(Command.RefreshTrack(queue.current())) } - when (playWhenReady) { - true -> { - when (playbackState) { - Player.STATE_READY -> mediaControlsManager.updateNotification(queue.current(), true) - Player.STATE_BUFFERING -> EventBus.send(Event.Buffering(true)) - Player.STATE_ENDED -> { - setPlaybackState(false) + if (!playWhenReady) { + Build.VERSION_CODES.N.onApi( + { stopForeground(STOP_FOREGROUND_DETACH) }, + { stopForeground(false) } + ) + } + } - queue.current = 0 - player.seekTo(0, C.TIME_UNSET) + override fun onPlaybackStateChanged(playbackState: Int) { + super.onPlaybackStateChanged(playbackState) + EventBus.send(Event.Buffering(playbackState == Player.STATE_BUFFERING)) + when (playbackState) { + Player.STATE_ENDED -> { + setPlaybackState(false) - ProgressBus.send(0, 0, 0) - } + queue.current = 0 + player.seekTo(0, C.TIME_UNSET) - Player.STATE_IDLE -> { - setPlaybackState(false) - - return EventBus.send(Event.PlaybackStopped) - } - } - - if (playbackState != Player.STATE_BUFFERING) EventBus.send(Event.Buffering(false)) + ProgressBus.send(0, 0, 0) } - false -> { - EventBus.send(Event.Buffering(false)) + Player.STATE_IDLE -> { + setPlaybackState(false) - Build.VERSION_CODES.N.onApi( - { stopForeground(STOP_FOREGROUND_DETACH) }, - { stopForeground(false) } - ) + EventBus.send(Event.PlaybackStopped) - when (playbackState) { - Player.STATE_READY -> mediaControlsManager.updateNotification(queue.current(), false) - Player.STATE_IDLE -> mediaControlsManager.remove() + if (!player.playWhenReady) { + mediaControlsManager.remove() } } } } - override fun onTracksChanged( - trackGroups: TrackGroupArray, - trackSelections: TrackSelectionArray - ) { - super.onTracksChanged(trackGroups, trackSelections) + override fun onTracksChanged(tracks: Tracks) { + super.onTracksChanged(tracks) - if (queue.current != player.currentWindowIndex) { - queue.current = player.currentWindowIndex - mediaControlsManager.updateNotification(queue.current(), player.playWhenReady) + if (queue.current != player.currentMediaItemIndex) { + queue.current = player.currentMediaItemIndex + mediaControlsManager.updateNotification(queue.current(), player.isPlaying) } if (queue.get().isNotEmpty() && @@ -510,13 +508,14 @@ class PlayerService : Service() { } } - override fun onPlayerError(error: ExoPlaybackException) { + override fun onPlayerError(error: PlaybackException) { EventBus.send(Event.PlaybackError(getString(R.string.error_playback))) if (player.playWhenReady) { queue.current++ - player.prepare(queue.dataSources, true, true) + player.setMediaSource(queue.dataSources, true) player.seekTo(queue.current, 0) + player.prepare() CommandBus.send(Command.RefreshTrack(queue.current())) } diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt b/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt index fe9bf31..821b860 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt @@ -12,6 +12,7 @@ import audio.funkwhale.ffa.utils.FFACache import audio.funkwhale.ffa.utils.log import audio.funkwhale.ffa.utils.mustNormalizeUrl import com.github.kittinunf.fuel.gson.gsonDeserializerOf +import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.source.ConcatenatingMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.gson.Gson @@ -38,8 +39,8 @@ class QueueManager(val context: Context) { metadata.map { track -> val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "") - ProgressiveMediaSource.Factory(factory).setTag(track.title) - .createMediaSource(Uri.parse(url)) + val mediaItem = MediaItem.fromUri(Uri.parse(url)).buildUpon().setTag(track.title).build() + ProgressiveMediaSource.Factory(factory).createMediaSource(mediaItem) } ) } @@ -63,8 +64,8 @@ class QueueManager(val context: Context) { val factory = cacheDataSourceFactoryProvider.create(context) val sources = tracks.map { track -> val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "") - - ProgressiveMediaSource.Factory(factory).setTag(track.title).createMediaSource(Uri.parse(url)) + val mediaItem = MediaItem.fromUri(Uri.parse(url)).buildUpon().setTag(track.title).build() + ProgressiveMediaSource.Factory(factory).createMediaSource(mediaItem) } metadata = tracks.toMutableList() @@ -84,7 +85,8 @@ class QueueManager(val context: Context) { val sources = missingTracks.map { track -> val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "") - ProgressiveMediaSource.Factory(factory).createMediaSource(Uri.parse(url)) + val mediaItem = MediaItem.fromUri(Uri.parse(url)).buildUpon().setTag(track.title).build() + ProgressiveMediaSource.Factory(factory).createMediaSource(mediaItem) } metadata.addAll(tracks) @@ -101,7 +103,8 @@ class QueueManager(val context: Context) { val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "") if (metadata.indexOf(track) == -1) { - ProgressiveMediaSource.Factory(factory).createMediaSource(Uri.parse(url)).let { + val mediaItem = MediaItem.fromUri(Uri.parse(url)).buildUpon().setTag(track.title).build() + ProgressiveMediaSource.Factory(factory).createMediaSource(mediaItem).let { dataSources.addMediaSource(current + 1, it) metadata.add(current + 1, track) } From 2de6ca303e9e97f7b9b23044b0c2be652d300859 Mon Sep 17 00:00:00 2001 From: Ryan Harg Date: Tue, 6 Dec 2022 09:31:09 +0100 Subject: [PATCH 12/13] Necessary upgrades to compileSdk and targetSdk and adjusting code --- app/build.gradle.kts | 6 +++-- app/src/main/AndroidManifest.xml | 12 +++++----- .../funkwhale/ffa/activities/LoginActivity.kt | 22 +++++++++---------- .../funkwhale/ffa/activities/MainActivity.kt | 6 ++--- .../funkwhale/ffa/playback/PinService.kt | 12 ++++++---- .../funkwhale/ffa/playback/PlayerService.kt | 8 +++---- .../ffa/repositories/SearchRepository.kt | 2 +- .../ffa/repositories/TracksRepository.kt | 2 +- .../java/audio/funkwhale/ffa/utils/Bus.kt | 2 +- .../audio/funkwhale/ffa/utils/Extensions.kt | 3 --- .../funkwhale/ffa/views/NowPlayingView.kt | 8 +++---- 11 files changed, 44 insertions(+), 39 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2ff9843..4ba0f2a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -36,6 +36,8 @@ android { targetCompatibility = JavaVersion.VERSION_1_8 } + namespace = "audio.funkwhale.ffa" + testCoverage { version = "0.8.7" } @@ -52,7 +54,7 @@ android { disable += listOf("MissingTranslation", "ExtraTranslation") } - compileSdk = 31 + compileSdk = 33 defaultConfig { @@ -62,7 +64,7 @@ android { versionName = androidGitVersion.name() minSdk = 24 - targetSdk = 30 + targetSdk = 33 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b6e4126..24462a3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + @@ -22,7 +21,8 @@ android:name=".activities.SplashActivity" android:launchMode="singleInstance" android:noHistory="true" - android:screenOrientation="portrait"> + android:screenOrientation="portrait" + android:exported="true"> @@ -61,7 +61,8 @@ + android:foregroundServiceType="mediaPlayback" + android:exported="false"> @@ -80,7 +81,8 @@ - + diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt index de6e936..914be0f 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt @@ -43,23 +43,23 @@ class LoginActivity : AppCompatActivity() { private var resultLauncher = registerForActivityResult(StartActivityForResult()) { result -> - result.data?.let { - oAuth.exchange(this, it) { - PowerPreference - .getFileByName(AppContext.PREFS_CREDENTIALS) - .setBoolean("anonymous", false) + result.data?.let { + oAuth.exchange(this, it) { + PowerPreference + .getFileByName(AppContext.PREFS_CREDENTIALS) + .setBoolean("anonymous", false) - lifecycleScope.launch(Main) { - Userinfo.get(this@LoginActivity, oAuth)?.let { - startActivity(Intent(this@LoginActivity, MainActivity::class.java)) + lifecycleScope.launch(Main) { + Userinfo.get(this@LoginActivity, oAuth)?.let { + startActivity(Intent(this@LoginActivity, MainActivity::class.java)) - return@launch finish() + return@launch finish() + } + throw Exception(getString(R.string.login_error_userinfo)) } - throw Exception(getString(R.string.login_error_userinfo)) } } } - } override fun onResume() { super.onResume() diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt index efe6eb6..c65a437 100644 --- a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt +++ b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt @@ -244,8 +244,8 @@ class MainActivity : AppCompatActivity() { item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) item.actionView = View(this) item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(item: MenuItem?) = false - override fun onMenuItemActionCollapse(item: MenuItem?) = false + override fun onMenuItemActionExpand(item: MenuItem) = false + override fun onMenuItemActionCollapse(item: MenuItem) = false }) item.isChecked = !item.isChecked @@ -358,7 +358,7 @@ class MainActivity : AppCompatActivity() { .alpha(0.0f) .setDuration(400) .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animator: Animator?) { + override fun onAnimationEnd(animator: Animator) { binding.nowPlaying.visibility = View.GONE } }) diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt index 321c125..3b5becf 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt @@ -80,16 +80,20 @@ class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) { override fun getScheduler(): Scheduler? = null - override fun getForegroundNotification(downloads: MutableList, - notMetRequirements: Int): Notification { + override fun getForegroundNotification( + downloads: MutableList, + notMetRequirements: Int + ): Notification { val description = resources.getQuantityString(R.plurals.downloads_description, downloads.size, downloads.size) return DownloadNotificationHelper( this, AppContext.NOTIFICATION_CHANNEL_DOWNLOADS - ).buildProgressNotification(this, R.drawable.downloads, null, description, - downloads, notMetRequirements) + ).buildProgressNotification( + this, R.drawable.downloads, null, description, + downloads, notMetRequirements + ) } private fun getDownloads() = downloadManager.downloadIndex.getDownloads() diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt index 68adff5..6b1c606 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt @@ -438,10 +438,10 @@ class PlayerService : Service() { } if (!playWhenReady) { - Build.VERSION_CODES.N.onApi( - { stopForeground(STOP_FOREGROUND_DETACH) }, - { stopForeground(false) } - ) + Build.VERSION_CODES.N.onApi( + { stopForeground(STOP_FOREGROUND_DETACH) }, + { stopForeground(false) } + ) } } diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt index ee32d64..60021e1 100644 --- a/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt +++ b/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt @@ -11,8 +11,8 @@ import audio.funkwhale.ffa.model.Track import audio.funkwhale.ffa.model.TracksCache import audio.funkwhale.ffa.model.TracksResponse import audio.funkwhale.ffa.utils.OAuth -import com.github.kittinunf.fuel.gson.gsonDeserializerOf import audio.funkwhale.ffa.utils.mustNormalizeUrl +import com.github.kittinunf.fuel.gson.gsonDeserializerOf import com.google.android.exoplayer2.offline.DownloadManager import com.google.android.exoplayer2.upstream.cache.Cache import com.google.gson.reflect.TypeToken diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/TracksRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/TracksRepository.kt index 7858bf0..7a224c6 100644 --- a/app/src/main/java/audio/funkwhale/ffa/repositories/TracksRepository.kt +++ b/app/src/main/java/audio/funkwhale/ffa/repositories/TracksRepository.kt @@ -7,8 +7,8 @@ import audio.funkwhale.ffa.model.TracksCache import audio.funkwhale.ffa.model.TracksResponse import audio.funkwhale.ffa.utils.OAuth import audio.funkwhale.ffa.utils.getMetadata -import com.github.kittinunf.fuel.gson.gsonDeserializerOf import audio.funkwhale.ffa.utils.mustNormalizeUrl +import com.github.kittinunf.fuel.gson.gsonDeserializerOf import com.google.android.exoplayer2.offline.Download import com.google.android.exoplayer2.offline.DownloadManager import com.google.android.exoplayer2.upstream.cache.Cache diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt index b7e4828..83b3ac1 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Bus.kt @@ -88,7 +88,7 @@ object CommandBus { var commands = _commands.asSharedFlow() fun send(command: Command) { GlobalScope.launch(IO) { - _commands.emit(command) + _commands.emit(command) } } diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt index 7fb8123..fbd5e81 100644 --- a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt +++ b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt @@ -10,10 +10,8 @@ import audio.funkwhale.ffa.model.DownloadInfo import audio.funkwhale.ffa.repositories.Repository import com.github.kittinunf.fuel.core.FuelError import com.github.kittinunf.fuel.core.Request -import com.github.kittinunf.fuel.core.ResponseDeserializable import com.google.android.exoplayer2.offline.Download import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.squareup.picasso.Picasso import com.squareup.picasso.RequestCreator import kotlinx.coroutines.CompletableDeferred @@ -23,7 +21,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import net.openid.appauth.ClientSecretPost -import java.io.Reader import java.text.SimpleDateFormat import java.util.Date import kotlin.coroutines.CoroutineContext diff --git a/app/src/main/java/audio/funkwhale/ffa/views/NowPlayingView.kt b/app/src/main/java/audio/funkwhale/ffa/views/NowPlayingView.kt index d4133b0..7ad7374 100644 --- a/app/src/main/java/audio/funkwhale/ffa/views/NowPlayingView.kt +++ b/app/src/main/java/audio/funkwhale/ffa/views/NowPlayingView.kt @@ -52,7 +52,7 @@ class NowPlayingView : MaterialCardView { viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { gestureDetectorCallback = OnGestureDetection() - gestureDetector = GestureDetector(context, gestureDetectorCallback) + gestureDetector = GestureDetector(context, gestureDetectorCallback!!) setOnTouchListener { _, motionEvent -> val ret = gestureDetector?.onTouchEvent(motionEvent) ?: false @@ -128,8 +128,8 @@ class NowPlayingView : MaterialCardView { } override fun onFling( - firstMotionEvent: MotionEvent?, - secondMotionEvent: MotionEvent?, + firstMotionEvent: MotionEvent, + secondMotionEvent: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { @@ -195,7 +195,7 @@ class NowPlayingView : MaterialCardView { return true } - override fun onSingleTapUp(e: MotionEvent?): Boolean { + override fun onSingleTapUp(e: MotionEvent): Boolean { layoutParams.let { if (height != minHeight) return true From fa48937b56c5679928728516196c2a065d8ecbde Mon Sep 17 00:00:00 2001 From: Ryan Harg Date: Tue, 6 Dec 2022 09:37:20 +0100 Subject: [PATCH 13/13] Set required flag for pendingIntent --- .../ffa/playback/MediaControlsManager.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt b/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt index 36b5302..9e1faee 100644 --- a/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt +++ b/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt @@ -2,6 +2,7 @@ package audio.funkwhale.ffa.playback import android.app.Notification import android.app.PendingIntent +import android.app.PendingIntent.FLAG_IMMUTABLE import android.app.Service import android.content.Intent import android.support.v4.media.session.MediaSessionCompat @@ -21,7 +22,11 @@ import kotlinx.coroutines.Dispatchers.Default import kotlinx.coroutines.launch import org.koin.java.KoinJavaComponent.inject -class MediaControlsManager(val context: Service, private val scope: CoroutineScope, private val mediaSession: MediaSessionCompat) { +class MediaControlsManager( + val context: Service, + private val scope: CoroutineScope, + private val mediaSession: MediaSessionCompat +) { companion object { const val NOTIFICATION_ACTION_OPEN_QUEUE = 0 @@ -41,8 +46,10 @@ class MediaControlsManager(val context: Service, private val scope: CoroutineSco } scope.launch(Default) { - val openIntent = Intent(context, MainActivity::class.java).apply { action = NOTIFICATION_ACTION_OPEN_QUEUE.toString() } - val openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, 0) + val openIntent = Intent(context, MainActivity::class.java).apply { + action = NOTIFICATION_ACTION_OPEN_QUEUE.toString() + } + val openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, FLAG_IMMUTABLE) val coverUrl = maybeNormalizeUrl(track.album?.cover()) @@ -98,7 +105,8 @@ class MediaControlsManager(val context: Service, private val scope: CoroutineSco if (playing) { context.startForeground(AppContext.NOTIFICATION_MEDIA_CONTROL, it) } else { - NotificationManagerCompat.from(context).notify(AppContext.NOTIFICATION_MEDIA_CONTROL, it) + NotificationManagerCompat.from(context) + .notify(AppContext.NOTIFICATION_MEDIA_CONTROL, it) } }