Send user a notification if app is not open from last 24 Hours

Viewed 207

I have a situation where the app has to locally generate a notification to the user. If the app is not opened for the last 24 hours and the internet is off.

I have tried to work manager to figure out the solution.

   private fun setUpWorker(context: Context)
{
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.NOT_REQUIRED).build()
    val workRequest =
        PeriodicWorkRequest.Builder(DozeWorkManager::class.java,1, TimeUnit.HOURS)
            .setConstraints(constraints)
            .build()

      WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        LOCAL_NOTIF_WORK,
        ExistingPeriodicWorkPolicy.KEEP,
        workRequest
    )
}

Here running hourly and checking if it's been 24 hours since the last notification was received then I will raise a local notification. The problem with this approach, it is not working in mi and other Chinese devices and sometimes it takes several hours to work again.

I also tried alarm manager.

   private fun startAlarm() {
    val CUSTOM_INTENT = "com.test.intent.action.ALARM"
    val intent = Intent(this@MainActivity, AlarmHelper::class.java)
    intent.action = CUSTOM_INTENT
    val pendingIntent: PendingIntent =
        getBroadcast(this@MainActivity, 101, intent, PendingIntent.FLAG_UPDATE_CURRENT)
    val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager

    alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
        System.currentTimeMillis(),
        System.currentTimeMillis()+60*60*1000, pendingIntent)
}

But it is not working when the app has been removed from the background.

Finally i tried below solution:

   private fun startAlert() {
    val CUSTOM_INTENT = "com.test.intent.action.ALARM"
    val intent = Intent(this@MainActivity, AlarmHelper::class.java)
    intent.action = CUSTOM_INTENT
    val pendingIntent: PendingIntent =
        PendingIntent.getBroadcast(this@MainActivity, 110, intent, PendingIntent.FLAG_CANCEL_CURRENT)
    val alarmManager = this@MainActivity.getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager

    val info = AlarmManager.AlarmClockInfo(System.currentTimeMillis()+60*60*1000,pendingIntent)
    alarmManager.setAlarmClock(info,pendingIntent)
}

This is working fine and tested in mi and realme devices but the problem with this approach is I have to manually do the looping in the receiver function. Like this

 override fun onReceive(context: Context?, p1: Intent?) {      
    setNotification(context)
    startAlert(context) // again setting the alarm.
}

The problem with this approach is, it creates a clock icon symbol in the user's device and as per android documentation this might consume battery

https://developer.android.com/reference/android/app/AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo,%20android.app.PendingIntent)

I am not sure what approach to follow or Do we have any alternatives? Any kind of help or suggestion will be highly appreciated.

2 Answers

This works on my Xiaomi device to start a broadcast receiver (called ScheduleAlarmsReceiver) at an exact time. You could set the delay to 24 hours before your app gets killed. It won't always trigger at 24 hours to the clock but should be good enough for most cases.

private fun scheduleSelf(context: Context) {

    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    val alarmIntent = Intent(context, ScheduleAlarmsReceiver::class.java).let { intent ->
        PendingIntent.getBroadcast(context, 0, intent, 0)
    }

    val delay = //your delay
    val triggerAt = SystemClock.elapsedRealtime() + delay
    alarmManager.setExact(
        AlarmManager.ELAPSED_REALTIME,
        triggerAt,
        alarmIntent
    )
}

Although, i don't quite understand your exact problem, but i have some sort of idea that might be able to help you. you create a value that lgos/record the time of the each application launch, then you can

let lastLaunch = myFunction() to get the last launch time and set it to 0 or whatever you want it to be. let timeFrame = 24hr/mins in 24hrs/or seconds

if the difference between the two variable exceeds the timeFrame, push the notification, otherwise do nothing.

Related