Ethan Allen
Ethan Allen

Reputation: 14835

Why does my notification show every time I open my Android app?

I set up this code (or so I thought) to display a Notification once every 7 days on a user's Android device, even if the user reboots their device. But what I'm seeing as a side-effect is that every time the user opens the app it also pops that notification.

How can I set this up so that the notifications get set up properly, even after reboot, but doesn't display until the required time.

I have a MainActivity with this:

override fun onCreate(savedInstanceState: Bundle?) {
  val bootRec = BootReceiver()
  bootRec.scheduleNotifications(this)
}

It calls BootReceiver with this:

class BootReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == "android.intent.action.BOOT_COMPLETED") {
            scheduleNotifications(context)
        }
    }

    fun scheduleNotifications(context: Context) {
        val receiver = ComponentName(context, BootReceiver::class.java)

        context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
        )

        val alarmMgr: AlarmManager?

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

        // Set the alarm to start at 8:30 a.m.
        val calendar: Calendar = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            set(Calendar.DAY_OF_WEEK, 1)
            set(Calendar.HOUR_OF_DAY, 15)
            set(Calendar.MINUTE, 13)
        }

        // setRepeating() lets you specify a precise custom interval--in this case,
        // 1 week.
        alarmMgr.setRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            AlarmManager.INTERVAL_DAY * 7,
            alarmIntent
        )
    }
}

which in turn calls AlarmReceiver:

class AlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val notificationManager = context.getSystemService(AppCompatActivity.NOTIFICATION_SERVICE) as NotificationManager
        val notChanId = "icollecteverything"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel = NotificationChannel(notChanId, "My Notifications", NotificationManager.IMPORTANCE_MAX)
            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.BLUE
            notificationChannel.vibrationPattern = longArrayOf(0, 1000, 500, 1000)
            notificationChannel.enableVibration(true)
            notificationManager.createNotificationChannel(notificationChannel)
        }

        // Create an explicit intent for an Activity in your app
        val intentMain = Intent(context, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }
        val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intentMain, 0)

        val notification = NotificationCompat.Builder(context, notChanId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setPriority(NotificationManagerCompat.IMPORTANCE_HIGH)
            .setContentIntent(pendingIntent)
            .setContentTitle("Title")
            .setContentText("Notification Text.")
            .setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText("Notification Text."))
            .build()
        notificationManager.notify(1, notification)
    }

}

The AndroidManifest has this in it:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<receiver android:name=".helper.AlarmReceiver" android:enabled="true"/>
<receiver android:name=".helper.BootReceiver"
        android:exported="true"
        android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

Upvotes: 1

Views: 541

Answers (1)

Steven Jeuris
Steven Jeuris

Reputation: 19100

Did you read the documentation on AlarmManager.setRepeating?

If the stated trigger time is in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.

I suspect this is the root of your problem.

If so, the solution would thus be making sure that triggerAtMillis is set to a time in the future. Probably feasibly through some additional/different Calendar calls.

Upvotes: 1

Related Questions