Service does not work when the screen is off - android

I have a function which is responsible for detecting my location along with the location of some records that I have in the realm of my database. I calculate a range of approximately 30 meters. If my location is close to the range, it will be saved as a record in another Realm class.
All good until there, but when the phone's screen is turned off, it stops working.
I don't know how to make it work, I need to keep recording while the screen is off. I use a timer in the service. I was investigating what WorkManager is, but I don't think that's what I need.
Can you help me how to improve my code?
Thank you!
class DistanceService : Service() {
private val timer = Timer()
override fun onBind(intent: Intent): IBinder? {
Log.i("service", "Close DistanceService2")
return null
}
override fun onCreate() {
Log.i("service", "Iniciando DistanceService")
super.onCreate()
}
private fun startService() {
stopService(Intent(this, AlertRepartoSleepService::class.java))
timer.scheduleAtFixedRate(mainTask(), 0, 2000)
}
private inner class mainTask : TimerTask() {
override fun run() {
toastHandler.sendEmptyMessage(0)
}
}
private val toastHandler = #SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
val gps = Gps(this#DistanceService)
if (gps.isLocationEnabled()) {
if (gps.latitude.toString() != "0.0" || gps.longitude.toString() != "0.0") {
distance(this#DistanceService, gps.latitude.toString(), gps.longitude.toString())
val toast = Toast.makeText(applicationContext, "Rango SuministroReparto", Toast.LENGTH_SHORT)
toast.setGravity(Gravity.TOP, Gravity.CENTER, 0)
toast.show()
} else {
Util.toastMensaje(applicationContext, "Gps Sin Cobertura")
}
}
}
}
override fun onDestroy() {
timer.cancel()
Log.i("service", "Close DistanceService")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startService()
return START_STICKY
}
private fun distance(context: Context, latitud: String, longitud: String) {
Completable.fromAction {
Realm.getDefaultInstance().use { realm ->
val suministroImp: SuministroImplementation = SuministroOver(realm)
val registroImp: RegistroImplementation = RegistroOver(realm)
val result: RealmResults<SuministroReparto>? = suministroImp.getSuministroReparto(1)
if (result != null) {
if (result.size != 0) {
for (r: SuministroReparto in result) {
if (r.latitud.isNotEmpty() && r.longitud.isNotEmpty()) {
val l1 = Location("location 1")
l1.latitude = r.latitud.toDouble()
l1.longitude = r.longitud.toDouble()
val l2 = Location("location 2")
l2.latitude = latitud.toDouble()
l2.longitude = longitud.toDouble()
try {
val distancia = calculationByDistance(l1, l2)
if (distancia <= 15) {
if (r.foto_Reparto != 0) {
val repartoId = registroImp.getRegistroIdentity()
if (r.foto_Reparto != 2) {
suministroImp.repartoSaveService(registroImp.getRegistroIdentity(), r.id_Reparto, r.id_Operario_Reparto, Util.getFechaActual(), latitud, longitud, r.id_observacion.toString(), 0)
}
context.startService(Intent(context, AlertRepartoSleepService::class.java)
.putExtra("Cod_Orden_Reparto", r.Cod_Orden_Reparto)
.putExtra("id_cab_Reparto", r.id_Reparto)
.putExtra("direction", r.Direccion_Reparto)
.putExtra("suministroNumeroReparto", r.Suministro_Numero_reparto)
.putExtra("foto", r.foto_Reparto)
.putExtra("operarioId", r.id_Operario_Reparto)
.putExtra("cliente", r.Cliente_Reparto)
.putExtra("registroId", repartoId))
stopSelf()
break
} else {
suministroImp.repartoSaveService(registroImp.getRegistroIdentity(), r.id_Reparto, r.id_Operario_Reparto, Util.getFechaActual(), latitud, longitud, r.id_observacion.toString(), 1)
}
}
} catch (e: Exception) {
Util.toastMensaje(applicationContext, e.toString())
}
}
}
} else {
notification(this#DistanceService)
}
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CompletableObserver {
override fun onComplete() {
Log.i("TAG", "COMPLETADO")
}
override fun onSubscribe(d: Disposable) {
}
override fun onError(e: Throwable) {
Log.i("TAG", e.toString())
}
})
}
private fun calculationByDistance(StartP: Location, EndP: Location): Double {
val radius = 6371 * 1000
val lat1 = StartP.latitude
val lat2 = EndP.latitude
val lon1 = StartP.longitude
val lon2 = EndP.longitude
val dLat = Math.toRadians(lat2 - lat1)
val dLon = Math.toRadians(lon2 - lon1)
val a = sin(dLat / 2) * sin(dLat / 2) + (cos(Math.toRadians(lat1))
* cos(Math.toRadians(lat2)) * sin(dLon / 2)
* sin(dLon / 2))
val c = 2 * asin(sqrt(a))
val valueResult = radius * c
val m = valueResult / 1
val newFormat = DecimalFormat("####")
val mInDec = Integer.valueOf(newFormat.format(m))
return mInDec.toDouble()
}
private fun getBasicNotificationBuilder(context: Context, channelId: String, playSound: Boolean)
: NotificationCompat.Builder {
val notificationSound: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val nBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
.setAutoCancel(true)
.setDefaults(0)
if (playSound) nBuilder.setSound(notificationSound)
return nBuilder
}
private fun notification(context: Context) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val nBuilder = getBasicNotificationBuilder(context, CHANNEL_ID_TIMER, false)
nBuilder.setContentTitle(String.format("Reparto"))
.setContentText("Acabas de culminar tus repartos . Tomar selfie FIN DE TRABAJO")
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
val nManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.createNotificationChannel(CHANNEL_ID_TIMER, CHANNEL_NAME_TIMER, true)
nManager.notify(1, nBuilder.build())
}
#TargetApi(26)
private fun NotificationManager.createNotificationChannel(channelID: String,
channelName: String,
playSound: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelImportance = if (playSound) NotificationManager.IMPORTANCE_DEFAULT
else NotificationManager.IMPORTANCE_LOW
val nChannel = NotificationChannel(channelID, channelName, channelImportance)
nChannel.enableLights(true)
nChannel.lightColor = Color.BLUE
this.createNotificationChannel(nChannel)
}
}
companion object {
private const val CHANNEL_ID_TIMER = "enable_gps"
private const val CHANNEL_NAME_TIMER = "Dsige_Enable_Gps"
private const val TIMER_ID = 0
}
}

Related

LocationRequest.setInterval is not working properly when device is in sleep mode

This is my location Client class
class DefaultLocationClient(
private val context: Context, private val client: FusedLocationProviderClient
) : LocationClient {
#SuppressLint("MissingPermission")
override fun getLocationUpdates(interval: Long): Flow<Location> {
return callbackFlow {
if (!context.hasLocationPermission()) {
throw LocationClient.LocationException("Missing location permission")
}
val locationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
val isNetWorkEnabled =
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
if (!isGPSEnabled && !isNetWorkEnabled) {
throw LocationClient.LocationException("GPS is disabled")
}
// val request = LocationRequest.create().setInterval(interval).setFastestInterval(interval)
val request = LocationRequest.create().setPriority(Priority.PRIORITY_HIGH_ACCURACY).setInterval(interval).setFastestInterval(interval)
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
super.onLocationResult(result)
result.locations.lastOrNull()?.let { location ->
launch { send(location) }
}
}
}
client.requestLocationUpdates(request, locationCallback, Looper.getMainLooper())
awaitClose { client.removeLocationUpdates(locationCallback) }
}
}
}
This is LocationService class
class LocationService : Service() {
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val serviceScopeForRomm = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private lateinit var locationClient: LocationClient
private lateinit var bookDao: BookDao
lateinit var current: String
var strStatus: String = "Null";
lateinit var context: Context
override fun onBind(p0: Intent?): IBinder? {
Log.e("TAG", "Service Binding: ")
return null
}
#RequiresApi(Build.VERSION_CODES.O)
override fun onCreate() {
super.onCreate()
context = applicationContext
locationClient = DefaultLocationClient(
applicationContext, LocationServices.getFusedLocationProviderClient(applicationContext)
)
val db = Room.databaseBuilder(
applicationContext, AppDatabase::class.java, "book_database"
).build()
bookDao = db.bookDao()
}
#RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
ACTION_START -> start()
ACTION_STOP -> stop(true)
ACTION_RESTART -> stop(false)
}
return START_STICKY
}
#RequiresApi(Build.VERSION_CODES.O)
private fun start() {
startForegroundService()
}
#RequiresApi(Build.VERSION_CODES.O)
private fun startForegroundService() {
val notification =
NotificationCompat.Builder(this, "location").setContentText("Location:$strStatus")
.setContentTitle("Track-location-Test").setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
locationClient.getLocationUpdates(500L)
.catch { e -> Log.e("Tag11", "getLocationUpdates: ${e.message}") }.onEach { location ->
val formatter: DateTimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
current = LocalDateTime.now().format(formatter)
val lat = location.latitude.toString()
val lng = location.longitude.toString()
val updatedNotification = notification.setContentText("Location: ($lat,$lng)")
notificationManager.notify(1, updatedNotification.build())
Log.e("TAG", "$lat - $lng - $current")
insertData(lat, lng)
}.launchIn(serviceScope)
startForeground(1, notification.build())
}
var flagStopService: Boolean = false
private fun stop(isTrue: Boolean) {
flagStopService = isTrue
Log.e("tag111", "$isTrue stop: $flagStopService")
if (flagStopService) {
stopForeground(true)
stopSelf()
}
}
#RequiresApi(Build.VERSION_CODES.O)
fun insertData(lat: String, lng: String) {
//Insert
bookDao.insertBook(Book(0, lat, lng, current))
}
companion object {
const val ACTION_START = "ACTION_START"
const val ACTION_STOP = "ACTION_STOP"
const val ACTION_RESTART = "ACTION_RESTART"
}
#RequiresApi(Build.VERSION_CODES.O)
override fun onDestroy() {
serviceScope.cancel()
super.onDestroy()
}
}
Service and Client class are working fine as expected but once the device in on SleepMode or Ideal
val request = LocationRequest.create().setPriority(Priority.PRIORITY_HIGH_ACCURACY).setInterval(interval).setFastestInterval(interval)
is not working properly.
For e.g. if I set the interval=5000 Service return location after interval time is exceed (some time after 1 minutes)
I want to retrieve background location in every 5sec even when the device is in sleep mode.

