From db0669098c1294bf57b46f9c6cd51a09fb9fc2e3 Mon Sep 17 00:00:00 2001 From: James Wells <14866211+SaintDubious@users.noreply.github.com> Date: Sun, 4 Jul 2021 16:42:18 -0400 Subject: [PATCH] Another Attempt at Auto --- ultrasonic/src/main/AndroidManifest.xml | 6 + .../AutoMediaPlayerService.kt} | 212 +++++++++--------- .../ultrasonic/service/MediaPlayerService.kt | 51 ++--- 3 files changed, 130 insertions(+), 139 deletions(-) rename ultrasonic/src/main/kotlin/org/moire/ultrasonic/{util/AndroidAutoMediaBrowser.kt => service/AutoMediaPlayerService.kt} (62%) diff --git a/ultrasonic/src/main/AndroidManifest.xml b/ultrasonic/src/main/AndroidManifest.xml index 7aa13db8..f3a0d39c 100644 --- a/ultrasonic/src/main/AndroidManifest.xml +++ b/ultrasonic/src/main/AndroidManifest.xml @@ -56,6 +56,12 @@ + + + diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/AndroidAutoMediaBrowser.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AutoMediaPlayerService.kt similarity index 62% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/AndroidAutoMediaBrowser.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AutoMediaPlayerService.kt index d951d514..2eb7fca5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/AndroidAutoMediaBrowser.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AutoMediaPlayerService.kt @@ -1,6 +1,5 @@ -package org.moire.ultrasonic.util +package org.moire.ultrasonic.service -import android.app.Application import android.os.Bundle import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaDescriptionCompat @@ -8,24 +7,26 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.media.MediaBrowserServiceCompat 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.ByteArrayOutputStream import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.util.concurrent.ExecutorService 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 artistListModel: ArtistListModel = ArtistListModel(application) + val mediaPlayerService : MediaPlayerService = MediaPlayerService() + var albumListModel: AlbumListModel? = null + var artistListModel: ArtistListModel? = null val executorService: ExecutorService = Executors.newFixedThreadPool(4) var maximumRootChildLimit: Int = 4 @@ -44,11 +45,11 @@ class AndroidAutoMediaBrowser(application: Application) { private val MEDIA_BROWSER_EXTRA_MEDIA_ID = "_Ultrasonic_mb_extra_media_id_" class AlbumListObserver( - val idPrefix: String, - val result: MediaBrowserServiceCompat.Result>, - data: LiveData> + val idPrefix: String, + val result: MediaBrowserServiceCompat.Result>, + data: LiveData> ) : - Observer> { + Observer> { private var liveData: LiveData>? = null @@ -73,15 +74,15 @@ class AndroidAutoMediaBrowser(application: Application) { val mediaItems: MutableList = mutableListOf() for (item in albumList) { val entryBuilder: MediaDescriptionCompat.Builder = - MediaDescriptionCompat.Builder() + MediaDescriptionCompat.Builder() entryBuilder - .setTitle(item.title) - .setMediaId(idPrefix + item.id) + .setTitle(item.title) + .setMediaId(idPrefix + item.id) mediaItems.add( - MediaBrowserCompat.MediaItem( - entryBuilder.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + entryBuilder.build(), + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) ) } @@ -90,11 +91,11 @@ class AndroidAutoMediaBrowser(application: Application) { } class ArtistListObserver( - val idPrefix: String, - val result: MediaBrowserServiceCompat.Result>, - data: LiveData> + val idPrefix: String, + val result: MediaBrowserServiceCompat.Result>, + data: LiveData> ) : - Observer> { + Observer> { private var liveData: LiveData>? = null @@ -119,15 +120,15 @@ class AndroidAutoMediaBrowser(application: Application) { val mediaItems: MutableList = mutableListOf() for (item in artistList) { val entryBuilder: MediaDescriptionCompat.Builder = - MediaDescriptionCompat.Builder() + MediaDescriptionCompat.Builder() entryBuilder - .setTitle(item.name) - .setMediaId(idPrefix + item.id) + .setTitle(item.name) + .setMediaId(idPrefix + item.id) mediaItems.add( - MediaBrowserCompat.MediaItem( - entryBuilder.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + entryBuilder.build(), + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) ) } @@ -135,15 +136,21 @@ class AndroidAutoMediaBrowser(application: Application) { } } - fun getRoot( - clientPackageName: String, - clientUid: Int, - rootHints: Bundle? - ): MediaBrowserServiceCompat.BrowserRoot { + override fun onCreate() { + super.onCreate() + + albumListModel = AlbumListModel(application) + artistListModel = ArtistListModel(application) + + mediaPlayerService.onCreate() + mediaPlayerService.updateMediaSession(null, PlayerState.IDLE) + } + + override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? { if (rootHints != null) { maximumRootChildLimit = rootHints.getInt( - MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT, - 4 + MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT, + 4 ) } // opt into the root tabs (because it's gonna be non-optional @@ -154,60 +161,56 @@ class AndroidAutoMediaBrowser(application: Application) { return MediaBrowserServiceCompat.BrowserRoot(MEDIA_BROWSER_ROOT_ID, extras) } - fun loadChildren( - parentMediaId: String, - result: MediaBrowserServiceCompat.Result> - ) { - + override fun onLoadChildren(parentId: String, result: Result>) { val mediaItems: MutableList = mutableListOf() - if (MEDIA_BROWSER_ROOT_ID == parentMediaId) { + if (MEDIA_BROWSER_ROOT_ID == parentId) { // Build the MediaItem objects for the top level, // and put them in the mediaItems list... var recentList: MediaDescriptionCompat.Builder = MediaDescriptionCompat.Builder() recentList.setTitle("Recent").setMediaId(MEDIA_BROWSER_RECENT_LIST_ROOT) mediaItems.add( - MediaBrowserCompat.MediaItem( - recentList.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + recentList.build(), + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) ) var albumList: MediaDescriptionCompat.Builder = MediaDescriptionCompat.Builder() albumList.setTitle("Albums").setMediaId(MEDIA_BROWSER_ALBUM_LIST_ROOT) mediaItems.add( - MediaBrowserCompat.MediaItem( - albumList.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + albumList.build(), + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) ) var artistList: MediaDescriptionCompat.Builder = MediaDescriptionCompat.Builder() artistList.setTitle("Artists").setMediaId(MEDIA_BROWSER_ARTIST_LIST_ROOT) mediaItems.add( - MediaBrowserCompat.MediaItem( - artistList.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + artistList.build(), + 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) 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) return - } else if (MEDIA_BROWSER_ARTIST_LIST_ROOT == parentMediaId) { + } else if (MEDIA_BROWSER_ARTIST_LIST_ROOT == parentId) { fetchArtistList(MEDIA_BROWSER_ARTIST_PREFIX, result) return - } else if (parentMediaId.startsWith(MEDIA_BROWSER_RECENT_PREFIX)) { - fetchTrackList(parentMediaId.substring(MEDIA_BROWSER_RECENT_PREFIX.length), result) + } else if (parentId.startsWith(MEDIA_BROWSER_RECENT_PREFIX)) { + fetchTrackList(parentId.substring(MEDIA_BROWSER_RECENT_PREFIX.length), result) return - } else if (parentMediaId.startsWith(MEDIA_BROWSER_ALBUM_PREFIX)) { - fetchTrackList(parentMediaId.substring(MEDIA_BROWSER_ALBUM_PREFIX.length), result) + } else if (parentId.startsWith(MEDIA_BROWSER_ALBUM_PREFIX)) { + fetchTrackList(parentId.substring(MEDIA_BROWSER_ALBUM_PREFIX.length), result) return - } else if (parentMediaId.startsWith(MEDIA_BROWSER_ARTIST_PREFIX)) { + } else if (parentId.startsWith(MEDIA_BROWSER_ARTIST_PREFIX)) { fetchArtistAlbumList( - parentMediaId.substring(MEDIA_BROWSER_ARTIST_PREFIX.length), - result + parentId.substring(MEDIA_BROWSER_ARTIST_PREFIX.length), + result ) return } else { @@ -217,13 +220,14 @@ class AndroidAutoMediaBrowser(application: Application) { result.sendResult(mediaItems) } + fun getBundleData(bundle: Bundle?): Pair>? { if (bundle == null) { return null } if (!bundle.containsKey(MEDIA_BROWSER_EXTRA_ALBUM_LIST) || - !bundle.containsKey(MEDIA_BROWSER_EXTRA_MEDIA_ID) + !bundle.containsKey(MEDIA_BROWSER_EXTRA_MEDIA_ID) ) { return null } @@ -231,58 +235,58 @@ class AndroidAutoMediaBrowser(application: Application) { val byteArrayInputStream = ByteArrayInputStream(bytes) val objectInputStream = ObjectInputStream(byteArrayInputStream) return Pair( - bundle.getString(MEDIA_BROWSER_EXTRA_MEDIA_ID), - objectInputStream.readObject() as List + bundle.getString(MEDIA_BROWSER_EXTRA_MEDIA_ID), + objectInputStream.readObject() as List ) } private fun fetchAlbumList( - type: AlbumListType, - idPrefix: String, - result: MediaBrowserServiceCompat.Result> + type: AlbumListType, + idPrefix: String, + result: MediaBrowserServiceCompat.Result> ) { - AlbumListObserver( - idPrefix, result, - albumListModel.albumList + AutoMediaPlayerService.AlbumListObserver( + idPrefix, result, + albumListModel!!.albumList ) val args: Bundle = Bundle() args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type.toString()) - albumListModel.getAlbumList(false, null, args) + albumListModel!!.getAlbumList(false, null, args) result.detach() } private fun fetchArtistList( - idPrefix: String, - result: MediaBrowserServiceCompat.Result> + idPrefix: String, + result: MediaBrowserServiceCompat.Result> ) { - ArtistListObserver(idPrefix, result, artistListModel.artists) + AutoMediaPlayerService.ArtistListObserver(idPrefix, result, artistListModel!!.artists) - artistListModel.getItems(false, null) + artistListModel!!.getItems(false, null) result.detach() } private fun fetchArtistAlbumList( - id: String, - result: MediaBrowserServiceCompat.Result> + id: String, + result: MediaBrowserServiceCompat.Result> ) { executorService.execute { val musicService = MusicServiceFactory.getMusicService() val musicDirectory = musicService.getMusicDirectory( - id, "", false + id, "", false ) val mediaItems: MutableList = mutableListOf() for (item in musicDirectory.getAllChild()) { val entryBuilder: MediaDescriptionCompat.Builder = - MediaDescriptionCompat.Builder() + MediaDescriptionCompat.Builder() entryBuilder.setTitle(item.title).setMediaId(MEDIA_BROWSER_ALBUM_PREFIX + item.id) mediaItems.add( - MediaBrowserCompat.MediaItem( - entryBuilder.build(), - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) + MediaBrowserCompat.MediaItem( + entryBuilder.build(), + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) ) } result.sendResult(mediaItems) @@ -291,14 +295,14 @@ class AndroidAutoMediaBrowser(application: Application) { } private fun fetchTrackList( - id: String, - result: MediaBrowserServiceCompat.Result> + id: String, + result: MediaBrowserServiceCompat.Result> ) { executorService.execute { val musicService = MusicServiceFactory.getMusicService() val albumDirectory = musicService.getAlbum( - id, "", false + id, "", false ) // The idea here is that we want to attach the full album list to every song, @@ -315,26 +319,26 @@ class AndroidAutoMediaBrowser(application: Application) { val extras = Bundle() extras.putByteArray( - MEDIA_BROWSER_EXTRA_ALBUM_LIST, - songList + MEDIA_BROWSER_EXTRA_ALBUM_LIST, + songList ) extras.putString( - MEDIA_BROWSER_EXTRA_MEDIA_ID, - item.id + MEDIA_BROWSER_EXTRA_MEDIA_ID, + item.id ) val entryBuilder: MediaDescriptionCompat.Builder = - MediaDescriptionCompat.Builder() + MediaDescriptionCompat.Builder() entryBuilder.setTitle(item.title).setMediaId(item.id).setExtras(extras) mediaItems.add( - MediaBrowserCompat.MediaItem( - entryBuilder.build(), - MediaBrowserCompat.MediaItem.FLAG_PLAYABLE - ) + MediaBrowserCompat.MediaItem( + entryBuilder.build(), + MediaBrowserCompat.MediaItem.FLAG_PLAYABLE + ) ) } result.sendResult(mediaItems) } result.detach() } -} +} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt index 1972bfaf..101a8f5d 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt @@ -7,15 +7,13 @@ package org.moire.ultrasonic.service -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent +import android.app.* import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle +import android.os.IBinder import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaMetadataCompat 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.receiver.MediaButtonIntentReceiver import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService -import org.moire.ultrasonic.util.AndroidAutoMediaBrowser -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 org.moire.ultrasonic.util.* import timber.log.Timber /** @@ -51,7 +45,8 @@ import timber.log.Timber * while the rest of the Ultrasonic App is in the background. */ @Suppress("LargeClass") -class MediaPlayerService : MediaBrowserServiceCompat() { +class MediaPlayerService : Service() { + private val binder: IBinder = SimpleServiceBinder(this) private val scrobbler = Scrobbler() private val jukeboxMediaPlayer by inject() @@ -62,20 +57,21 @@ class MediaPlayerService : MediaBrowserServiceCompat() { private val nowPlayingEventDistributor by inject() private val mediaPlayerLifecycleSupport by inject() - private var autoMediaBrowser: AndroidAutoMediaBrowser? = null private var mediaSession: MediaSessionCompat? = null + private var mediaSessionToken: MediaSessionCompat.Token? = null private var isInForeground = false private var notificationBuilder: NotificationCompat.Builder? = null private val repeatMode: RepeatMode get() = Util.getRepeatMode() + override fun onBind(intent: Intent): IBinder { + return binder + } + override fun onCreate() { super.onCreate() - autoMediaBrowser = AndroidAutoMediaBrowser(application) - updateMediaSession(null, PlayerState.IDLE) - downloader.onCreate() shufflePlayBuffer.onCreate() 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> - ) { - autoMediaBrowser!!.loadChildren(parentMediaId, result) - } - @Synchronized fun seekTo(position: Int) { 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") if (mediaSession == null) initMediaSessions() @@ -645,8 +626,8 @@ class MediaPlayerService : MediaBrowserServiceCompat() { // Use the Media Style, to enable native Android support for playback notification val style = androidx.media.app.NotificationCompat.MediaStyle() - if (getSessionToken() != null) { - style.setMediaSession(getSessionToken()) + if (mediaSessionToken != null) { + style.setMediaSession(mediaSessionToken) } // Clear old actions @@ -813,7 +794,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() { Timber.w("Creating media session") mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService") - setSessionToken(mediaSession!!.sessionToken) + mediaSessionToken = mediaSession!!.sessionToken updateMediaButtonReceiver() @@ -829,7 +810,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() { Timber.v("Media Session Callback: onPlay") } - +/* override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) { super.onPlayFromMediaId(mediaId, extras) @@ -857,7 +838,7 @@ class MediaPlayerService : MediaBrowserServiceCompat() { } Timber.v("Media Session Callback: onPlayFromMediaId") } - +*/ override fun onPause() { super.onPause() getPendingIntentForMediaAction(