Media3 has a nice API for getting media files but I am running into a permission error.
In my manifest I have a service that has permission to listen to notifications
<service android:name=".NotificationService"
android:label="NotificationService"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
This is what the notification service looks like:
package com.aatorque.stats
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.google.common.util.concurrent.FutureCallback
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.MoreExecutors
import timber.log.Timber
class NotificationService : Service() {
override fun onCreate() {
super.onCreate()
val sessionToken = SessionToken.getAllServiceTokens(this)
val listener = object : Player.Listener {
override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
Timber.d("artist ${mediaMetadata.artist}")
super.onMediaMetadataChanged(mediaMetadata)
}
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
super.onMediaItemTransition(mediaItem, reason)
Timber.d("artist ${mediaItem?.mediaMetadata?.artist}")
}
}
for (token in sessionToken) {
val controller = MediaController.Builder(this, token).buildAsync()
Futures.addCallback(controller, object : FutureCallback<MediaController> {
override fun onSuccess(result: MediaController?) {
result?.addListener(listener)
Timber.d("success ${result?.mediaMetadata?.artist}")
}
override fun onFailure(t: Throwable) {
Timber.d(t, "failure ${token.packageName}")
}
}, MoreExecutors.directExecutor())
}
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
I can see it getting all the services in getAllServiceTokens
. However all the apps I care about reject the connection request:
failure com.spotify.music
java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:67)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:57)
at androidx.media3.session.MediaController.release(MediaController.java:529)
at androidx.media3.session.MediaControllerImplLegacy$ConnectionCallback.onConnectionFailed(MediaControllerImplLegacy.java:1720)
at android.support.v4.media.MediaBrowserCompat$ConnectionCallback$ConnectionCallbackApi21.onConnectionFailed(MediaBrowserCompat.java:721)
at android.media.browse.MediaBrowser$7.run(MediaBrowser.java:649)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8762)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Is there a simple way to get what is currently playing without listening to intents? I have my app enabled to listen to notifications and Spotify enabled to allow other apps to see what it is playing. I don't want to use APIs specific to one application.