How do i make Android recognize what song is playing?

I have a music player but i noticed that android and other devices don't recognize what song is playing.
For example in mi band 4 i can control the music if i have it on youtube music but not in my app or even in my launcher the at a glance widget recognizes it's playing.
Example:
Now that you know the context, what do i need to make it work or what am i missing?
Here's my service that plays the music:
class SimpleMPService: Service() {
private val mBinder = LocalBinder()
private lateinit var notification: Notification
private lateinit var notificationManager: NotificationManager
var playList = ArrayList<Song>()
private var shuffledPlaylist = ArrayList<Song>()
var currentSongPosition: Int = 0
private var currentSongPath: String = ""
var onRepeatMode = false
private lateinit var audioManager: AudioManager
//Listeners
var onMusicSelectedListener: OnMusicSelectedListener? = null
var onMusicSelectedListenerToQueue: OnMusicSelectedListenerToQueue? = null //Since there is no way to have two listeners at same time it needs another listener to the queue list
var onMusicPausedListener: OnMusicPausedListener? = null
var onPlaylistAdded: OnPlaylistsAdded? = null
var onMusicResumedListener: OnMusicResumedListener? = null
var onMusicSecondPassedListener: OnSecondPassedListener? = null
var onMusicShuffleToggledListener: OnMusicShuffleToggledListener? = null
var onMediaPlayerStoppedListener: OnMediaPlayerStoppedListener? = null
//Player States
private var serviceStarted = false
var musicShuffled = false
private var musicStarted = false
//Others
private lateinit var mediaButtonReceiver: ComponentName
private lateinit var mediaSession: MediaSessionCompat
inner class LocalBinder : Binder() {
fun getService(): SimpleMPService = this#SimpleMPService
}
companion object {
private val mediaPlayer = MediaPlayer()
fun startService(context: Context) {
val startIntent = Intent(context, SimpleMPService::class.java)
context.startForegroundService(startIntent)
}
}
override fun onBind(intent: Intent?): IBinder {
val context = this
mediaButtonReceiver = ComponentName(context, ReceiverPlayPause::class.java)
mediaSession = MediaSessionCompat(context, "SessionTag")
mediaSession.setCallback(object : MediaSessionCompat.Callback(){
override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean {
val ke = mediaButtonIntent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
if( ke?.action == KeyEvent.ACTION_DOWN ){
if( ke.keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS )
previousSong( context )
if( ke.keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE )
pauseResumeMusic( context )
if( ke.keyCode == KeyEvent.KEYCODE_MEDIA_PLAY )
pauseResumeMusic( context )
if( ke.keyCode == KeyEvent.KEYCODE_MEDIA_NEXT )
skipSong( context )
}
return super.onMediaButtonEvent(mediaButtonIntent)
}
})
return mBinder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
override fun onCreate() {
super.onCreate()
notificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
fun getCurrentPlaylist(): ArrayList<Song>{
return if(!musicShuffled) playList else shuffledPlaylist
}
fun isMusicPlayingOrPaused(): Boolean{ return musicStarted }
fun toggleShuffle(){
if( !musicShuffled ){
musicShuffled = true
shuffledPlaylist = ArrayList()
val tempShuffledPlaylist = ArrayList<Song>()
//Adds the current song to first position
playList.forEach { song ->
if (song.path != currentSongPath)
tempShuffledPlaylist.add(song)
else
shuffledPlaylist.add( song )
}
//Shuffles the temp playlist and adds it to the one with just the current song
tempShuffledPlaylist.shuffle()
for( song in tempShuffledPlaylist )
shuffledPlaylist.add( song )
currentSongPosition = 0
}
else{
musicShuffled = false
for( i in playList.indices ){
if( playList[i].path == currentSongPath ){
currentSongPosition = i
break
}
}
}
onMusicShuffleToggledListener?.onMusicShuffleToggled(musicShuffled)
}
fun enableShuffle(){
musicShuffled = true
shuffledPlaylist = ArrayList(playList)
shuffledPlaylist.shuffle()
onMusicShuffleToggledListener?.onMusicShuffleToggled(true)
currentSongPosition = 0
}
fun setPlaylist( newPlaylist: ArrayList<Song> ){ playList = newPlaylist }
fun playSongAndEnableShuffle(context: Context, position: Int){
val selectedSong = playList[position]
shuffledPlaylist = ArrayList(playList)
shuffledPlaylist.shuffle()
shuffledPlaylist.removeIf{ it.path == selectedSong.path }
shuffledPlaylist.add(0, selectedSong )
currentSongPosition = 0
playSong(context)
musicShuffled = true
}
fun isMusicPlaying(): Boolean{
return mediaPlayer.isPlaying
}
fun getCurrentSongPath(): String{ return currentSongPath }
private val audioFocusChangeListener = OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {}
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT->{}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
if( mediaPlayer.isPlaying )
pauseMusic(this )
}
AudioManager.AUDIOFOCUS_LOSS -> {
if( mediaPlayer.isPlaying )
pauseMusic(this )
}
}
}
private val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
setAudioAttributes(AudioAttributes.Builder().run {
setUsage(AudioAttributes.USAGE_MEDIA)
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
build()
})
setAcceptsDelayedFocusGain(true)
setOnAudioFocusChangeListener(audioFocusChangeListener)
build()
}
fun playSong(context: Context){
serviceStarted = true
musicStarted = true
val songPath: String
val songTitle: String
val songArtist: String
val songID: Long
val songAlbumID: Long
val songAlbumArt: Bitmap
val songDuration: Int
if( !musicShuffled ) {
songPath = playList[currentSongPosition].path
songTitle = playList[currentSongPosition].title
songArtist = playList[currentSongPosition].artistName
songID = playList[currentSongPosition].id
songAlbumID = playList[currentSongPosition].albumID
songAlbumArt = GetSongs.getSongAlbumArt(context, songID, songAlbumID)
songDuration = playList[currentSongPosition].duration
}
else{
songPath = shuffledPlaylist[currentSongPosition].path
songTitle = shuffledPlaylist[currentSongPosition].title
songArtist = shuffledPlaylist[currentSongPosition].artistName
songID = shuffledPlaylist[currentSongPosition].id
songAlbumID = shuffledPlaylist[currentSongPosition].albumID
songAlbumArt = GetSongs.getSongAlbumArt(context, songID, songAlbumID)
songDuration = shuffledPlaylist[currentSongPosition].duration
}
currentSongPath = songPath
val isAudioLimited = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("setting_limitAudioVolume", true)
mediaPlayer.reset()
mediaPlayer.setDataSource(songPath)
when(isAudioLimited){
true-> mediaPlayer.setVolume(0.08F, 0.08F)
false-> mediaPlayer.setVolume(0.1F, 0.1F)
}
mediaPlayer.prepareAsync()
mediaPlayer.setOnPreparedListener {
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
requestPlayWithFocus()
mediaSession.isActive = true
//Open App
val openAppIntent = Intent( context, ActivityMain::class.java )
val pendingOpenAppIntent = TaskStackBuilder.create( context ).run{
addNextIntentWithParentStack(openAppIntent)
getPendingIntent( 0, PendingIntent.FLAG_IMMUTABLE )
}
//Stop Service
val stopIntent = Intent(context, ReceiverStop::class.java )
val pendingStopIntent = PendingIntent.getBroadcast( context, 1, stopIntent, PendingIntent.FLAG_IMMUTABLE )
//Previous Music
val previousSongIntent = Intent(context, ReceiverPreviousSong::class.java )
val pendingPreviousSongIntent = PendingIntent.getBroadcast( context, 1, previousSongIntent, PendingIntent.FLAG_IMMUTABLE )
//Pauses/Plays music
val playPauseIntent = Intent(context, ReceiverPlayPause::class.java )
val pendingPlayPauseIntent = PendingIntent.getBroadcast( context, 1, playPauseIntent, PendingIntent.FLAG_IMMUTABLE )
//Skips to next music
val skipSongIntent = Intent(context, ReceiverSkipSong::class.java )
val pendingSkipSongIntent = PendingIntent.getBroadcast( context, 1, skipSongIntent, PendingIntent.FLAG_IMMUTABLE )
notification = NotificationCompat.Builder(context, "Playback")
.setContentIntent( pendingOpenAppIntent )
.setStyle( androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
.setShowActionsInCompactView(1, 2, 3)
)
.setSmallIcon(R.drawable.icon)
.addAction(R.drawable.icon_x, "Stop Player", pendingStopIntent )
.addAction(R.drawable.icon_previous_notification, "Previous Music", pendingPreviousSongIntent )
.addAction(R.drawable.icon_pause_notification, "Play Pause Music", pendingPlayPauseIntent )
.addAction(R.drawable.icon_next_notification, "Next Music", pendingSkipSongIntent )
.build()
mediaSession.setMetadata(
MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_TITLE, songTitle)
.putString(MediaMetadata.METADATA_KEY_ARTIST, songArtist)
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, songAlbumArt)
.putLong(MediaMetadata.METADATA_KEY_DURATION, songDuration.toLong())
.build()
)
startForeground( 2, notification )
notificationManager.notify( 2, notification )
}
handleSongFinished( context )
if( !musicShuffled ) {
onMusicSelectedListener?.onMusicSelected(playList, currentSongPosition)
onMusicSelectedListenerToQueue?.onMusicSelected(playList, currentSongPosition)
}
else {
onMusicSelectedListener?.onMusicSelected(shuffledPlaylist, currentSongPosition)
onMusicSelectedListenerToQueue?.onMusicSelected(shuffledPlaylist, currentSongPosition)
}
val bluetoothReceiver = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
context.registerReceiver(bluetoothBroadcastReceiver, bluetoothReceiver )
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.post( object : Runnable{
override fun run() {
if( onMusicSecondPassedListener != null )
onMusicSecondPassedListener?.onSecondPassed( mediaPlayer.currentPosition )
mainHandler.postDelayed( this,1000)
}
})
}
private val bluetoothBroadcastReceiver = object : BroadcastReceiver(){
override fun onReceive(p0: Context?, p1: Intent?) {
if(isMusicPlaying()) pauseMusic(p0!!)
}
}
fun seekTo( position: Int){
val newSongPosition = position * 1000
mediaPlayer.seekTo(newSongPosition)
if( !mediaPlayer.isPlaying ) mediaPlayer.start()
}
private fun handleSongFinished(context: Context) {
mediaPlayer.setOnCompletionListener{
//If loop mode is activated
if( onRepeatMode ){
playSong( context )
}
//Is it's the last song
else if( (currentSongPosition + 1) == playList.size ){
stopMediaPlayer()
}
else{
currentSongPosition++
playSong( context )
}
}
}
fun toggleLoop(){
onRepeatMode = !onRepeatMode
}
fun stopMediaPlayer(){
onMediaPlayerStoppedListener?.onMediaPlayerStopped()
mediaPlayer.stop()
currentSongPosition = -1
currentSongPath = ""
stopForeground(true)
stopSelf()
}
fun skipSong(context: Context){
if( (currentSongPosition + 1) < playList.size ){
currentSongPosition ++
playSong( context )
}
}
fun previousSong(context: Context){
if( (currentSongPosition - 1) >= 0 ){
currentSongPosition--
playSong( context )
}
}
#Suppress("DEPRECATION")
fun pauseMusic(context: Context ){
val playPauseIcon = R.drawable.icon_play_notification
mediaPlayer.pause()
mediaSession.isActive = false
if( onMusicPausedListener != null)
onMusicPausedListener?.onMusicPaused()
//Updates the notification
val playPauseIntent = Intent(context, ReceiverPlayPause::class.java )
playPauseIntent.putExtra( "action", "playPause" )
val pendingPlayPauseIntent = PendingIntent.getBroadcast( context, 1, playPauseIntent, PendingIntent.FLAG_IMMUTABLE )
notification.actions[2] = Notification.Action( playPauseIcon, "Play Music", pendingPlayPauseIntent )
startForeground( 2, notification )
notificationManager.notify( 2, notification )
}
#Suppress("DEPRECATION")
fun pauseResumeMusic(context: Context ){
val playPauseIcon: Int
if( mediaPlayer.isPlaying ) {
playPauseIcon = R.drawable.icon_play_notification
mediaPlayer.pause()
if( onMusicPausedListener != null) onMusicPausedListener?.onMusicPaused()
}
else {
playPauseIcon = R.drawable.icon_pause_notification
if( onMusicResumedListener != null ) onMusicResumedListener?.onMusicResumed()
requestPlayWithFocus()
}
//Updates the notification
val playPauseIntent = Intent(context, ReceiverPlayPause::class.java )
playPauseIntent.putExtra( "action", "playPause" )
val pendingPlayPauseIntent = PendingIntent.getBroadcast( context, 1, playPauseIntent, PendingIntent.FLAG_IMMUTABLE )
notification.actions[2] = Notification.Action( playPauseIcon, "Play Music", pendingPlayPauseIntent )
startForeground( 2, notification )
notificationManager.notify( 2, notification )
}
private fun requestPlayWithFocus(){
val focusLock = Any()
val res = audioManager.requestAudioFocus(focusRequest)
synchronized(focusLock) {
when (res) {
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
mediaPlayer.start()
onMusicResumedListener?.onMusicResumed()
true
}
else -> false
}
}
}
fun updatePlaylists(){ onPlaylistAdded?.onPlaylistAdded() }
//////////////////////////////////////////////////////////////////////////////////////////////////////
interface OnMusicSelectedListener{ fun onMusicSelected(playList: ArrayList<Song>, position: Int ) }
interface OnMusicSelectedListenerToQueue{ fun onMusicSelected(playList: ArrayList<Song>, position: Int ) }
interface OnPlaylistsAdded{ fun onPlaylistAdded() }
interface OnMusicPausedListener{ fun onMusicPaused() }
interface OnMusicResumedListener{ fun onMusicResumed() }
interface OnSecondPassedListener{ fun onSecondPassed(position: Int ) }
interface OnMusicShuffleToggledListener{ fun onMusicShuffleToggled(state: Boolean) }
interface OnMediaPlayerStoppedListener{ fun onMediaPlayerStopped() }
}
I wanted to make other devices recognize what song is playing and map the respective buttons like previous pause play next. I tried to search but didn't find anything useful. I don't know what to search specifically.
Thanks in advance :D
I finally found the problem. I wass missing Playback State And Callbacks.
I am sharing what i did in case anyone ends up here and in the same situation.
First i added other callbacks to media session callback. Mainly this ones:
override fun onPlay() {
super.onPlay()
pauseResumeMusic(context)
}
override fun onStop() {
super.onStop()
stopMediaPlayer()
}
override fun onPause() {
super.onPause()
pauseResumeMusic(context)
}
override fun onSkipToNext() {
super.onSkipToNext()
selectNextSong(context)
}
override fun onSkipToPrevious() {
super.onSkipToPrevious()
selectPreviousSong(context)
}
After that i needed to set the state when those actions happened. For that i made a function to set it.
fun setPlaybackState(state: Int){
val stateBuilder = PlaybackStateCompat.Builder()
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE
or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
or PlaybackStateCompat.ACTION_SKIP_TO_NEXT)
.apply {
setState(state, mediaPlayer.currentPosition.toLong(), 1.0f)
}
mediaSession.setPlaybackState(stateBuilder.build())
}
Now everytime i need to update i just call the function and send the state as a parameter.
Example:
setPlaybackState(PlaybackStateCompat.STATE_PLAYING)
Hope this helps someone in case it was stuck like me for months XD

