Put Previous/Play/Next in compact notification
This commit is contained in:
parent
cf367ead92
commit
545b65921e
|
@ -7,149 +7,42 @@
|
||||||
|
|
||||||
package org.moire.ultrasonic.playback
|
package org.moire.ultrasonic.playback
|
||||||
|
|
||||||
/*
|
|
||||||
import android.app.Notification
|
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.common.util.Assertions
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.common.util.Util
|
import androidx.media3.common.util.Util.getAvailableCommands
|
||||||
|
import androidx.media3.session.CommandButton
|
||||||
|
import androidx.media3.session.DefaultMediaNotificationProvider
|
||||||
import androidx.media3.session.MediaController
|
import androidx.media3.session.MediaController
|
||||||
import androidx.media3.session.MediaNotification
|
import androidx.media3.session.MediaNotification
|
||||||
import androidx.media3.session.MediaNotification.ActionFactory
|
import androidx.media3.session.MediaSession
|
||||||
import org.moire.ultrasonic.R
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a copy of DefaultMediaNotificationProvider.java with some small changes
|
|
||||||
* I have opened a bug https://github.com/androidx/media/issues/65 to make it easier to customize
|
|
||||||
* the icons and actions without creating our own copy of this class..
|
|
||||||
*/
|
|
||||||
//@UnstableApi
|
|
||||||
/* package */
|
|
||||||
// Disabled while getting updated
|
|
||||||
/*
|
|
||||||
internal class MediaNotificationProvider(context: Context) :
|
|
||||||
MediaNotification.Provider {
|
|
||||||
private val context: Context = context.applicationContext
|
|
||||||
private val notificationManager: NotificationManager = Assertions.checkStateNotNull(
|
|
||||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
)
|
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@UnstableApi
|
||||||
override fun createNotification(
|
class MediaNotificationProvider(context: Context) : DefaultMediaNotificationProvider(context) {
|
||||||
mediaController: MediaController,
|
|
||||||
actionFactory: ActionFactory,
|
|
||||||
onNotificationChangedCallback: MediaNotification.Provider.Callback
|
|
||||||
): MediaNotification {
|
|
||||||
ensureNotificationChannel()
|
|
||||||
val builder: NotificationCompat.Builder = NotificationCompat.Builder(
|
|
||||||
context,
|
|
||||||
NOTIFICATION_CHANNEL_ID
|
|
||||||
)
|
|
||||||
// Skip to previous action.
|
|
||||||
builder.addAction(
|
|
||||||
actionFactory.createMediaAction(
|
|
||||||
IconCompat.createWithResource(
|
|
||||||
context,
|
|
||||||
R.drawable.media3_notification_seek_to_previous
|
|
||||||
),
|
|
||||||
context.getString(R.string.media3_controls_seek_to_previous_description),
|
|
||||||
ActionFactory.COMMAND_SKIP_TO_PREVIOUS
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (mediaController.playbackState == Player.STATE_ENDED ||
|
|
||||||
!mediaController.playWhenReady
|
|
||||||
) {
|
|
||||||
// Play action.
|
|
||||||
builder.addAction(
|
|
||||||
actionFactory.createMediaAction(
|
|
||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_play),
|
|
||||||
context.getString(R.string.media3_controls_play_description),
|
|
||||||
ActionFactory.COMMAND_PLAY
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Pause action.
|
|
||||||
builder.addAction(
|
|
||||||
actionFactory.createMediaAction(
|
|
||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_pause),
|
|
||||||
context.getString(R.string.media3_controls_pause_description),
|
|
||||||
ActionFactory.COMMAND_PAUSE
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// Skip to next action.
|
|
||||||
builder.addAction(
|
|
||||||
actionFactory.createMediaAction(
|
|
||||||
IconCompat.createWithResource(context, R.drawable.media3_notification_seek_to_next),
|
|
||||||
context.getString(R.string.media3_controls_seek_to_next_description),
|
|
||||||
ActionFactory.COMMAND_SKIP_TO_NEXT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set metadata info in the notification.
|
override fun addNotificationActions(
|
||||||
val metadata = mediaController.mediaMetadata
|
mediaSession: MediaSession,
|
||||||
builder.setContentTitle(metadata.title).setContentText(metadata.artist)
|
mediaButtons: MutableList<CommandButton>,
|
||||||
if (metadata.artworkData != null) {
|
builder: NotificationCompat.Builder,
|
||||||
val artworkBitmap =
|
actionFactory: MediaNotification.ActionFactory
|
||||||
BitmapFactory.decodeByteArray(metadata.artworkData, 0, metadata.artworkData!!.size)
|
): IntArray {
|
||||||
builder.setLargeIcon(artworkBitmap)
|
return super.addNotificationActions(mediaSession, mediaButtons, builder, actionFactory)
|
||||||
}
|
|
||||||
val mediaStyle = androidx.media.app.NotificationCompat.MediaStyle()
|
|
||||||
.setShowActionsInCompactView(0, 1, 2)
|
|
||||||
val notification: Notification = builder
|
|
||||||
.setContentIntent(mediaController.sessionActivity)
|
|
||||||
.setOnlyAlertOnce(true)
|
|
||||||
.setSmallIcon(getSmallIconResId())
|
|
||||||
.setStyle(mediaStyle)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setOngoing(false)
|
|
||||||
.build()
|
|
||||||
return MediaNotification(
|
|
||||||
NOTIFICATION_ID,
|
|
||||||
notification
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleCustomAction(
|
override fun getMediaButtons(
|
||||||
mediaController: MediaController,
|
playerCommands: Player.Commands,
|
||||||
action: String,
|
customLayout: MutableList<CommandButton>,
|
||||||
extras: Bundle
|
playWhenReady: Boolean
|
||||||
) {
|
): MutableList<CommandButton> {
|
||||||
// We don't handle custom commands.
|
val commands = super.getMediaButtons(playerCommands, customLayout, playWhenReady)
|
||||||
|
|
||||||
|
commands.forEachIndexed { index, command ->
|
||||||
|
command.extras.putInt(COMMAND_KEY_COMPACT_VIEW_INDEX, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureNotificationChannel() {
|
return commands
|
||||||
if (Util.SDK_INT < Build.VERSION_CODES.O ||
|
|
||||||
notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) != null
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
val channel = NotificationChannel(
|
|
||||||
NOTIFICATION_CHANNEL_ID,
|
|
||||||
NOTIFICATION_CHANNEL_NAME,
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
)
|
|
||||||
channel.setShowBadge(false)
|
|
||||||
|
|
||||||
notificationManager.createNotificationChannel(channel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic"
|
|
||||||
private const val NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service"
|
|
||||||
private const val NOTIFICATION_ID = 3032
|
|
||||||
private fun getSmallIconResId(): Int {
|
|
||||||
return R.drawable.ic_stat_ultrasonic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import androidx.media3.datasource.DataSource
|
||||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
import androidx.media3.session.DefaultMediaNotificationProvider
|
|
||||||
import androidx.media3.session.MediaLibraryService
|
import androidx.media3.session.MediaLibraryService
|
||||||
import androidx.media3.session.MediaSession
|
import androidx.media3.session.MediaSession
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -90,7 +89,7 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
|
||||||
private fun initializeSessionAndPlayer() {
|
private fun initializeSessionAndPlayer() {
|
||||||
if (isStarted) return
|
if (isStarted) return
|
||||||
|
|
||||||
setMediaNotificationProvider(DefaultMediaNotificationProvider(UApp.applicationContext()))
|
setMediaNotificationProvider(MediaNotificationProvider(UApp.applicationContext()))
|
||||||
|
|
||||||
val subsonicAPIClient: SubsonicAPIClient by inject()
|
val subsonicAPIClient: SubsonicAPIClient by inject()
|
||||||
|
|
||||||
|
|
|
@ -659,7 +659,6 @@ fun Track.toMediaItem(): MediaItem {
|
||||||
val bitrate = Settings.maxBitRate
|
val bitrate = Settings.maxBitRate
|
||||||
val uri = "$id|$bitrate|$filePath"
|
val uri = "$id|$bitrate|$filePath"
|
||||||
|
|
||||||
|
|
||||||
val rmd = MediaItem.RequestMetadata.Builder()
|
val rmd = MediaItem.RequestMetadata.Builder()
|
||||||
.setMediaUri(uri.toUri())
|
.setMediaUri(uri.toUri())
|
||||||
.build()
|
.build()
|
||||||
|
|
Loading…
Reference in New Issue