Search code examples
androidandroid-fragmentskotlinandroid-service

ForegroundService not getting started from a fragment?


I'm trying to start a service from a fragment but my code doesn't seem to run properly or I think there is something wrong with how I deal with contexts. It runs ok when I start my service from inside an activity but it doesn't work inside a fragment.

This is my fragment class:

class OnAirFragment : BaseFragment() {

    private var play = "Play"
    private var playValue = false
    private lateinit var updatePlaybackUI: BroadcastReceiver

    private var playWhenReady = "Play State"
    private var playbackState = "Playback State"

    private var isClicked = false


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_on_air, container, false)

        view.start.setOnClickListener {
            Log.d("TEST", "TAP")
            if (!isClicked) {
                Log.d("TEST2", "TAP2")

                start.setBackgroundResource(R.drawable.ic_pause_empty)

                val intent = Intent(context, PlaybackService::class.java)
                intent.putExtra(play, playValue)
                Util.startForegroundService(context, intent)


                var intentToService = Intent("activity.to.service.transfer")
                intentToService.putExtra("x", true)

                context!!.sendBroadcast(intentToService)


                val filter = IntentFilter()
                filter.addAction("service.to.activity.transfer")
                updatePlaybackUI = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent?) {
                        // UI update here
                        var playPauseState = intent!!.getBooleanExtra(playWhenReady, true)
                        var stopState = intent.getIntExtra(playbackState, Int.MAX_VALUE)

                        if (!playPauseState || stopState == 1) {
                            start.setBackgroundResource(R.drawable.ic_play_empty)
                            isClicked = false

                        } else {
                            start.setBackgroundResource(R.drawable.ic_pause_empty)
                        }
                    }
                }
                context!!.registerReceiver(updatePlaybackUI, filter)
                isClicked = !isClicked

            } else {
                Log.d("TEST3", "TAP3")
                playValue = false

                start.setBackgroundResource(R.drawable.ic_play_empty)

                val intent = Intent(context, PlaybackService::class.java)
                intent.putExtra(play, playValue)
                context!!.stopService(intent)
                isClicked = !isClicked
            }

        }


        return view
    }
}

And this is my service class:

class PlaybackService : Service() {
    private var player: SimpleExoPlayer? = null
    private var playerNotificationManager: PlayerNotificationManager? = null
    private var mediaSession: MediaSessionCompat? = null

    private lateinit var receiver: BroadcastReceiver


    private var playWhenReady = "Play State"
    private var playbackState = "Playback State"

    override fun onCreate() {
        super.onCreate()
        val context = this

        player = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector())
        val dataSourceFactory = DefaultDataSourceFactory(
                context, Util.getUserAgent(context, "Exo"))

        val mediaUri = Uri.parse("http://www.radioideal.net:8026/;")
        val mediaSource = ExtractorMediaSource.Factory(dataSourceFactory)
                .createMediaSource(mediaUri)

        player!!.prepare(mediaSource)
        player!!.playWhenReady = true

        val filter = IntentFilter()
        filter.addAction("activity.to.service.transfer")
        receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent?) {
                var play = intent!!.getBooleanExtra("x", true)
                player!!.playWhenReady = play
            }
        }
        registerReceiver(receiver, filter)

        player?.addListener(eventListener)

        playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
                context,
                "BREAKFAST RADIO",
                R.string.exo_download_notification_channel_name,
                1000,
                object : PlayerNotificationManager.MediaDescriptionAdapter {
                    override fun getCurrentContentTitle(player: Player): String {
                        return "BR Live"
                    }

                    @Nullable
                    override fun createCurrentContentIntent(player: Player): PendingIntent? {
                        return null
                    }

                    @Nullable
                    override fun getCurrentContentText(player: Player): String? {
                        return "BR Live"
                    }

                    @Nullable
                    override fun getCurrentLargeIcon(player: Player, callback: PlayerNotificationManager.BitmapCallback): Bitmap? {
                        return BitmapFactory.decodeResource(context.resources, R.drawable.exo_controls_play)
                    }
                }
        )
        playerNotificationManager!!.setNotificationListener(object : PlayerNotificationManager.NotificationListener {
            override fun onNotificationStarted(notificationId: Int, notification: Notification) {
                startForeground(notificationId, notification)
            }

            override fun onNotificationCancelled(notificationId: Int) {
                stopSelf()
            }
        })
        playerNotificationManager!!.setPlayer(player)


        playerNotificationManager?.setFastForwardIncrementMs(0)
        playerNotificationManager?.setRewindIncrementMs(0)
        playerNotificationManager?.setUseNavigationActions(false)


        val playbackStateBuilder = PlaybackStateCompat.Builder()
        playbackStateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE)

        mediaSession = MediaSessionCompat(context, "BREAKFAST")
        mediaSession!!.isActive = true
        mediaSession?.setPlaybackState(playbackStateBuilder.build())
        playerNotificationManager!!.setMediaSessionToken(mediaSession!!.sessionToken)

    }

    override fun onDestroy() {
        mediaSession!!.release()
        playerNotificationManager!!.setPlayer(null)
        player!!.release()
        player = null

        super.onDestroy()
    }

    @Nullable
    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        return Service.START_STICKY
    }

    private var eventListener: Player.EventListener = object : Player.EventListener {
        override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
            var i = 0
        }

        override fun onSeekProcessed() {
            var i = 0
        }

        override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
            var i = 0
        }

        override fun onPlayerError(error: ExoPlaybackException?) {
            var i = 0
        }

        override fun onLoadingChanged(isLoading: Boolean) {
            var i = 0
        }

        override fun onPositionDiscontinuity(reason: Int) {
            var i = 0
        }

        override fun onRepeatModeChanged(repeatMode: Int) {
            var i = 0
        }

        override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
            var i = 0
        }

        override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
            var i = 0
        }

        override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
            sendPlaybackState(playWhenReady, playbackState)
        }
    }

    private fun sendPlaybackState(playWhenReadyValue: Boolean, playbackStateValue: Int) {
        var intent = Intent("service.to.activity.transfer")
        intent.putExtra(playWhenReady, playWhenReadyValue)
        intent.putExtra(playbackState, playbackStateValue)

        sendBroadcast(intent)
    }
}

and I'm not sure my broadcast receivers work either.


Solution

  • Register Service in Manifest.xml