how do i get the set notification in BLE nordic

i am trying to set notification callback in BLE nordic, where i am using the Android BLE library (Nordic Github). But i not ablet to get the notification event when i am changing the value of the characteristics.
`
class BleManagerHP1T(context: Context) : BleManager(context) {
override fun getGattCallback(): BleManagerGattCallback = GattCallback()
override fun log(priority: Int, message: String) {
if (BuildConfig.DEBUG || priority == Log.ERROR) {
Log.println(priority, GattService.TAG, message)
}
}
private inner class GattCallback : BleManagerGattCallback() {
private var myCharacteristic: BluetoothGattCharacteristic? = null
private var rxCharacteristic: BluetoothGattCharacteristic? = null
#SuppressLint("MissingPermission")
override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
val service = gatt.getService(GattService.MyServiceProfile.MY_SERVICE_UUID)
myCharacteristic =
service?.getCharacteristic(GattService.MyServiceProfile.MY_CHARACTERISTIC_UUID)
val myCharacteristicProperties = myCharacteristic?.properties ?: 0
Log.d(TAG, "isRequiredServiceSupported: notify ${(myCharacteristicProperties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0)}")
rxCharacteristic = service?.getCharacteristic(GattService.MyServiceProfile.RX_CHARACTERISTIC_UUID)
val obj = JSONObject()
obj.put("OPCODE","PROVISION")
rxCharacteristic?.value = obj.toString().encodeToByteArray()
val rxRead = gatt.writeCharacteristic(rxCharacteristic)
Log.d(TAG, "isRequiredServiceSupported: Read $rxRead")
return (myCharacteristicProperties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0)
}
override fun initialize() {
enableNotifications(myCharacteristic).enqueue()
requestMtu(260).enqueue();
setNotificationCallback(myCharacteristic).with { _, data ->
Log.d(TAG, "initialize: TX char Notification Called")
if (data.value != null) {
val value = String(data.value!!, Charsets.UTF_8)
Log.d(TAG, "initialize: TX char value $value")
}
}
requestMtu(260).enqueue();
enableNotifications(rxCharacteristic).enqueue()
setNotificationCallback(rxCharacteristic).with { _, data ->
Log.d(TAG, "initialize: RX char Notification Called")
if (data.value != null) {
val value = String(data.value!!, Charsets.UTF_8)
Log.d(TAG, "initialize: RX char value $value")
}
}
beginAtomicRequestQueue()
.add(enableNotifications(myCharacteristic)
.fail { _: BluetoothDevice?, status: Int ->
log(Log.ERROR, "Could not subscribe: $status")
disconnect().enqueue()
}
)
.done {
log(Log.INFO, "Target initialized")
}
.enqueue()
}
override fun onServicesInvalidated() {
myCharacteristic = null
}
}
override fun readCharacteristic(characteristic: BluetoothGattCharacteristic?): ReadRequest {
return Request.newReadRequest(characteristic)
}
}
`
gatt connection is establishing perfectly fine, using this code.
`
val bleManager = BleManagerHP1T(this#ControllerActivity)
synchronized (this) {
bleManager.connect(deviceMainList[position]).useAutoConnect(false).enqueue()
}
`
here is the gatt service file .
`
class GattService : Service() {
private val defaultScope = CoroutineScope(Dispatchers.Default)
private lateinit var bluetoothObserver: BroadcastReceiver
private var myCharacteristicChangedChannel: SendChannel<String>? = null
private val clientManagers = mutableMapOf<String, ClientManager>()
// val connect = BleManager()
#RequiresApi(Build.VERSION_CODES.O)
override fun onCreate() {
super.onCreate()
// Setup as a foreground service
val notificationChannel = NotificationChannel(
GattService::class.java.simpleName,
resources.getString(R.string.gatt_service_name),
NotificationManager.IMPORTANCE_DEFAULT
)
val notificationService =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationService.createNotificationChannel(notificationChannel)
val notification = NotificationCompat.Builder(this, GattService::class.java.simpleName)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(resources.getString(R.string.gatt_service_name))
.setContentText(resources.getString(R.string.gatt_service_running_notification))
.setAutoCancel(true)
startForeground(1, notification.build())
// Observe OS state changes in BLE
bluetoothObserver = object : BroadcastReceiver() {
#SuppressLint("MissingPermission")
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
BluetoothAdapter.ACTION_STATE_CHANGED -> {
val bluetoothState = intent.getIntExtra(
BluetoothAdapter.EXTRA_STATE,
-1
)
when (bluetoothState) {
BluetoothAdapter.STATE_ON -> enableBleServices()
BluetoothAdapter.STATE_OFF -> disableBleServices()
}
}
BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
val device =
intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
Log.d(TAG, "Bond state changed for device ${device?.address}: ${device?.bondState}")
when (device?.bondState) {
BluetoothDevice.BOND_BONDED -> addDevice(device)
BluetoothDevice.BOND_NONE -> removeDevice(device)
}
}
}
}
}
registerReceiver(bluetoothObserver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
registerReceiver(bluetoothObserver, IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED))
// Startup BLE if we have it
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
if (bluetoothManager.adapter?.isEnabled == true) enableBleServices()
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(bluetoothObserver)
disableBleServices()
}
override fun onBind(intent: Intent?): IBinder? =
when (intent?.action) {
DATA_PLANE_ACTION -> {
DataPlane()
}
else -> null
}
override fun onUnbind(intent: Intent?): Boolean =
when (intent?.action) {
DATA_PLANE_ACTION -> {
myCharacteristicChangedChannel = null
true
}
else -> false
}
/**
* A binding to be used to interact with data of the service
*/
inner class DataPlane : Binder() {
fun setMyCharacteristicChangedChannel(sendChannel: SendChannel<String>) {
myCharacteristicChangedChannel = sendChannel
}
}
#SuppressLint("MissingPermission")
private fun enableBleServices() {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
if (bluetoothManager.adapter?.isEnabled == true) {
Log.i(TAG, "Enabling BLE services")
bluetoothManager.adapter.bondedDevices.forEach { device -> addDevice(device) }
} else {
Log.w(TAG, "Cannot enable BLE services as either there is no Bluetooth adapter or it is disabled")
}
}
private fun disableBleServices() {
clientManagers.values.forEach { clientManager ->
clientManager.close()
}
clientManagers.clear()
}
private fun addDevice(device: BluetoothDevice) {
if (!clientManagers.containsKey(device.address)) {
val clientManager = ClientManager()
clientManager.connect(device).useAutoConnect(true).enqueue()
clientManagers[device.address] = clientManager
}
}
private fun removeDevice(device: BluetoothDevice) {
clientManagers.remove(device.address)?.close()
}
/*
* Manages the entire GATT service, declaring the services and characteristics on offer
*/
companion object {
/**
* A binding action to return a binding that can be used in relation to the service's data
*/
const val DATA_PLANE_ACTION = "data-plane"
const val TAG = "gatt-service"
}
private inner class ClientManager : BleManager(this#GattService) {
override fun getGattCallback(): BleManagerGattCallback = GattCallback()
override fun log(priority: Int, message: String) {
if (BuildConfig.DEBUG || priority == Log.ERROR) {
Log.println(priority, TAG, message)
Log.d(TAG, "log: $message")
}
}
private inner class GattCallback : BleManagerGattCallback() {
private var myCharacteristic: BluetoothGattCharacteristic? = null
override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
val service = gatt.getService(MyServiceProfile.MY_SERVICE_UUID)
myCharacteristic =
service?.getCharacteristic(MyServiceProfile.MY_CHARACTERISTIC_UUID)
val myCharacteristicProperties = myCharacteristic?.properties ?: 0
return (myCharacteristicProperties and BluetoothGattCharacteristic.PROPERTY_READ != 0) &&
(myCharacteristicProperties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0)
}
override fun initialize() {
setNotificationCallback(myCharacteristic).with { _, data ->
if (data.value != null) {
val value = String(data.value!!, Charsets.UTF_8)
defaultScope.launch {
myCharacteristicChangedChannel?.send(value)
}
}
}
beginAtomicRequestQueue()
.add(enableNotifications(myCharacteristic)
.fail { _: BluetoothDevice?, status: Int ->
log(Log.ERROR, "Could not subscribe: $status")
disconnect().enqueue()
}
)
.done {
log(Log.INFO, "Target initialized")
}
.enqueue()
}
override fun onServicesInvalidated() {
myCharacteristic = null
}
}
}
object MyServiceProfile {
val MY_SERVICE_UUID: UUID = UUID.fromString("8d67d51a-801b-43cb-aea2-bbec9d1211fd")
val MY_CHARACTERISTIC_UUID: UUID = UUID.fromString("8d67d51c-801b-43cb-aea2-bbec9d1211fd")
val RX_CHARACTERISTIC_UUID: UUID = UUID.fromString("8d67d51b-801b-43cb-aea2-bbec9d1211fd")
}
}
`

