Skip to content

Instantly share code, notes, and snippets.

@izyaboi
Last active October 3, 2021 17:25
Show Gist options
  • Save izyaboi/5d53cd3dada60fb2d024255576e5af97 to your computer and use it in GitHub Desktop.
Save izyaboi/5d53cd3dada60fb2d024255576e5af97 to your computer and use it in GitHub Desktop.
package com.example.bmradio
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.core.view.WindowCompat
import com.example.bmradio.service.PlayerNotificationService
import com.example.bmradio.ui.theme.BMRadioTheme
import com.google.accompanist.insets.ProvideWindowInsets
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.InternalCoroutinesApi
import com.google.android.exoplayer2.SimpleExoPlayer
import android.content.ComponentName
import android.content.Context
import android.os.IBinder
import android.content.ServiceConnection
import android.util.AttributeSet
import android.view.View
import com.google.android.exoplayer2.util.Util
@ExperimentalCoroutinesApi
@AndroidEntryPoint
class MainActivity : ComponentActivity(){
private var player: SimpleExoPlayer? = null
private lateinit var playerNotificationService: PlayerNotificationService
private var bound = false
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, service: IBinder) {
val binder = service as PlayerNotificationService.LocalBinder
playerNotificationService = binder.getService()
bound = true
initPlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
bound = false
}
}
private fun initPlayer() {
if(bound){
player = playerNotificationService.player
}
}
@ExperimentalAnimationApi
@FlowPreview
@InternalCoroutinesApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this,PlayerNotificationService::class.java)
Util.startForegroundService(this,intent)
initPlayer()
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
BMRadioTheme {
ProvideWindowInsets{
Surface(color = MaterialTheme.colors.background) {
MainScreen(player)
}
}
}
}
}
override fun onStart() {
super.onStart()
Intent(this, PlayerNotificationService::class.java).also {
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
unbindService(serviceConnection)
bound = false
}
}
package com.example.bmradio.service
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.graphics.Bitmap
import android.os.IBinder
import com.example.bmradio.MainActivity
import com.example.bmradio.R
import com.example.bmradio.di.AppModule
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import kotlinx.coroutines.ExperimentalCoroutinesApi
import android.os.Binder
@ExperimentalCoroutinesApi
class PlayerNotificationService : Service() {
var player: SimpleExoPlayer? = null
private lateinit var dataSourceFactory: DefaultHttpDataSource.Factory
private lateinit var playerNotificationManager: PlayerNotificationManager
private val binder: IBinder = LocalBinder()
private var notificationId = 123;
private var channelId = "channelId"
override fun onCreate() {
super.onCreate()
initPlayer()
}
private fun initPlayer() {
val context = this
player = SimpleExoPlayer.Builder(this)
.build()
.apply {
dataSourceFactory = DefaultHttpDataSource.Factory()
val source = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(AppModule.RadioUrl))
setMediaSource(source)
prepare()
}
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
channelId,
R.string.channel_name,
R.string.channel_desc,
notificationId,
object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player): PendingIntent? {
// return pending intent
val intent = Intent(context,MainActivity::class.java)
return PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
//pass description here
override fun getCurrentContentText(player: Player): String? {
return "Description"
}
//pass title (mostly playing audio name)
override fun getCurrentContentTitle(player: Player): String {
return "Title"
}
// pass image as bitmap
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return null
}
},
object : PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification,
onGoing: Boolean) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(
notificationId: Int,
dismissedByUser: Boolean
) {
stopSelf()
}
}
)
playerNotificationManager.setPlayer(player)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if(player == null){
initPlayer()
}
return START_STICKY
}
// detach player
override fun onDestroy() {
playerNotificationManager.setPlayer(null)
player?.release()
super.onDestroy()
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
stopSelf()
}
inner class LocalBinder : Binder() {
fun getService(): PlayerNotificationService = this@PlayerNotificationService
}
override fun onBind(p0: Intent?): IBinder = binder
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment