Another Attempt at Auto

This commit is contained in:
James Wells 2021-07-04 16:42:18 -04:00
parent 04de4544ee
commit db0669098c
No known key found for this signature in database
GPG Key ID: DB1528F6EED16127
3 changed files with 130 additions and 139 deletions

View File

@ -56,6 +56,12 @@
<service <service
android:name=".service.MediaPlayerService" android:name=".service.MediaPlayerService"
android:label="Ultrasonic Media Player Service" android:label="Ultrasonic Media Player Service"
android:exported="false">
</service>
<service
android:name=".service.AutoMediaPlayerService"
android:label="Ultrasonic Auto Media Player Service"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>

View File

@ -1,6 +1,5 @@
package org.moire.ultrasonic.util package org.moire.ultrasonic.service
import android.app.Application
import android.os.Bundle import android.os.Bundle
import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaDescriptionCompat
@ -8,24 +7,26 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.media.MediaBrowserServiceCompat import androidx.media.MediaBrowserServiceCompat
import androidx.media.utils.MediaConstants import androidx.media.utils.MediaConstants
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.fragment.AlbumListModel
import org.moire.ultrasonic.fragment.ArtistListModel
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Pair
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.ObjectInputStream import java.io.ObjectInputStream
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.fragment.AlbumListModel
import org.moire.ultrasonic.fragment.ArtistListModel
import org.moire.ultrasonic.service.MusicServiceFactory
class AndroidAutoMediaBrowser(application: Application) { class AutoMediaPlayerService: MediaBrowserServiceCompat() {
val albumListModel: AlbumListModel = AlbumListModel(application) val mediaPlayerService : MediaPlayerService = MediaPlayerService()
val artistListModel: ArtistListModel = ArtistListModel(application) var albumListModel: AlbumListModel? = null
var artistListModel: ArtistListModel? = null
val executorService: ExecutorService = Executors.newFixedThreadPool(4) val executorService: ExecutorService = Executors.newFixedThreadPool(4)
var maximumRootChildLimit: Int = 4 var maximumRootChildLimit: Int = 4
@ -135,11 +136,17 @@ class AndroidAutoMediaBrowser(application: Application) {
} }
} }
fun getRoot( override fun onCreate() {
clientPackageName: String, super.onCreate()
clientUid: Int,
rootHints: Bundle? albumListModel = AlbumListModel(application)
): MediaBrowserServiceCompat.BrowserRoot { artistListModel = ArtistListModel(application)
mediaPlayerService.onCreate()
mediaPlayerService.updateMediaSession(null, PlayerState.IDLE)
}
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? {
if (rootHints != null) { if (rootHints != null) {
maximumRootChildLimit = rootHints.getInt( maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT, MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
@ -154,14 +161,10 @@ class AndroidAutoMediaBrowser(application: Application) {
return MediaBrowserServiceCompat.BrowserRoot(MEDIA_BROWSER_ROOT_ID, extras) return MediaBrowserServiceCompat.BrowserRoot(MEDIA_BROWSER_ROOT_ID, extras)
} }
fun loadChildren( override fun onLoadChildren(parentId: String, result: Result<List<MediaBrowserCompat.MediaItem>>) {
parentMediaId: String,
result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>>
) {
val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf() val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()
if (MEDIA_BROWSER_ROOT_ID == parentMediaId) { if (MEDIA_BROWSER_ROOT_ID == parentId) {
// Build the MediaItem objects for the top level, // Build the MediaItem objects for the top level,
// and put them in the mediaItems list... // and put them in the mediaItems list...
@ -189,24 +192,24 @@ class AndroidAutoMediaBrowser(application: Application) {
MediaBrowserCompat.MediaItem.FLAG_BROWSABLE MediaBrowserCompat.MediaItem.FLAG_BROWSABLE
) )
) )
} else if (MEDIA_BROWSER_RECENT_LIST_ROOT == parentMediaId) { } else if (MEDIA_BROWSER_RECENT_LIST_ROOT == parentId) {
fetchAlbumList(AlbumListType.RECENT, MEDIA_BROWSER_RECENT_PREFIX, result) fetchAlbumList(AlbumListType.RECENT, MEDIA_BROWSER_RECENT_PREFIX, result)
return return
} else if (MEDIA_BROWSER_ALBUM_LIST_ROOT == parentMediaId) { } else if (MEDIA_BROWSER_ALBUM_LIST_ROOT == parentId) {
fetchAlbumList(AlbumListType.SORTED_BY_NAME, MEDIA_BROWSER_ALBUM_PREFIX, result) fetchAlbumList(AlbumListType.SORTED_BY_NAME, MEDIA_BROWSER_ALBUM_PREFIX, result)
return return
} else if (MEDIA_BROWSER_ARTIST_LIST_ROOT == parentMediaId) { } else if (MEDIA_BROWSER_ARTIST_LIST_ROOT == parentId) {
fetchArtistList(MEDIA_BROWSER_ARTIST_PREFIX, result) fetchArtistList(MEDIA_BROWSER_ARTIST_PREFIX, result)
return return
} else if (parentMediaId.startsWith(MEDIA_BROWSER_RECENT_PREFIX)) { } else if (parentId.startsWith(MEDIA_BROWSER_RECENT_PREFIX)) {
fetchTrackList(parentMediaId.substring(MEDIA_BROWSER_RECENT_PREFIX.length), result) fetchTrackList(parentId.substring(MEDIA_BROWSER_RECENT_PREFIX.length), result)
return return
} else if (parentMediaId.startsWith(MEDIA_BROWSER_ALBUM_PREFIX)) { } else if (parentId.startsWith(MEDIA_BROWSER_ALBUM_PREFIX)) {
fetchTrackList(parentMediaId.substring(MEDIA_BROWSER_ALBUM_PREFIX.length), result) fetchTrackList(parentId.substring(MEDIA_BROWSER_ALBUM_PREFIX.length), result)
return return
} else if (parentMediaId.startsWith(MEDIA_BROWSER_ARTIST_PREFIX)) { } else if (parentId.startsWith(MEDIA_BROWSER_ARTIST_PREFIX)) {
fetchArtistAlbumList( fetchArtistAlbumList(
parentMediaId.substring(MEDIA_BROWSER_ARTIST_PREFIX.length), parentId.substring(MEDIA_BROWSER_ARTIST_PREFIX.length),
result result
) )
return return
@ -217,6 +220,7 @@ class AndroidAutoMediaBrowser(application: Application) {
result.sendResult(mediaItems) result.sendResult(mediaItems)
} }
fun getBundleData(bundle: Bundle?): Pair<String, List<MusicDirectory.Entry>>? { fun getBundleData(bundle: Bundle?): Pair<String, List<MusicDirectory.Entry>>? {
if (bundle == null) { if (bundle == null) {
return null return null
@ -241,14 +245,14 @@ class AndroidAutoMediaBrowser(application: Application) {
idPrefix: String, idPrefix: String,
result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>> result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>>
) { ) {
AlbumListObserver( AutoMediaPlayerService.AlbumListObserver(
idPrefix, result, idPrefix, result,
albumListModel.albumList albumListModel!!.albumList
) )
val args: Bundle = Bundle() val args: Bundle = Bundle()
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type.toString()) args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type.toString())
albumListModel.getAlbumList(false, null, args) albumListModel!!.getAlbumList(false, null, args)
result.detach() result.detach()
} }
@ -256,9 +260,9 @@ class AndroidAutoMediaBrowser(application: Application) {
idPrefix: String, idPrefix: String,
result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>> result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>>
) { ) {
ArtistListObserver(idPrefix, result, artistListModel.artists) AutoMediaPlayerService.ArtistListObserver(idPrefix, result, artistListModel!!.artists)
artistListModel.getItems(false, null) artistListModel!!.getItems(false, null)
result.detach() result.detach()
} }

View File

@ -7,15 +7,13 @@
package org.moire.ultrasonic.service package org.moire.ultrasonic.service
import android.app.Notification import android.app.*
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.IBinder
import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
@ -39,11 +37,7 @@ import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.AndroidAutoMediaBrowser import org.moire.ultrasonic.util.*
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.NowPlayingEventDistributor
import org.moire.ultrasonic.util.ShufflePlayBuffer
import org.moire.ultrasonic.util.Util
import timber.log.Timber import timber.log.Timber
/** /**
@ -51,7 +45,8 @@ import timber.log.Timber
* while the rest of the Ultrasonic App is in the background. * while the rest of the Ultrasonic App is in the background.
*/ */
@Suppress("LargeClass") @Suppress("LargeClass")
class MediaPlayerService : MediaBrowserServiceCompat() { class MediaPlayerService : Service() {
private val binder: IBinder = SimpleServiceBinder(this)
private val scrobbler = Scrobbler() private val scrobbler = Scrobbler()
private val jukeboxMediaPlayer by inject<JukeboxMediaPlayer>() private val jukeboxMediaPlayer by inject<JukeboxMediaPlayer>()
@ -62,20 +57,21 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
private val nowPlayingEventDistributor by inject<NowPlayingEventDistributor>() private val nowPlayingEventDistributor by inject<NowPlayingEventDistributor>()
private val mediaPlayerLifecycleSupport by inject<MediaPlayerLifecycleSupport>() private val mediaPlayerLifecycleSupport by inject<MediaPlayerLifecycleSupport>()
private var autoMediaBrowser: AndroidAutoMediaBrowser? = null
private var mediaSession: MediaSessionCompat? = null private var mediaSession: MediaSessionCompat? = null
private var mediaSessionToken: MediaSessionCompat.Token? = null
private var isInForeground = false private var isInForeground = false
private var notificationBuilder: NotificationCompat.Builder? = null private var notificationBuilder: NotificationCompat.Builder? = null
private val repeatMode: RepeatMode private val repeatMode: RepeatMode
get() = Util.getRepeatMode() get() = Util.getRepeatMode()
override fun onBind(intent: Intent): IBinder {
return binder
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
autoMediaBrowser = AndroidAutoMediaBrowser(application)
updateMediaSession(null, PlayerState.IDLE)
downloader.onCreate() downloader.onCreate()
shufflePlayBuffer.onCreate() shufflePlayBuffer.onCreate()
localMediaPlayer.init() localMediaPlayer.init()
@ -136,21 +132,6 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
} }
} }
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): MediaBrowserServiceCompat.BrowserRoot {
return autoMediaBrowser!!.getRoot(clientPackageName, clientUid, rootHints)
}
override fun onLoadChildren(
parentMediaId: String,
result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>>
) {
autoMediaBrowser!!.loadChildren(parentMediaId, result)
}
@Synchronized @Synchronized
fun seekTo(position: Int) { fun seekTo(position: Int) {
if (jukeboxMediaPlayer.isEnabled) { if (jukeboxMediaPlayer.isEnabled) {
@ -483,7 +464,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
} }
} }
private fun updateMediaSession(currentPlaying: DownloadFile?, playerState: PlayerState) { fun updateMediaSession(currentPlaying: DownloadFile?, playerState: PlayerState) {
Timber.d("Updating the MediaSession") Timber.d("Updating the MediaSession")
if (mediaSession == null) initMediaSessions() if (mediaSession == null) initMediaSessions()
@ -645,8 +626,8 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
// Use the Media Style, to enable native Android support for playback notification // Use the Media Style, to enable native Android support for playback notification
val style = androidx.media.app.NotificationCompat.MediaStyle() val style = androidx.media.app.NotificationCompat.MediaStyle()
if (getSessionToken() != null) { if (mediaSessionToken != null) {
style.setMediaSession(getSessionToken()) style.setMediaSession(mediaSessionToken)
} }
// Clear old actions // Clear old actions
@ -813,7 +794,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
Timber.w("Creating media session") Timber.w("Creating media session")
mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService") mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService")
setSessionToken(mediaSession!!.sessionToken) mediaSessionToken = mediaSession!!.sessionToken
updateMediaButtonReceiver() updateMediaButtonReceiver()
@ -829,7 +810,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
Timber.v("Media Session Callback: onPlay") Timber.v("Media Session Callback: onPlay")
} }
/*
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) { override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
super.onPlayFromMediaId(mediaId, extras) super.onPlayFromMediaId(mediaId, extras)
@ -857,7 +838,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() {
} }
Timber.v("Media Session Callback: onPlayFromMediaId") Timber.v("Media Session Callback: onPlayFromMediaId")
} }
*/
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
getPendingIntentForMediaAction( getPendingIntentForMediaAction(