Android Notification is not canceling after workManager completes

I am using Android WorkManager with setForegroundAsync, But the notification is not canceling after workManager completes.
OfflinePushWorkManager is a work manager class to push offline stuff to the server.
class OfflinePushWorkManager(var context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams),
KoinComponent {
private val reflectionUtil: ReflectionUtil by inject()
private val apiService: ApiService by inject()
private val flowchartDao: FlowChartDao by inject()
val flowchartUploadObserver = MutableLiveData<ApiResponse<BaseResponse<SaveFlowchartResponse>>>()
val deleteFlowchart = MutableLiveData<ApiResponse<Unit>>()
override suspend fun doWork(): Result {
setForegroundAsync(createForegroundInfo())
val data = inputData.getString(Constants.BundleKeys.FLOWCHART)
// val docString : String? = DocumentReaderUtil.readTxtFromUri(Uri.parse(data.toString()), applicationContext)
Log.d("uri is ", data.toString())
val dataString: String? = AppUtils.readStringFromFileInternalStorage(applicationContext, data)
Log.d("dataString is ", dataString+"")
dataString?.let {
val flowchart = reflectionUtil.gsonToClass(it, FlowChart::class.java)
uploadFlowchart(flowchart)
AppLogs.e("classObject", "" + flowchart)
}
return Result.success()
}
companion object{
var notificationManager:NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
var uploadedProgress : Int = 1
var notification: NotificationCompat.Builder? = null
fun updateProgress(progress : Int?){
if(progress == 100){
uploadedProgress = 100
cancelNotification()
AppLogs.e("uploadedProgress", " " + uploadedProgress)
}
else {
uploadedProgress = uploadedProgress + 30
if(uploadedProgress < 100 && uploadedProgress < 70)
notification?.setProgress(100,uploadedProgress,false)
AppLogs.e("uploadedProgress", " " + uploadedProgress)
if(notification != null) {
Log.d("Notification CancelAll---->", "5 Notifying")
notificationManager.notify(1, notification?.build())
}
}
}
fun cancelNotification(){
Log.d("Notification CancelAll---->", "3")
notificationManager.cancelAll()
}
fun displayNotification(title: String) : Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
Constants.SCULPTOR,
Constants.SCULPTOR,
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager?.createNotificationChannel(channel)
}
notification = NotificationCompat.Builder(
context,
Constants.SCULPTOR
)
.setContentTitle(title)
.setSmallIcon(R.mipmap.ic_launcher)
.setOnlyAlertOnce(true)
notification?.setProgress(100,uploadedProgress,false)
Log.d("Notification CancelAll---->", "4 Notifying")
notificationManager?.notify(1, notification?.build())
return notification!!.build()
}
}
/**
* Create ForegroundInfo required to run a Worker in a foreground service.
*/
private fun createForegroundInfo(): ForegroundInfo {
val notificationId = 1
return ForegroundInfo(notificationId, displayNotification("Uploading in progress...."))
}
}
Calling Sequense
private fun setWorkManager(list: Array<FlowChart>) {
Log.d("---->", "${list.size} {list.size}")
val gsonList:ArrayList<String> = ArrayList()
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
workManager = WorkManager.getInstance(applicationContext)
OfflinePushWorkManager.uploadedProgress = 0
for( i in 0 until list.size) {
val listData = reflectionUtil.gsonFromClass(list.get(i))
gsonList.add(listData)
if(mPref.get(PreferenceConstants.TOKEN,"").isNullOrEmpty()){
workManager?.cancelAllWork()
OfflinePushWorkManager.cancelNotification()
break
}
val dataString: String = AppUtils.writeStringToFileInternalStorage(applicationContext, listData, i.toString())
val data: Data = Data.Builder().putString(Constants.BundleKeys.FLOWCHART,dataString).build()
val workManagerRequest = OneTimeWorkRequest.Builder(OfflinePushWorkManager::class.java).setInputData(data)
.setConstraints(constraints).build()
workManager?.enqueue(workManagerRequest)
mPref.put(PreferenceConstants.WORK_ID,workManagerRequest.id.toString())
handleWorkManagerState(workManagerRequest,i,list)
}
}
private fun cancelNotification(){
workManager?.pruneWork()
GlobalScope.launch {
val nMgr = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
nMgr.activeNotifications.forEach {
nMgr.cancel(it.id)
Log.d("Notification Cancel---->", "1 ${it.id}")
}
Log.d("Notification CancelAll---->", "2")
nMgr.cancelAll()
}
}
private fun handleWorkManagerState(workManagerRequest: OneTimeWorkRequest, i: Int, list: Array<FlowChart>) {
workManager?.getWorkInfoByIdLiveData(workManagerRequest.id)
?.observe(this, object : androidx.lifecycle.Observer<WorkInfo> {
override fun onChanged(t: WorkInfo?) {
if(t?.state == WorkInfo.State.RUNNING ){
mPref.put(PreferenceConstants.IS_WORK_RUNNING,true)
OfflinePushWorkManager.updateProgress(0)
} else if(t?.state == WorkInfo.State.SUCCEEDED){
if(i+1 == list.size){
mPref.put(PreferenceConstants.IS_WORK_RUNNING,false)
OfflinePushWorkManager.updateProgress(100)
workManager?.cancelAllWork()
OfflinePushWorkManager.cancelNotification()
cancelNotification()
} else{
OfflinePushWorkManager.updateProgress(0)
}
} else if(t?.state == WorkInfo.State.FAILED){
if(i+1 == list.size) {
mPref.put(PreferenceConstants.IS_WORK_RUNNING,false)
workManager?.cancelAllWork()
OfflinePushWorkManager.cancelNotification()
cancelNotification()
}
} else if(t?.state == WorkInfo.State.CANCELLED){
mPref.put(PreferenceConstants.IS_WORK_RUNNING,false)
workManager?.cancelAllWork()
OfflinePushWorkManager.cancelNotification()
cancelNotification()
mPref.put(PreferenceConstants.WORK_ID,"")
}
}
})
}

