I am trying to show a local notification in the scheduled days of week, in the scheduled hour and minute even if the app is killed.
The reason I am not using Alarm Manager is because the Android 14 only supports the USE_EXACT_ALARM permission, but google play does not support it if you are not using calendar. Since I am not using calendar i am trying a different way to show the notification. The problem is, if i use the Worker, since it does a lot of calls all the time, the notification shows more than 40 times.I want to show the notification only once, i tried using the preferences but again the notification will show 4 times. Here is my code, if I set the seconds also to 0, the notification will not show at all. I don’t know how to fix this issue, when the seconds are 0 the worker does not catch the time, but if i remove it, it will show 40+ times the notification. I am confused, how can i fix this
class ReminderWorker(appContext: Context, workerParams: WorkerParameters) :
CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
if(AppPreferences.userNotifications && AppPreferences.specialUserNotifications){
AppPreferences.selectedDays.fromPrettyJson<ArrayList<String>>().forEach {
val nextNotificationTime =calculateInitialDelay(
it.toInt(),
AppPreferences.hourOfDay,
AppPreferences.minuteOfDay
)
if (nextNotificationTime == 0L) {
triggerNotification()
}
else {
scheduleNextWork(nextNotificationTime)
}
}
}
return Result.success()
}
private fun calculateInitialDelay(dayOfWeek: Int, hourOfTheDay: Int, minuteOfTheDay: Int): Long {
val currentCalendar = Calendar.getInstance().apply {
// set(Calendar.SECOND, 0)
// set(Calendar.MILLISECOND, 0)
}
val notificationCalendar = Calendar.getInstance().apply {
set(Calendar.DAY_OF_WEEK, dayOfWeek)
set(Calendar.HOUR_OF_DAY, hourOfTheDay)
set(Calendar.MINUTE, minuteOfTheDay)
//If i set the seconds 0 here the notification will not come
// set(Calendar.SECOND, 0)
// set(Calendar.MILLISECOND, 0)
}
var initialDelay = notificationCalendar.timeInMillis - currentCalendar.timeInMillis
if (initialDelay < 0) {
notificationCalendar.add(Calendar.WEEK_OF_YEAR, 1)
initialDelay = notificationCalendar.timeInMillis - currentCalendar.timeInMillis
} else if (initialDelay == 0L) {
// If the scheduled time is exactly now
return 0L
}
return initialDelay
}
private fun scheduleNextWork(nextNotificationTime: Long) {
val workRequest = OneTimeWorkRequestBuilder<ReminderWorker>()
.setInitialDelay(nextNotificationTime - System.currentTimeMillis(), java.util.concurrent.TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(applicationContext).enqueue(workRequest)
}
private fun triggerNotification() {
val notificationId = Random().nextInt(60000)
val notificationManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = applicationContext.getString(R.string.message_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
// Create the NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = applicationContext.getString(R.string.message_notification_channel_name)
val descriptionText = applicationContext.getString(R.string.message_notification_channel_name)
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(channelId, name, importance).apply {
description = descriptionText
enableLights(true)
enableVibration(true)
if (defaultSoundUri != null) {
val att = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()
setSound(defaultSoundUri, att)
}
lightColor = Color.parseColor("#501450")
}
notificationManager.createNotificationChannel(channel)
}
val newIntent = Intent(applicationContext, StartActivity::class.java)
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
newIntent.action = "actionString" + System.currentTimeMillis()
val pendingIntent = PendingIntent.getActivity(
applicationContext,
0,
newIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notificationBuilder = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setColor(Color.parseColor("#222831"))
.setContentText(applicationContext.getString(R.string.remiderNotificationText))
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setVibrate(LongArray(0))
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent)
notificationManager.notify(notificationId, notificationBuilder.build())
}
}
Flutura Demaj is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.