Search code examples
androidbroadcastreceiver

Notifications per day of week


I have never scheduled notifications before and need help. My app have Notification entity which contains:

@Parcelize
@Entity
data class Notification(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    var time: Date,
    var daysOfWeek: Set<DayOfWeek>,
    var enabled: Boolean = false
) : Parcelable

I wish to let this notification trigger selected days of week in specified time. I also have several methods to set notifications:

private fun codeForNotification(notification: Notification, dayOfWeek: DayOfWeek) =
        1000 + notification.id * 10 + dayOfWeek.ordinal

    fun checkNotification(notification: Notification, isEnabled: Boolean? = null) = with(notification) {
        if ((isEnabled == null && enabled) || isEnabled == true) daysOfWeek.forEach { dow ->
            setNotification(time, dow, codeForNotification(this, dow))
        } else daysOfWeek.forEach { dow ->
            Intent(appContext, NotificationReceiver::class.java).let { intent ->
                PendingIntent.getBroadcast(
                    appContext,
                    codeForNotification(this, dow),
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT
                )
            }.let(alarmManager::cancel)
        }
    }

    fun setNotification(time: Date, dayOfWeek: DayOfWeek, code: Int) {
        c2.time = time
        c1.apply {
            this.time = Date()
            set(Calendar.HOUR_OF_DAY, c2.get(Calendar.HOUR_OF_DAY))
            set(Calendar.MINUTE, c2.get(Calendar.MINUTE))
        }
        c1.set(Calendar.DAY_OF_WEEK, dayOfWeek.calendarValue)
        if (c1.timeInMillis < System.currentTimeMillis()) {
            c1.add(Calendar.DAY_OF_YEAR, 7)
        }
        Intent(appContext, NotificationReceiver::class.java).let {
            PendingIntent.getBroadcast(appContext, code, it, PendingIntent.FLAG_CANCEL_CURRENT)
        }.let {
            alarmManager.setRepeating(
                AlarmManager.RTC_WAKEUP,
                c1.timeInMillis,
                AlarmManager.INTERVAL_DAY * DayOfWeek.values().size,
                it
            )
        }
    }

Notifications are set similarly to the question (using check notification), but they do not fire.

My receiver class:

class NotificationReceiver : BroadcastReceiver() {
    companion object {
        const val CHANNEL_ID = "CHANNEL"
        const val NOTIFY_ID = 1111
    }

    override fun onReceive(context: Context?, intent: Intent?) = context?.let{
        val builder: NotificationCompat.Builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setContentTitle("Notification")
            .setContentText("Hello world")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)

        val notificationManager =
            NotificationManagerCompat.from(context)
        notificationManager.notify(NOTIFY_ID, builder.build())
    } ?: Unit
}

And manifest have :

<uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".main.notification.NotificationReceiver" />

Please help me!


Solution

  • Setting notification channel fixed this issue:

    override fun onReceive(context: Context?, intent: Intent?) = context?.run {
            val notificationManager: NotificationManager? =
                getSystemService(this, NotificationManager::class.java)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                notificationManager?.let(::setNotificationChanel)
                Notification.Builder(context, CHANNEL_ID)
            } else {
                Notification.Builder(context)
            }.setSmallIcon(R.drawable.ic_access_alarm_24px)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(getString(R.string.notification_description))
                .setContentIntent(getActivityIntent(this))
                .setAutoCancel(true)
                .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_access_alarm_24px))
                .build().let { notification ->
                    notificationManager?.notify(NOTIFICATION_ID, notification)
                }
        } ?: Unit
    
        @RequiresApi(Build.VERSION_CODES.O)
        private fun setNotificationChanel(notificationManager: NotificationManager) =
            NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_HIGH).apply {
                description = CHANNEL_DESC
                enableLights(true)
                lightColor = Color.RED
                enableVibration(true)
                setShowBadge(true)
            }.let(notificationManager::createNotificationChannel)