setProgressAsync in ListenableWorker not sending update to LiveData

I have to implement a library that creates it's own thread to do the execution. Now, have to start the library-execution in background and hence using ListenableWorker.
But, setProgressAsync is not updating the LiveData.
Here is the code,
class ForegroundWorker(appContext: Context, params: WorkerParameters) :
ListenableWorker(appContext, params) {
private val notificationManager = appContext.getSystemService(NotificationManager::class.java)
override fun startWork(): ListenableFuture<Result> {
Log.d(TAG, "Start job")
return CallbackToFutureAdapter.getFuture { completer: CallbackToFutureAdapter.Completer<Result> ->
val callback: AsyncCallback = object : AsyncCallback {
var successes: Int = 0
override fun onError(failure: String?) {
completer.setException(Throwable())
}
override fun onSuccess(foo: String?) {
++successes
setProgressAsync(workDataOf(Progress to successes))
//completer.set(Result.success(workDataOf(Progress to successes)))
if (successes == 100) {
completer.set(Result.success(workDataOf(Progress to successes)))
}
}
}
//completer.addCancellationListener(cancelDownloadsRunnable, executor)
//for (i in 0..99) {
downloadAsynchronously("https://www.google.com", callback)
//}
callback
}
/*createNotificationChannel()
val notification = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Important background job")
.build()
val foregroundInfo = ForegroundInfo(NOTIFICATION_ID, notification)
setForegroundAsync(foregroundInfo)
for (i in 0..100) {
setProgressAsync(workDataOf(Progress to i))
showProgress(i)
GlobalScope.launch {
delay(delayDuration)
}
}
Log.d(TAG, "Finish job")
return Result.success()*/
}
private fun downloadAsynchronously(s: String, callback: AsyncCallback) {
createNotificationChannel()
val notification = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Important background job")
.build()
val foregroundInfo = ForegroundInfo(NOTIFICATION_ID, notification)
setForegroundAsync(foregroundInfo)
for (i in 0..1000) {
setProgressAsync(workDataOf(Progress to i))
showProgress(i)
GlobalScope.launch {
delay(delayDuration)
}
callback.onSuccess("")
}
}
private fun showProgress(progress: Int) {
val notification = NotificationCompat.Builder(applicationContext,
channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Important background job")
.setProgress(100, progress, false)
.build()
notificationManager?.notify(NOTIFICATION_ID, notification)
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
var notificationChannel =
notificationManager?.getNotificationChannel(channelId)
if (notificationChannel == null) {
notificationChannel = NotificationChannel(
channelId, TAG, NotificationManager.IMPORTANCE_LOW
)
notificationManager?.createNotificationChannel(notificationChannel)
}
}
}
companion object {
const val NOTIFICATION_ID = 42
const val TAG = "ForegroundWorker"
const val channelId = "Job progress"
const val Progress = "Progress"
private const val delayDuration = 100L
}
interface AsyncCallback {
fun onSuccess(foo: String?)
fun onError(failure: String?)
}
}
and the livedata,
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
val workManager = WorkManager.getInstance(this)
var workRequest: OneTimeWorkRequest = OneTimeWorkRequest.from(ForegroundWorker::class.java)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
/*val workManager = WorkManager.getInstance(this)
val workRequest = OneTimeWorkRequest.from(ForegroundWorker::class.java)*/
// if (SharedPreferenceHelper.workRequestId != "") {
workManager.getWorkInfoByIdLiveData(workRequest.id)
.observe(this, Observer { workInfo: WorkInfo? ->
if (workInfo != null) {
val progress = workInfo.progress
val value = progress.getInt(Progress, 0)
binding.progressBar.progress = value
}
})
//}
workManager.enqueue(workRequest)
}
}
For some reason, setProgressAsync is not updating the Livedata.

Categories

Resources