1

I created a worker that runs on connecting audio jack but I can't stop the running worker on audio jack disconnection which is triggered by Broadcast Receiver. I want to keep track of headset usage limit with the help of worker which will only trigger when there is headset connection and will stop the worker whenever the audio jack/headset is detached.

Here is the Broadcast Reciver Code

package com.xanjit.focusly.broadcast_receivers

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.work.*
import com.xanjit.focusly.workers.GetHeadsetUsageTimeWorker
import java.sql.Timestamp
import java.time.Duration

class AudioInputBroadcastReceiver : BroadcastReceiver() {
//    lateinit var workManager: WorkManager
//    lateinit var workRequest: WorkRequest

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onReceive(context: Context?, intent: Intent?) {

        val isConnected = intent!!.getIntExtra("state", 0) === 1
        val workManager = WorkManager.getInstance(context!!)

        if (isConnected) {
            var startTime = System.currentTimeMillis()
            Toast.makeText(context,"Connected",Toast.LENGTH_SHORT).show()
            val data = Data.Builder()

            data.putLong("startTime", startTime)
            val workRequest = OneTimeWorkRequest.Builder(
                GetHeadsetUsageTimeWorker::class.java,
            ).setInputData(data.build())




                .build()
            workManager.enqueue(workRequest)
        } else {
            Toast.makeText(context,"Disconnected",Toast.LENGTH_SHORT).show()

//            val data = Data.Builder()
//
//            data.putBoolean("isStopped", true)
//            val workRequest = OneTimeWorkRequest.Builder(
//                GetHeadsetUsageTimeWorker::class.java,
//            ).setInputData(data.build()).build()
            workManager.cancelAllWork()



        }

    }

    override fun peekService(myContext: Context?, service: Intent?): IBinder {
        return super.peekService(myContext, service)
    }

}

Worker Code

package com.xanjit.focusly.workers

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.graphics.BitmapFactory
import android.media.AudioAttributes
import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.work.ListenableWorker
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.xanjit.focusly.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

import java.sql.Timestamp
import kotlin.time.seconds

var TAG = "EarGuard"

class GetHeadsetUsageTimeWorker(context: Context, workerParams: WorkerParameters) : Worker(
    context,
    workerParams,
) {

    @RequiresApi(Build.VERSION_CODES.O)
    override fun doWork(): Result {
//                    Log.d("EarGuard", "StartTime Worker")

        var startTime = inputData.getLong("startTime", System.currentTimeMillis())
//        var stopped = inputData.getBoolean("isStopped", false)

//        if (!isStopped and !stopped) {
//            Log.d("EarGuard", "StartTime Worker" + startTime)
        Log.d(TAG, isStopped.toString())
        Thread {
            while (!isStopped) {
                Thread.sleep(1000)
                var usageTime = System.currentTimeMillis()
                usageTime -= startTime
                Log.d(TAG, usageTime.toString())
                if ((usageTime / 1000) == 5L) {


                    CoroutineScope(Dispatchers.Main).launch(Dispatchers.Main)
                    {
//                            Toast.makeText(
//                                applicationContext,
//                                "Time limit exceeded", Toast.LENGTH_LONG
//                            ).show()
                        val notificationChannel = NotificationChannel(
                            "123",
                            "EarGuard",
                            NotificationManager.IMPORTANCE_HIGH
                        )
                        notificationChannel.description =
                            "You have exceeded the maximum usage limit of listening on headset"
                        notificationChannel.name = "EarGuard"
                        notificationChannel.lockscreenVisibility = 1
                        notificationChannel.shouldShowLights()
                        notificationChannel.enableVibration(true)
                        notificationChannel.setSound(
                            Uri.parse("R.raw.sad"),
                            AudioAttributes.Builder()
                                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build()
                        )
                        notificationChannel.shouldVibrate()
                        var notificationManager =
                            applicationContext.getSystemService(NotificationManager::class.java)
                        notificationManager.createNotificationChannel(notificationChannel)
                        notificationManager.notify(
                            123, NotificationCompat.Builder(
                                applicationContext, "123"
                            ).setSmallIcon(R.drawable.ic_launcher_foreground)
                                .setLargeIcon(
                                    BitmapFactory.decodeResource(
                                        applicationContext.resources,
                                        R.drawable.ic_launcher_foreground
                                    )
                                )
                                .setSound(
                                    Uri.parse("R.raw.sad")
                                )

                                .setContentTitle("EarGuard")
                                .setPriority(NotificationCompat.PRIORITY_HIGH)
                                .setContentText("You have exceeded the maximum usage limit of listening on headset")
                                .setAutoCancel(false)
                                .setChannelId("123")
                                .build()
                        )

                    }

                    break
                }


            }
        }.start()

//        }
        return Result.success()
    }

//    @SuppressLint("RestrictedApi")
//    override fun isRunInForeground(): Boolean {
//        return super.isRunInForeground()
//    }

    override fun onStopped() {
        Log.d(TAG, "Stopped Worker")
        super.onStopped()

    }

}

MainActivity.kt

package com.xanjit.focusly


import android.content.*
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkRequest
import com.xanjit.focusly.broadcast_receivers.AudioInputBroadcastReceiver
import com.xanjit.focusly.services.CustomService
import com.xanjit.focusly.workers.GetHeadsetUsageTimeWorker
import java.lang.Exception


class MainActivity : ComponentActivity() {

    lateinit var receiver: BroadcastReceiver
    var TAG = "EarGuard"
    lateinit var workManager: WorkManager
    lateinit var workRequest: WorkRequest

    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)
        
        receiver = AudioInputBroadcastReceiver()
        setContent {


            Surface() {
                Scaffold(
                    topBar = {
                        TopAppBar() {

                        }
                    }
                ) {


                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        var intentFilter = IntentFilter("android.intent.action.HEADSET_PLUG");
        registerReceiver(receiver, intentFilter)

    }
}
  • take a look at this question: https://stackoverflow.com/questions/9699292/how-to-stop-all-worker-threads-in-android-application Hope it helps! – Lopat Jun 13 '21 at 17:46

1 Answers1

0

You could try keep you workRequest.id on your AudioInputBroadcastReceiver and in case of disconnection you can stop this work. I think its a bad practice cancel all running works if you only want to finish your audio work.

cancelAllWork() Cancels all unfinished work. Use this method with extreme caution! By invoking it, you will potentially affect other modules or libraries in your codebase. It is strongly recommended that you use one of the other cancellation methods at your disposal.

class AudioInputBroadcastReceiver : BroadcastReceiver() {

    val workerRequestId: UUID? = null

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onReceive(context: Context?, intent: Intent?) {

        val isConnected = intent!!.getIntExtra("state", 0) === 1
        val workManager = WorkManager.getInstance(context!!)

        if (isConnected) {
            ....
            val workRequest = OneTimeWorkRequest.Builder(
                GetHeadsetUsageTimeWorker::class.java,
            ).setInputData(data.build()).build()

            workerRequestId = workRequest.id

            workManager.enqueue(workRequest)
        } else {
            Toast.makeText(context,"Disconnected",Toast.LENGTH_SHORT).show()
            workerRequestId?.let { workManager.cancelWorkById(it) }
        }
    }
...
Juan Fraga
  • 434
  • 3
  • 9