2021-07-13 19:25:37 +02:00
|
|
|
/*
|
2021-07-18 13:17:29 +02:00
|
|
|
* MediaPlayerLifecycleSupport.kt
|
|
|
|
* Copyright (C) 2009-2021 Ultrasonic developers
|
|
|
|
*
|
|
|
|
* Distributed under terms of the GNU GPLv3 license.
|
2021-07-13 19:25:37 +02:00
|
|
|
*/
|
2021-07-18 13:17:29 +02:00
|
|
|
|
2021-07-13 19:25:37 +02:00
|
|
|
package org.moire.ultrasonic.service
|
|
|
|
|
|
|
|
import android.content.BroadcastReceiver
|
|
|
|
import android.content.Intent
|
|
|
|
import android.view.KeyEvent
|
2021-10-31 15:22:15 +01:00
|
|
|
import io.reactivex.rxjava3.disposables.Disposable
|
2021-07-13 19:25:37 +02:00
|
|
|
import org.koin.core.component.KoinComponent
|
|
|
|
import org.koin.core.component.inject
|
|
|
|
import org.moire.ultrasonic.app.UApp.Companion.applicationContext
|
|
|
|
import org.moire.ultrasonic.util.CacheCleaner
|
|
|
|
import org.moire.ultrasonic.util.Constants
|
2021-11-09 22:20:41 +01:00
|
|
|
import org.moire.ultrasonic.util.Util.ifNotNull
|
2021-07-13 19:25:37 +02:00
|
|
|
import timber.log.Timber
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class is responsible for handling received events for the Media Player implementation
|
|
|
|
*/
|
|
|
|
class MediaPlayerLifecycleSupport : KoinComponent {
|
2021-10-23 16:37:19 +02:00
|
|
|
private val playbackStateSerializer by inject<PlaybackStateSerializer>()
|
2021-07-13 19:25:37 +02:00
|
|
|
private val mediaPlayerController by inject<MediaPlayerController>()
|
|
|
|
|
|
|
|
private var created = false
|
|
|
|
private var headsetEventReceiver: BroadcastReceiver? = null
|
2021-10-31 15:22:15 +01:00
|
|
|
private var mediaButtonEventSubscription: Disposable? = null
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
fun onCreate() {
|
|
|
|
onCreate(false, null)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onCreate(autoPlay: Boolean, afterCreated: Runnable?) {
|
|
|
|
|
|
|
|
if (created) {
|
|
|
|
afterCreated?.run()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
mediaPlayerController.onCreate()
|
|
|
|
if (autoPlay) mediaPlayerController.preload()
|
|
|
|
|
2021-10-23 16:50:33 +02:00
|
|
|
playbackStateSerializer.deserialize {
|
|
|
|
|
|
|
|
mediaPlayerController.restore(
|
|
|
|
it!!.songs,
|
|
|
|
it.currentPlayingIndex,
|
|
|
|
it.currentPlayingPosition,
|
|
|
|
autoPlay,
|
|
|
|
false
|
|
|
|
)
|
|
|
|
|
|
|
|
afterCreated?.run()
|
|
|
|
}
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
CacheCleaner().clean()
|
|
|
|
created = true
|
|
|
|
Timber.i("LifecycleSupport created")
|
|
|
|
}
|
|
|
|
|
|
|
|
fun onDestroy() {
|
|
|
|
|
|
|
|
if (!created) return
|
|
|
|
|
2022-04-04 21:18:07 +02:00
|
|
|
playbackStateSerializer.serializeNow(
|
|
|
|
mediaPlayerController.playList,
|
|
|
|
mediaPlayerController.currentMediaItemIndex,
|
|
|
|
mediaPlayerController.playerPosition
|
|
|
|
)
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
mediaPlayerController.clear(false)
|
2021-10-31 15:22:15 +01:00
|
|
|
mediaButtonEventSubscription?.dispose()
|
2021-07-13 19:25:37 +02:00
|
|
|
applicationContext().unregisterReceiver(headsetEventReceiver)
|
|
|
|
mediaPlayerController.onDestroy()
|
|
|
|
|
|
|
|
created = false
|
|
|
|
Timber.i("LifecycleSupport destroyed")
|
|
|
|
}
|
|
|
|
|
|
|
|
fun receiveIntent(intent: Intent?) {
|
|
|
|
|
|
|
|
if (intent == null) return
|
|
|
|
|
|
|
|
val intentAction = intent.action
|
|
|
|
if (intentAction == null || intentAction.isEmpty()) return
|
|
|
|
|
|
|
|
Timber.i("Received intent: %s", intentAction)
|
|
|
|
|
|
|
|
if (intentAction == Constants.CMD_PROCESS_KEYCODE) {
|
|
|
|
if (intent.extras != null) {
|
|
|
|
val event = intent.extras!![Intent.EXTRA_KEY_EVENT] as KeyEvent?
|
2021-11-09 22:20:41 +01:00
|
|
|
event.ifNotNull { handleKeyEvent(it) }
|
2021-07-13 19:25:37 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
handleUltrasonicIntent(intentAction)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-04 18:18:52 +02:00
|
|
|
@Suppress("MagicNumber", "ComplexMethod")
|
2021-07-13 19:25:37 +02:00
|
|
|
private fun handleKeyEvent(event: KeyEvent) {
|
|
|
|
|
|
|
|
if (event.action != KeyEvent.ACTION_DOWN || event.repeatCount > 0) return
|
|
|
|
|
2022-04-03 23:57:50 +02:00
|
|
|
val keyCode: Int = event.keyCode
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
val autoStart =
|
|
|
|
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
|
2022-04-05 10:10:24 +02:00
|
|
|
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY ||
|
|
|
|
keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
|
|
|
|
keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
|
|
|
|
keyCode == KeyEvent.KEYCODE_MEDIA_NEXT
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
// We can receive intents (e.g. MediaButton) when everything is stopped, so we need to start
|
|
|
|
onCreate(autoStart) {
|
|
|
|
when (keyCode) {
|
|
|
|
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
|
|
|
|
KeyEvent.KEYCODE_HEADSETHOOK -> mediaPlayerController.togglePlayPause()
|
|
|
|
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> mediaPlayerController.previous()
|
|
|
|
KeyEvent.KEYCODE_MEDIA_NEXT -> mediaPlayerController.next()
|
|
|
|
KeyEvent.KEYCODE_MEDIA_STOP -> mediaPlayerController.stop()
|
2022-04-03 23:57:50 +02:00
|
|
|
KeyEvent.KEYCODE_MEDIA_PLAY -> mediaPlayerController.play()
|
2021-07-13 19:25:37 +02:00
|
|
|
KeyEvent.KEYCODE_MEDIA_PAUSE -> mediaPlayerController.pause()
|
|
|
|
KeyEvent.KEYCODE_1 -> mediaPlayerController.setSongRating(1)
|
|
|
|
KeyEvent.KEYCODE_2 -> mediaPlayerController.setSongRating(2)
|
|
|
|
KeyEvent.KEYCODE_3 -> mediaPlayerController.setSongRating(3)
|
|
|
|
KeyEvent.KEYCODE_4 -> mediaPlayerController.setSongRating(4)
|
|
|
|
KeyEvent.KEYCODE_5 -> mediaPlayerController.setSongRating(5)
|
|
|
|
KeyEvent.KEYCODE_STAR -> mediaPlayerController.toggleSongStarred()
|
|
|
|
else -> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function processes the intent that could come from other applications.
|
|
|
|
*/
|
2022-04-04 18:18:52 +02:00
|
|
|
@Suppress("ComplexMethod")
|
2022-04-04 17:59:12 +02:00
|
|
|
private fun handleUltrasonicIntent(action: String) {
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
val isRunning = created
|
|
|
|
|
|
|
|
// If Ultrasonic is not running, do nothing to stop or pause
|
2022-04-04 17:59:12 +02:00
|
|
|
if (!isRunning && (action == Constants.CMD_PAUSE || action == Constants.CMD_STOP))
|
2022-04-03 23:57:50 +02:00
|
|
|
return
|
2021-07-13 19:25:37 +02:00
|
|
|
|
2022-04-04 17:59:12 +02:00
|
|
|
val autoStart = action == Constants.CMD_PLAY ||
|
2022-04-05 10:10:24 +02:00
|
|
|
action == Constants.CMD_RESUME_OR_PLAY ||
|
|
|
|
action == Constants.CMD_TOGGLEPAUSE ||
|
|
|
|
action == Constants.CMD_PREVIOUS ||
|
|
|
|
action == Constants.CMD_NEXT
|
2021-07-13 19:25:37 +02:00
|
|
|
|
|
|
|
// We can receive intents when everything is stopped, so we need to start
|
|
|
|
onCreate(autoStart) {
|
2022-04-04 17:59:12 +02:00
|
|
|
when (action) {
|
2021-07-13 19:25:37 +02:00
|
|
|
Constants.CMD_PLAY -> mediaPlayerController.play()
|
2021-07-18 13:17:29 +02:00
|
|
|
Constants.CMD_RESUME_OR_PLAY ->
|
|
|
|
// If Ultrasonic wasn't running, the autoStart is enough to resume,
|
|
|
|
// no need to call anything
|
2021-07-13 19:25:37 +02:00
|
|
|
if (isRunning) mediaPlayerController.resumeOrPlay()
|
|
|
|
|
|
|
|
Constants.CMD_NEXT -> mediaPlayerController.next()
|
|
|
|
Constants.CMD_PREVIOUS -> mediaPlayerController.previous()
|
|
|
|
Constants.CMD_TOGGLEPAUSE -> mediaPlayerController.togglePlayPause()
|
2022-04-03 23:57:50 +02:00
|
|
|
Constants.CMD_STOP -> mediaPlayerController.stop()
|
2021-07-13 19:25:37 +02:00
|
|
|
Constants.CMD_PAUSE -> mediaPlayerController.pause()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-18 13:17:29 +02:00
|
|
|
}
|