improve player notification

This commit is contained in:
Bnyro 2022-08-07 18:10:13 +02:00
parent 39a26a9820
commit e25cbf343b

View File

@ -3,9 +3,11 @@ package com.github.libretube.services
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.IBinder import android.os.IBinder
@ -15,6 +17,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.github.libretube.BACKGROUND_CHANNEL_ID import com.github.libretube.BACKGROUND_CHANNEL_ID
import com.github.libretube.PLAYER_NOTIFICATION_ID import com.github.libretube.PLAYER_NOTIFICATION_ID
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.activities.MainActivity
import com.github.libretube.obj.Segment import com.github.libretube.obj.Segment
import com.github.libretube.obj.Segments import com.github.libretube.obj.Segments
import com.github.libretube.obj.Streams import com.github.libretube.obj.Streams
@ -35,6 +38,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.net.URL
/** /**
* Loads the selected videos audio in background mode with a notification area. * Loads the selected videos audio in background mode with a notification area.
@ -106,9 +110,6 @@ class BackgroundMode : Service() {
* Initializes the [player] with the [MediaItem]. * Initializes the [player] with the [MediaItem].
*/ */
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// destroy the old player
destroyPlayer()
// get the intent arguments // get the intent arguments
videoId = intent?.getStringExtra("videoId")!! videoId = intent?.getStringExtra("videoId")!!
val position = intent.getLongExtra("position", 0L) val position = intent.getLongExtra("position", 0L)
@ -194,9 +195,6 @@ class BackgroundMode : Service() {
val videoId = response!! val videoId = response!!
.relatedStreams!![0].url.toID() .relatedStreams!![0].url.toID()
// destroy previous notification and player
destroyPlayer()
// play new video on background // play new video on background
this.videoId = videoId this.videoId = videoId
this.segmentData = null this.segmentData = null
@ -204,6 +202,85 @@ class BackgroundMode : Service() {
} }
} }
/**
* The [DescriptionAdapter] is used to show title, uploaderName and thumbnail of the video in the notification
* Basic example [here](https://github.com/AnthonyMarkD/AudioPlayerSampleTest)
*/
inner class DescriptionAdapter() :
PlayerNotificationManager.MediaDescriptionAdapter {
/**
* sets the title of the notification
*/
override fun getCurrentContentTitle(player: Player): CharSequence {
// return controller.metadata.description.title.toString()
return response?.title!!
}
/**
* overrides the action when clicking the notification
*/
override fun createCurrentContentIntent(player: Player): PendingIntent? {
// return controller.sessionActivity
/**
* starts a new MainActivity Intent when the player notification is clicked
* it doesn't start a completely new MainActivity because the MainActivity's launchMode
* is set to "singleTop" in the AndroidManifest (important!!!)
* that's the only way to launch back into the previous activity (e.g. the player view
*/
val intent = Intent(this@BackgroundMode, MainActivity::class.java)
return PendingIntent.getActivity(this@BackgroundMode, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}
/**
* the description of the notification (below the title)
*/
override fun getCurrentContentText(player: Player): CharSequence? {
// return controller.metadata.description.subtitle.toString()
return response?.uploader
}
/**
* return the icon/thumbnail of the video
*/
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
lateinit var bitmap: Bitmap
/**
* running on a new thread to prevent a NetworkMainThreadException
*/
val thread = Thread {
try {
/**
* try to GET the thumbnail from the URL
*/
val inputStream = URL(response?.thumbnailUrl).openStream()
bitmap = BitmapFactory.decodeStream(inputStream)
} catch (ex: java.lang.Exception) {
ex.printStackTrace()
}
}
thread.start()
thread.join()
/**
* returns the scaled bitmap if it got fetched successfully
*/
return try {
val resizedBitmap = Bitmap.createScaledBitmap(
bitmap,
bitmap.width,
bitmap.width,
false
)
resizedBitmap
} catch (e: Exception) {
null
}
}
}
/** /**
* Initializes the [playerNotification] attached to the [player] and shows it. * Initializes the [playerNotification] attached to the [player] and shows it.
*/ */
@ -212,12 +289,7 @@ class BackgroundMode : Service() {
.Builder(this, PLAYER_NOTIFICATION_ID, BACKGROUND_CHANNEL_ID) .Builder(this, PLAYER_NOTIFICATION_ID, BACKGROUND_CHANNEL_ID)
// set the description of the notification // set the description of the notification
.setMediaDescriptionAdapter( .setMediaDescriptionAdapter(
DescriptionAdapter( DescriptionAdapter()
response?.title!!,
response?.uploader!!,
response?.thumbnailUrl!!,
this
)
) )
.build() .build()
playerNotification?.apply { playerNotification?.apply {
@ -284,17 +356,6 @@ class BackgroundMode : Service() {
} }
} }
private fun destroyPlayer() {
// clear old player and its notification
playerNotification = null
player = null
// kill old notification
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
notificationManager.cancel(PLAYER_NOTIFICATION_ID)
}
override fun onBind(p0: Intent?): IBinder? { override fun onBind(p0: Intent?): IBinder? {
TODO("Not yet implemented") TODO("Not yet implemented")
} }