mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-16 19:50:35 +01:00
Started refactoring events to ReactiveX
This commit is contained in:
parent
f0c02f5551
commit
5eaf9cccb1
@ -43,6 +43,8 @@ ext.versions = [
|
|||||||
timber : "4.7.1",
|
timber : "4.7.1",
|
||||||
fastScroll : "2.0.1",
|
fastScroll : "2.0.1",
|
||||||
colorPicker : "2.2.3",
|
colorPicker : "2.2.3",
|
||||||
|
rxJava : "3.1.2",
|
||||||
|
rxAndroid : "3.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
ext.gradlePlugins = [
|
ext.gradlePlugins = [
|
||||||
@ -91,6 +93,8 @@ ext.other = [
|
|||||||
fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll",
|
fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll",
|
||||||
sortListView : "com.github.tzugen:drag-sort-listview:$versions.sortListView",
|
sortListView : "com.github.tzugen:drag-sort-listview:$versions.sortListView",
|
||||||
colorPickerView : "com.github.skydoves:colorpickerview:$versions.colorPicker",
|
colorPickerView : "com.github.skydoves:colorpickerview:$versions.colorPicker",
|
||||||
|
rxJava : "io.reactivex.rxjava3:rxjava:$versions.rxJava",
|
||||||
|
rxAndroid : "io.reactivex.rxjava3:rxandroid:$versions.rxAndroid",
|
||||||
]
|
]
|
||||||
|
|
||||||
ext.testing = [
|
ext.testing = [
|
||||||
|
@ -106,6 +106,8 @@ dependencies {
|
|||||||
implementation other.fastScroll
|
implementation other.fastScroll
|
||||||
implementation other.sortListView
|
implementation other.sortListView
|
||||||
implementation other.colorPickerView
|
implementation other.colorPickerView
|
||||||
|
implementation other.rxJava
|
||||||
|
implementation other.rxAndroid
|
||||||
|
|
||||||
kapt androidSupport.room
|
kapt androidSupport.room
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import org.moire.ultrasonic.domain.MusicDirectory;
|
|||||||
import org.moire.ultrasonic.domain.PlayerState;
|
import org.moire.ultrasonic.domain.PlayerState;
|
||||||
import org.moire.ultrasonic.service.DownloadFile;
|
import org.moire.ultrasonic.service.DownloadFile;
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||||
|
import org.moire.ultrasonic.service.RxBus;
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider;
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider;
|
||||||
import org.moire.ultrasonic.util.Constants;
|
import org.moire.ultrasonic.util.Constants;
|
||||||
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
|
||||||
@ -26,6 +27,7 @@ import org.moire.ultrasonic.util.Settings;
|
|||||||
import org.moire.ultrasonic.util.Util;
|
import org.moire.ultrasonic.util.Util;
|
||||||
|
|
||||||
import kotlin.Lazy;
|
import kotlin.Lazy;
|
||||||
|
import kotlin.Unit;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
import static org.koin.java.KoinJavaComponent.inject;
|
import static org.koin.java.KoinJavaComponent.inject;
|
||||||
@ -70,8 +72,6 @@ public class NowPlayingFragment extends Fragment {
|
|||||||
nowPlayingArtist = view.findViewById(R.id.now_playing_artist);
|
nowPlayingArtist = view.findViewById(R.id.now_playing_artist);
|
||||||
|
|
||||||
nowPlayingEventListener = new NowPlayingEventListener() {
|
nowPlayingEventListener = new NowPlayingEventListener() {
|
||||||
@Override
|
|
||||||
public void onDismissNowPlaying() { }
|
|
||||||
@Override
|
@Override
|
||||||
public void onHideNowPlaying() { }
|
public void onHideNowPlaying() { }
|
||||||
@Override
|
@Override
|
||||||
@ -177,7 +177,7 @@ public class NowPlayingFragment extends Fragment {
|
|||||||
{
|
{
|
||||||
if (deltaY < 0)
|
if (deltaY < 0)
|
||||||
{
|
{
|
||||||
nowPlayingEventDistributor.getValue().raiseNowPlayingDismissedEvent();
|
RxBus.INSTANCE.getDismissNowPlayingCommandPublisher().onNext(Unit.INSTANCE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (deltaY > 0)
|
if (deltaY > 0)
|
||||||
|
@ -31,12 +31,12 @@ import org.moire.ultrasonic.log.FileLoggerTree;
|
|||||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
||||||
import org.moire.ultrasonic.service.Consumer;
|
import org.moire.ultrasonic.service.Consumer;
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||||
|
import org.moire.ultrasonic.service.RxBus;
|
||||||
import org.moire.ultrasonic.util.Constants;
|
import org.moire.ultrasonic.util.Constants;
|
||||||
import org.moire.ultrasonic.util.FileUtil;
|
import org.moire.ultrasonic.util.FileUtil;
|
||||||
import org.moire.ultrasonic.util.MediaSessionHandler;
|
import org.moire.ultrasonic.util.MediaSessionHandler;
|
||||||
import org.moire.ultrasonic.util.PermissionUtil;
|
import org.moire.ultrasonic.util.PermissionUtil;
|
||||||
import org.moire.ultrasonic.util.Settings;
|
import org.moire.ultrasonic.util.Settings;
|
||||||
import org.moire.ultrasonic.util.ThemeChangedEventDistributor;
|
|
||||||
import org.moire.ultrasonic.util.TimeSpanPreference;
|
import org.moire.ultrasonic.util.TimeSpanPreference;
|
||||||
import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat;
|
import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat;
|
||||||
import org.moire.ultrasonic.util.Util;
|
import org.moire.ultrasonic.util.Util;
|
||||||
@ -44,6 +44,7 @@ import org.moire.ultrasonic.util.Util;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import kotlin.Lazy;
|
import kotlin.Lazy;
|
||||||
|
import kotlin.Unit;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
import static org.koin.java.KoinJavaComponent.inject;
|
import static org.koin.java.KoinJavaComponent.inject;
|
||||||
@ -89,7 +90,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
|
|
||||||
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||||
private final Lazy<PermissionUtil> permissionUtil = inject(PermissionUtil.class);
|
private final Lazy<PermissionUtil> permissionUtil = inject(PermissionUtil.class);
|
||||||
private final Lazy<ThemeChangedEventDistributor> themeChangedEventDistributor = inject(ThemeChangedEventDistributor.class);
|
|
||||||
private final Lazy<MediaSessionHandler> mediaSessionHandler = inject(MediaSessionHandler.class);
|
private final Lazy<MediaSessionHandler> mediaSessionHandler = inject(MediaSessionHandler.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -192,7 +192,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
} else if (Constants.PREFERENCES_KEY_ID3_TAGS.equals(key)) {
|
} else if (Constants.PREFERENCES_KEY_ID3_TAGS.equals(key)) {
|
||||||
showArtistPicture.setEnabled(sharedPreferences.getBoolean(key, false));
|
showArtistPicture.setEnabled(sharedPreferences.getBoolean(key, false));
|
||||||
} else if (Constants.PREFERENCES_KEY_THEME.equals(key)) {
|
} else if (Constants.PREFERENCES_KEY_THEME.equals(key)) {
|
||||||
themeChangedEventDistributor.getValue().RaiseThemeChangedEvent();
|
RxBus.INSTANCE.getThemeChangedEventPublisher().onNext(Unit.INSTANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import androidx.navigation.ui.setupWithNavController
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
@ -43,6 +44,7 @@ import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
|||||||
import org.moire.ultrasonic.service.DownloadFile
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
||||||
|
import org.moire.ultrasonic.service.RxBus
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
import org.moire.ultrasonic.util.Constants
|
import org.moire.ultrasonic.util.Constants
|
||||||
import org.moire.ultrasonic.util.FileUtil
|
import org.moire.ultrasonic.util.FileUtil
|
||||||
@ -52,8 +54,6 @@ import org.moire.ultrasonic.util.PermissionUtil
|
|||||||
import org.moire.ultrasonic.util.ServerColor
|
import org.moire.ultrasonic.util.ServerColor
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
|
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
|
||||||
import org.moire.ultrasonic.util.ThemeChangedEventDistributor
|
|
||||||
import org.moire.ultrasonic.util.ThemeChangedEventListener
|
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -75,14 +75,13 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||||
private lateinit var nowPlayingEventListener: NowPlayingEventListener
|
private lateinit var nowPlayingEventListener: NowPlayingEventListener
|
||||||
private lateinit var themeChangedEventListener: ThemeChangedEventListener
|
private var themeChangedEventSubscription: Disposable? = null
|
||||||
|
|
||||||
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
||||||
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
|
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
|
||||||
private val mediaPlayerController: MediaPlayerController by inject()
|
private val mediaPlayerController: MediaPlayerController by inject()
|
||||||
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
||||||
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
|
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
|
||||||
private val themeChangedEventDistributor: ThemeChangedEventDistributor by inject()
|
|
||||||
private val permissionUtil: PermissionUtil by inject()
|
private val permissionUtil: PermissionUtil by inject()
|
||||||
private val activeServerProvider: ActiveServerProvider by inject()
|
private val activeServerProvider: ActiveServerProvider by inject()
|
||||||
private val serverRepository: ServerSettingDao by inject()
|
private val serverRepository: ServerSettingDao by inject()
|
||||||
@ -169,12 +168,13 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
showWelcomeDialog()
|
showWelcomeDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
nowPlayingEventListener = object : NowPlayingEventListener {
|
RxBus.dismissNowPlayingCommandObservable.subscribe {
|
||||||
override fun onDismissNowPlaying() {
|
|
||||||
nowPlayingHidden = true
|
nowPlayingHidden = true
|
||||||
hideNowPlaying()
|
hideNowPlaying()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nowPlayingEventListener = object : NowPlayingEventListener {
|
||||||
|
|
||||||
override fun onHideNowPlaying() {
|
override fun onHideNowPlaying() {
|
||||||
hideNowPlaying()
|
hideNowPlaying()
|
||||||
}
|
}
|
||||||
@ -184,12 +184,11 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
themeChangedEventListener = object : ThemeChangedEventListener {
|
themeChangedEventSubscription = RxBus.themeChangedEventObservable.subscribe {
|
||||||
override fun onThemeChanged() { recreate() }
|
recreate()
|
||||||
}
|
}
|
||||||
|
|
||||||
nowPlayingEventDistributor.subscribe(nowPlayingEventListener)
|
nowPlayingEventDistributor.subscribe(nowPlayingEventListener)
|
||||||
themeChangedEventDistributor.subscribe(themeChangedEventListener)
|
|
||||||
|
|
||||||
serverRepository.liveServerCount().observe(
|
serverRepository.liveServerCount().observe(
|
||||||
this,
|
this,
|
||||||
@ -238,7 +237,7 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
|
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
|
||||||
themeChangedEventDistributor.unsubscribe(themeChangedEventListener)
|
themeChangedEventSubscription?.dispose()
|
||||||
imageLoaderProvider.clearImageLoader()
|
imageLoaderProvider.clearImageLoader()
|
||||||
permissionUtil.onForegroundApplicationStopped()
|
permissionUtil.onForegroundApplicationStopped()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import org.moire.ultrasonic.util.MediaSessionEventDistributor
|
|||||||
import org.moire.ultrasonic.util.MediaSessionHandler
|
import org.moire.ultrasonic.util.MediaSessionHandler
|
||||||
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
||||||
import org.moire.ultrasonic.util.PermissionUtil
|
import org.moire.ultrasonic.util.PermissionUtil
|
||||||
import org.moire.ultrasonic.util.ThemeChangedEventDistributor
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Koin module contains the registration of general classes needed for Ultrasonic
|
* This Koin module contains the registration of general classes needed for Ultrasonic
|
||||||
@ -18,7 +17,6 @@ val applicationModule = module {
|
|||||||
single { ImageLoaderProvider(androidContext()) }
|
single { ImageLoaderProvider(androidContext()) }
|
||||||
single { PermissionUtil(androidContext()) }
|
single { PermissionUtil(androidContext()) }
|
||||||
single { NowPlayingEventDistributor() }
|
single { NowPlayingEventDistributor() }
|
||||||
single { ThemeChangedEventDistributor() }
|
|
||||||
single { MediaSessionEventDistributor() }
|
single { MediaSessionEventDistributor() }
|
||||||
single { MediaSessionHandler() }
|
single { MediaSessionHandler() }
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import android.support.v4.media.MediaDescriptionCompat
|
|||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import androidx.media.MediaBrowserServiceCompat
|
import androidx.media.MediaBrowserServiceCompat
|
||||||
import androidx.media.utils.MediaConstants
|
import androidx.media.utils.MediaConstants
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@ -93,16 +94,17 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
|
|||||||
private val useId3Tags get() = Settings.shouldUseId3Tags
|
private val useId3Tags get() = Settings.shouldUseId3Tags
|
||||||
private val musicFolderId get() = activeServerProvider.getActiveServer().musicFolderId
|
private val musicFolderId get() = activeServerProvider.getActiveServer().musicFolderId
|
||||||
|
|
||||||
|
private var mediaSessionTokenSubscription: Disposable? = null
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
mediaSessionTokenSubscription = RxBus.mediaSessionTokenObservable.subscribe {
|
||||||
|
if (sessionToken == null) sessionToken = it
|
||||||
|
}
|
||||||
|
|
||||||
mediaSessionEventListener = object : MediaSessionEventListener {
|
mediaSessionEventListener = object : MediaSessionEventListener {
|
||||||
override fun onMediaSessionTokenCreated(token: MediaSessionCompat.Token) {
|
|
||||||
if (sessionToken == null) {
|
|
||||||
sessionToken = token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlayFromMediaIdRequested(mediaId: String?, extras: Bundle?) {
|
override fun onPlayFromMediaIdRequested(mediaId: String?, extras: Bundle?) {
|
||||||
Timber.d(
|
Timber.d(
|
||||||
@ -182,6 +184,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
mediaSessionTokenSubscription?.dispose()
|
||||||
mediaSessionEventDistributor.unsubscribe(mediaSessionEventListener)
|
mediaSessionEventDistributor.unsubscribe(mediaSessionEventListener)
|
||||||
mediaSessionHandler.release()
|
mediaSessionHandler.release()
|
||||||
serviceJob.cancel()
|
serviceJob.cancel()
|
||||||
|
@ -14,6 +14,7 @@ import android.content.IntentFilter
|
|||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
@ -39,7 +40,7 @@ class MediaPlayerLifecycleSupport : KoinComponent {
|
|||||||
|
|
||||||
private var created = false
|
private var created = false
|
||||||
private var headsetEventReceiver: BroadcastReceiver? = null
|
private var headsetEventReceiver: BroadcastReceiver? = null
|
||||||
private lateinit var mediaSessionEventListener: MediaSessionEventListener
|
private var mediaButtonEventSubscription: Disposable? = null
|
||||||
|
|
||||||
fun onCreate() {
|
fun onCreate() {
|
||||||
onCreate(false, null)
|
onCreate(false, null)
|
||||||
@ -52,13 +53,10 @@ class MediaPlayerLifecycleSupport : KoinComponent {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaSessionEventListener = object : MediaSessionEventListener {
|
mediaButtonEventSubscription = RxBus.mediaButtonEventObservable.subscribe {
|
||||||
override fun onMediaButtonEvent(keyEvent: KeyEvent?) {
|
handleKeyEvent(it)
|
||||||
if (keyEvent != null) handleKeyEvent(keyEvent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaSessionEventDistributor.subscribe(mediaSessionEventListener)
|
|
||||||
registerHeadsetReceiver()
|
registerHeadsetReceiver()
|
||||||
mediaPlayerController.onCreate()
|
mediaPlayerController.onCreate()
|
||||||
if (autoPlay) mediaPlayerController.preload()
|
if (autoPlay) mediaPlayerController.preload()
|
||||||
@ -98,9 +96,8 @@ class MediaPlayerLifecycleSupport : KoinComponent {
|
|||||||
mediaPlayerController.playerPosition
|
mediaPlayerController.playerPosition
|
||||||
)
|
)
|
||||||
|
|
||||||
mediaSessionEventDistributor.unsubscribe(mediaSessionEventListener)
|
|
||||||
|
|
||||||
mediaPlayerController.clear(false)
|
mediaPlayerController.clear(false)
|
||||||
|
mediaButtonEventSubscription?.dispose()
|
||||||
applicationContext().unregisterReceiver(headsetEventReceiver)
|
applicationContext().unregisterReceiver(headsetEventReceiver)
|
||||||
mediaPlayerController.onDestroy()
|
mediaPlayerController.onDestroy()
|
||||||
|
|
||||||
@ -165,12 +162,7 @@ class MediaPlayerLifecycleSupport : KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val headsetIntentFilter: IntentFilter =
|
val headsetIntentFilter = IntentFilter(AudioManager.ACTION_HEADSET_PLUG)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
IntentFilter(AudioManager.ACTION_HEADSET_PLUG)
|
|
||||||
} else {
|
|
||||||
IntentFilter(Intent.ACTION_HEADSET_PLUG)
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationContext().registerReceiver(headsetEventReceiver, headsetIntentFilter)
|
applicationContext().registerReceiver(headsetEventReceiver, headsetIntentFilter)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import android.support.v4.media.session.MediaSessionCompat
|
|||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
@ -73,6 +74,7 @@ class MediaPlayerService : Service() {
|
|||||||
private var isInForeground = false
|
private var isInForeground = false
|
||||||
private var notificationBuilder: NotificationCompat.Builder? = null
|
private var notificationBuilder: NotificationCompat.Builder? = null
|
||||||
private lateinit var mediaSessionEventListener: MediaSessionEventListener
|
private lateinit var mediaSessionEventListener: MediaSessionEventListener
|
||||||
|
private var mediaSessionTokenSubscription: Disposable? = null
|
||||||
|
|
||||||
private val repeatMode: RepeatMode
|
private val repeatMode: RepeatMode
|
||||||
get() = Settings.repeatMode
|
get() = Settings.repeatMode
|
||||||
@ -102,11 +104,11 @@ class MediaPlayerService : Service() {
|
|||||||
|
|
||||||
localMediaPlayer.onNextSongRequested = Runnable { setNextPlaying() }
|
localMediaPlayer.onNextSongRequested = Runnable { setNextPlaying() }
|
||||||
|
|
||||||
mediaSessionEventListener = object : MediaSessionEventListener {
|
mediaSessionTokenSubscription = RxBus.mediaSessionTokenObservable.subscribe {
|
||||||
override fun onMediaSessionTokenCreated(token: MediaSessionCompat.Token) {
|
mediaSessionToken = it
|
||||||
mediaSessionToken = token
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaSessionEventListener = object : MediaSessionEventListener {
|
||||||
override fun onSkipToQueueItemRequested(id: Long) {
|
override fun onSkipToQueueItemRequested(id: Long) {
|
||||||
play(id.toInt())
|
play(id.toInt())
|
||||||
}
|
}
|
||||||
@ -134,6 +136,7 @@ class MediaPlayerService : Service() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
instance = null
|
instance = null
|
||||||
try {
|
try {
|
||||||
|
mediaSessionTokenSubscription?.dispose()
|
||||||
mediaSessionEventDistributor.unsubscribe(mediaSessionEventListener)
|
mediaSessionEventDistributor.unsubscribe(mediaSessionEventListener)
|
||||||
mediaSessionHandler.release()
|
mediaSessionHandler.release()
|
||||||
|
|
||||||
@ -357,19 +360,11 @@ class MediaPlayerService : Service() {
|
|||||||
private fun setupOnCurrentPlayingChangedHandler() {
|
private fun setupOnCurrentPlayingChangedHandler() {
|
||||||
localMediaPlayer.onCurrentPlayingChanged = { currentPlaying: DownloadFile? ->
|
localMediaPlayer.onCurrentPlayingChanged = { currentPlaying: DownloadFile? ->
|
||||||
|
|
||||||
if (currentPlaying != null) {
|
Util.broadcastNewTrackInfo(this@MediaPlayerService, currentPlaying?.song)
|
||||||
Util.broadcastNewTrackInfo(this@MediaPlayerService, currentPlaying.song)
|
|
||||||
Util.broadcastA2dpMetaDataChange(
|
Util.broadcastA2dpMetaDataChange(
|
||||||
this@MediaPlayerService, playerPosition, currentPlaying,
|
this@MediaPlayerService, playerPosition, currentPlaying,
|
||||||
downloader.all.size, downloader.currentPlayingIndex + 1
|
downloader.all.size, downloader.currentPlayingIndex + 1
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Util.broadcastNewTrackInfo(this@MediaPlayerService, null)
|
|
||||||
Util.broadcastA2dpMetaDataChange(
|
|
||||||
this@MediaPlayerService, playerPosition, null,
|
|
||||||
downloader.all.size, downloader.currentPlayingIndex + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update widget
|
// Update widget
|
||||||
val playerState = localMediaPlayer.playerState
|
val playerState = localMediaPlayer.playerState
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package org.moire.ultrasonic.service
|
||||||
|
|
||||||
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.core.Observable
|
||||||
|
import io.reactivex.rxjava3.observables.ConnectableObservable
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
object RxBus {
|
||||||
|
var mediaSessionTokenPublisher: PublishSubject<MediaSessionCompat.Token> =
|
||||||
|
PublishSubject.create()
|
||||||
|
val mediaSessionTokenObservable: Observable<MediaSessionCompat.Token> =
|
||||||
|
mediaSessionTokenPublisher.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.replay(1)
|
||||||
|
.autoConnect()
|
||||||
|
.doOnEach { Timber.d("RxBus mediaSessionTokenPublisher onEach $it")}
|
||||||
|
|
||||||
|
val mediaButtonEventPublisher: PublishSubject<KeyEvent> =
|
||||||
|
PublishSubject.create()
|
||||||
|
val mediaButtonEventObservable: Observable<KeyEvent> =
|
||||||
|
mediaButtonEventPublisher.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnEach { Timber.d("RxBus mediaButtonEventPublisher onEach $it")}
|
||||||
|
|
||||||
|
val themeChangedEventPublisher: PublishSubject<Unit> =
|
||||||
|
PublishSubject.create()
|
||||||
|
val themeChangedEventObservable: Observable<Unit> =
|
||||||
|
themeChangedEventPublisher.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnEach { Timber.d("RxBus themeChangedEventPublisher onEach $it")}
|
||||||
|
|
||||||
|
val dismissNowPlayingCommandPublisher: PublishSubject<Unit> =
|
||||||
|
PublishSubject.create()
|
||||||
|
val dismissNowPlayingCommandObservable: Observable<Unit> =
|
||||||
|
dismissNowPlayingCommandPublisher.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnEach { Timber.d("RxBus dismissNowPlayingCommandPublisher onEach $it")}
|
||||||
|
|
||||||
|
fun releaseMediaSessionToken() { mediaSessionTokenPublisher = PublishSubject.create() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -23,30 +23,12 @@ class MediaSessionEventDistributor {
|
|||||||
|
|
||||||
fun subscribe(listener: MediaSessionEventListener) {
|
fun subscribe(listener: MediaSessionEventListener) {
|
||||||
eventListenerList.add(listener)
|
eventListenerList.add(listener)
|
||||||
|
|
||||||
synchronized(this) {
|
|
||||||
if (cachedToken != null)
|
|
||||||
listener.onMediaSessionTokenCreated(cachedToken!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unsubscribe(listener: MediaSessionEventListener) {
|
fun unsubscribe(listener: MediaSessionEventListener) {
|
||||||
eventListenerList.remove(listener)
|
eventListenerList.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun releaseCachedMediaSessionToken() {
|
|
||||||
synchronized(this) {
|
|
||||||
cachedToken = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun raiseMediaSessionTokenCreatedEvent(token: MediaSessionCompat.Token) {
|
|
||||||
synchronized(this) {
|
|
||||||
cachedToken = token
|
|
||||||
eventListenerList.forEach { listener -> listener.onMediaSessionTokenCreated(token) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun raisePlayFromMediaIdRequestedEvent(mediaId: String?, extras: Bundle?) {
|
fun raisePlayFromMediaIdRequestedEvent(mediaId: String?, extras: Bundle?) {
|
||||||
eventListenerList.forEach {
|
eventListenerList.forEach {
|
||||||
listener ->
|
listener ->
|
||||||
@ -61,8 +43,4 @@ class MediaSessionEventDistributor {
|
|||||||
fun raiseSkipToQueueItemRequestedEvent(id: Long) {
|
fun raiseSkipToQueueItemRequestedEvent(id: Long) {
|
||||||
eventListenerList.forEach { listener -> listener.onSkipToQueueItemRequested(id) }
|
eventListenerList.forEach { listener -> listener.onSkipToQueueItemRequested(id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun raiseMediaButtonEvent(keyEvent: KeyEvent?) {
|
|
||||||
eventListenerList.forEach { listener -> listener.onMediaButtonEvent(keyEvent) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ import android.view.KeyEvent
|
|||||||
* Callback interface for MediaSession related event subscribers
|
* Callback interface for MediaSession related event subscribers
|
||||||
*/
|
*/
|
||||||
interface MediaSessionEventListener {
|
interface MediaSessionEventListener {
|
||||||
fun onMediaSessionTokenCreated(token: MediaSessionCompat.Token) {}
|
// fun onMediaSessionTokenCreated(token: MediaSessionCompat.Token) {}
|
||||||
fun onPlayFromMediaIdRequested(mediaId: String?, extras: Bundle?) {}
|
fun onPlayFromMediaIdRequested(mediaId: String?, extras: Bundle?) {}
|
||||||
fun onPlayFromSearchRequested(query: String?, extras: Bundle?) {}
|
fun onPlayFromSearchRequested(query: String?, extras: Bundle?) {}
|
||||||
fun onSkipToQueueItemRequested(id: Long) {}
|
fun onSkipToQueueItemRequested(id: Long) {}
|
||||||
fun onMediaButtonEvent(keyEvent: KeyEvent?) {}
|
// fun onMediaButtonEvent(keyEvent: KeyEvent?) {}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import org.moire.ultrasonic.domain.PlayerState
|
|||||||
import org.moire.ultrasonic.imageloader.BitmapUtils
|
import org.moire.ultrasonic.imageloader.BitmapUtils
|
||||||
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver
|
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver
|
||||||
import org.moire.ultrasonic.service.DownloadFile
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
|
import org.moire.ultrasonic.service.RxBus
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
private const val INTENT_CODE_MEDIA_BUTTON = 161
|
private const val INTENT_CODE_MEDIA_BUTTON = 161
|
||||||
@ -53,7 +54,7 @@ class MediaSessionHandler : KoinComponent {
|
|||||||
if (referenceCount > 0) return
|
if (referenceCount > 0) return
|
||||||
|
|
||||||
mediaSession?.isActive = false
|
mediaSession?.isActive = false
|
||||||
mediaSessionEventDistributor.releaseCachedMediaSessionToken()
|
RxBus.releaseMediaSessionToken()
|
||||||
mediaSession?.release()
|
mediaSession?.release()
|
||||||
mediaSession = null
|
mediaSession = null
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ class MediaSessionHandler : KoinComponent {
|
|||||||
|
|
||||||
mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService")
|
mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService")
|
||||||
val mediaSessionToken = mediaSession?.sessionToken ?: return
|
val mediaSessionToken = mediaSession?.sessionToken ?: return
|
||||||
mediaSessionEventDistributor.raiseMediaSessionTokenCreatedEvent(mediaSessionToken)
|
RxBus.mediaSessionTokenPublisher.onNext(mediaSessionToken)
|
||||||
|
|
||||||
updateMediaButtonReceiver()
|
updateMediaButtonReceiver()
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ class MediaSessionHandler : KoinComponent {
|
|||||||
// This probably won't be necessary once we implement more
|
// This probably won't be necessary once we implement more
|
||||||
// of the modern media APIs, like the MediaController etc.
|
// of the modern media APIs, like the MediaController etc.
|
||||||
val event = mediaButtonEvent.extras!!["android.intent.extra.KEY_EVENT"] as KeyEvent?
|
val event = mediaButtonEvent.extras!!["android.intent.extra.KEY_EVENT"] as KeyEvent?
|
||||||
mediaSessionEventDistributor.raiseMediaButtonEvent(event)
|
event?.let { RxBus.mediaButtonEventPublisher.onNext(it) }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,4 @@ class NowPlayingEventDistributor {
|
|||||||
fun raiseHideNowPlayingEvent() {
|
fun raiseHideNowPlayingEvent() {
|
||||||
eventListenerList.forEach { listener -> listener.onHideNowPlaying() }
|
eventListenerList.forEach { listener -> listener.onHideNowPlaying() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun raiseNowPlayingDismissedEvent() {
|
|
||||||
eventListenerList.forEach { listener -> listener.onDismissNowPlaying() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ package org.moire.ultrasonic.util
|
|||||||
* Callback interface for Now Playing event subscribers
|
* Callback interface for Now Playing event subscribers
|
||||||
*/
|
*/
|
||||||
interface NowPlayingEventListener {
|
interface NowPlayingEventListener {
|
||||||
fun onDismissNowPlaying()
|
|
||||||
fun onHideNowPlaying()
|
fun onHideNowPlaying()
|
||||||
fun onShowNowPlaying()
|
fun onShowNowPlaying()
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package org.moire.ultrasonic.util
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class distributes Theme change related events to its subscribers.
|
|
||||||
* It is a primitive implementation of a pub-sub event bus
|
|
||||||
*/
|
|
||||||
class ThemeChangedEventDistributor {
|
|
||||||
var eventListenerList: MutableList<ThemeChangedEventListener> =
|
|
||||||
listOf<ThemeChangedEventListener>().toMutableList()
|
|
||||||
|
|
||||||
fun subscribe(listener: ThemeChangedEventListener) {
|
|
||||||
eventListenerList.add(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unsubscribe(listener: ThemeChangedEventListener) {
|
|
||||||
eventListenerList.remove(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RaiseThemeChangedEvent() {
|
|
||||||
eventListenerList.forEach { listener -> listener.onThemeChanged() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package org.moire.ultrasonic.util
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback interface for Theme change event subscribers
|
|
||||||
*/
|
|
||||||
interface ThemeChangedEventListener {
|
|
||||||
fun onThemeChanged()
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user