Ashok Choudhary
Ashok Choudhary

Reputation: 3

How To schedule and a send Notification even after user removes app from recent apps?

My app is simple

  1. Take Time from the user(I know how to do it)

  2. schedule A notification(I know how to send notification)

  3. Now I just want to know that How can I send this notification even user removes it from recent apps.

Tried Solutions- AlarmManager, BroudcastReceiver, Service, Intent Service,

But all are work only when the app is present in RAM (recent apps list Of Mobile).

How can I do that just tell me the topic. I don't need code. I will study that.

Upvotes: 0

Views: 798

Answers (2)

Lakindu
Lakindu

Reputation: 950

As you have mentioned that AlarmManager and others did not work for you, I tested what you are trying to achieve with JobScheduler.

It worked for me, and it worked even after removing the app from the recent apps list. I tried it on Android 10 emulator.

You have asked for topics / references to study as the answer. So first I'll mention the references I used.

Here is the code lab of JobScheduler and it's really helpful : https://codelabs.developers.google.com/codelabs/android-training-job-scheduler/

Here is a good reference about creating multiple scheduled jobs : https://android-developers.googleblog.com/2017/10/working-with-multiple-jobservices.html

Here is what I tried.

NotificationJobService.kt

private const val NOTIF_CHANNEL_ID = "primary_notification_channel"
private const val NOTIF_CHANNEL_NAME = "Job Service notification"

class NotificationJobService : JobService() {

    override fun onStartJob(params: JobParameters?): Boolean {

        // Get Notification Manager
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Create Notification Channel if device OS >= Android O
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel(NOTIF_CHANNEL_ID, NOTIF_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT).let {
                notificationManager.createNotificationChannel(it)
            }
        }

        // Create PendingIntent with empty Intent
        // So this pending intent does nothing
        val pendingIntent = PendingIntent.getActivity(this, 0, Intent(), PendingIntent.FLAG_ONE_SHOT)

        // Configure NotificationBuilder
        val builder = NotificationCompat.Builder(this, NOTIF_CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("Title")
            .setContentText("Message")
            .setAutoCancel(true)
            .setContentIntent(pendingIntent)

        // Make the Notification
        notificationManager.notify(0, builder.build())

        // False to let system know that the job is completed by the end of onStartJob(),
        // and the system calls jobFinished() to end the job.
        return false

    }

    override fun onStopJob(params: JobParameters?): Boolean {
        // True because if the job fails, you want the job to be rescheduled instead of dropped.
        return true
    }

}

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Job ID must be unique if you have multiple jobs scheduled
        var jobID = 0

        // Get fake user set time (a future time 1 min from current time)
        val ( userSetHourOfDay, userSetMinute ) = getMockUserSetTime()

        val timeToWaitBeforeExecuteJob = calculateTimeDifferenceMs(userSetHourOfDay, userSetMinute)

        (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).run {
            schedule(
                JobInfo.Builder(
                    jobID,
                    ComponentName(baseContext, NotificationJobService::class.java)
                )
                // job execution will be delayed by this amount of time
                .setMinimumLatency(timeToWaitBeforeExecuteJob)
                // job will be run by this deadline
                .setOverrideDeadline(timeToWaitBeforeExecuteJob)
                .build()
            )
        }
    }

    // Returns a pair ( hourOfDay, minute ) that represents a future time,
    // 1 minute after the current time
    private fun getMockUserSetTime() : Pair<Int, Int> {
        val calendar = Calendar.getInstance().apply {
            // add just 1 min from current time
            add(Calendar.MINUTE, 1)
        }
        return Pair(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE))
    }

    // Calculate time difference relative to current time in ms
    private fun calculateTimeDifferenceMs(hourOfDay: Int, minute: Int) : Long {
        val now = Calendar.getInstance()
        val then = (now.clone() as Calendar).apply {
            set(Calendar.HOUR_OF_DAY, hourOfDay)
            set(Calendar.MINUTE, minute)
        }
        return then.timeInMillis - now.timeInMillis
    }

}

I used setMinimumLatency(timeToWaitBeforeExecuteJob) and setOverrideDeadline(timeToWaitBeforeExecuteJob) constraints when scheduling the job so that, the job will be executed at exact time we want it to run.

I ran the app once, go back and removed the app from recent apps list. Then I suspended the device, and after 1 minute, I heard the notification sound. When I resumed the device and checked, the expected notification was there.

You should consider Remon Shehatta's answer as well. Because it seems WorkManager sits on top of JobScheduler and AlarmManager, and picks the right one based on device's API level. So it may be better to use WorkManager if you are targeting API levels older than 21. But as you mentioned that AlarmManager did not work for you, you should experiment and choose the right one.

Please update us with your findings.

Upvotes: 1

Remon Shehatta
Remon Shehatta

Reputation: 1470

you can use WorkManger to schedule tasks.

The WorkManager API makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or device restarts.

check Google documentation here.

for notifications, you can send a notification in your work manager class. learn more here.

these hints should be enough. let me know if you need more clarifications.

Upvotes: 3

Related Questions