Reputation: 141
I am trying to send notification daily at 10am. The code works fine when app is running and in background, but it does not work when the app is terminated/Killed.
Here is what I am doing,
In Manifest:
<receiver
android:name=".ReminderBroadcast"
android:exported="true"
android:enabled="true"/>
My BroadcastReceiver:
public class ReminderBroadcast extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
context.startService(new Intent(context, NotifyService.class));
}
}
My Service inside onCreate:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "notifyHackhshieldPP")
.setSmallIcon(R.drawable.logopp)
.setContentTitle("Hello")
.setContentText("Notification Test")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
notificationManager.notify(200, builder.build());
Then calling it:
private void setnotificationSendService()
{
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//creating a new intent specifying the broadcast receiver
Intent i = new Intent(this, ReminderBroadcast.class);
//creating a pending intent using the intent
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
//setting the repeating alarm that will be fired every day
Calendar alarmStartTime = Calendar.getInstance();
alarmStartTime.set(Calendar.HOUR_OF_DAY, 20);
alarmStartTime.set(Calendar.MINUTE, 5);
alarmStartTime.set(Calendar.SECOND, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, (alarmStartTime.getTimeInMillis()), AlarmManager.INTERVAL_DAY, pi);
}
Upvotes: 2
Views: 2562
Reputation: 1545
According to official documents, you can use alarmMgr.setInexactRepeating() but due to the system being busy it does not work properly I found another way to do this work. Use alarmMgr.set() for this purpose this will Wake up the device to fire a one-time (non-repeating) alarm. But when it triggers the device give it next date and time. It works properly when the app is terminated/Killedwork I am describing both methods just follow which one you want
NotificationUtils.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
class NotificationUtils(context:Context) {
private var mContext = context
private lateinit var notificationBuilder: NotificationCompat.Builder
val notificationManager = NotificationManagerCompat.from(mContext)
private val CHANNEL_ID = "My_Notification_Channel"
init {
createNotificationChannel()
initNotificationBuilder()
}
fun launchNotification(){
with(NotificationManagerCompat.from(mContext)) {
// notificationId is a unique int for each notification that you must define
notificationManager.notify(0, notificationBuilder.build())
}
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Channel Name"
val descriptionText = "Channel Description"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notifiManager: NotificationManager =
mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notifiManager.createNotificationChannel(channel)
}
}
private fun initNotificationBuilder() {
// Create an explicit intent for an Activity in your app
val sampleIntent = Intent(mContext, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(mContext, 0, sampleIntent, 0)
/***
* Notice that the NotificationCompat.Builder constructor requires that you provide a channel ID.
* This is required for compatibility with Android 8.0 (API level 26) and higher,
* but is ignored by older versions.
*/
notificationBuilder = NotificationCompat.Builder(mContext, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Notification Title")
.setContentText("Notification Body Text, Notification Body Text")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
// Automatically removes the notification when the user taps it.
.setAutoCancel(true)
}
}
AlarmUtils.kt
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import java.util.*
class AlarmUtils(context: Context) {
private var mContext = context
private var alarmMgr: AlarmManager? = null
private var alarmIntent: PendingIntent
init {
alarmMgr = mContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(mContext, AlarmReceiver::class.java).let { mIntent ->
// if you want more than one notification use different requestCode
// every notification need different requestCode
PendingIntent.getBroadcast(mContext, 100, mIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
fun initRepeatingAlarm(){
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, 10)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
}
alarmMgr?.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
alarmIntent
)
}
}
AlarmReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class AlarmReceiver:BroadcastReceiver() {
override fun onReceive(context: Context?, mIntent: Intent?) {
val notificationUtils = NotificationUtils(context!!)
notificationUtils.launchNotification()
}
}
AndroidManifest.xml
<receiver android:name=".AlarmReceiver" />
MainActivity.kt
val alarmUtils = AlarmUtils(this)
alarmUtils.initRepeatingAlarm()
NotificationUtils.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
class NotificationUtils(context:Context) {
private var mContext = context
private lateinit var notificationBuilder: NotificationCompat.Builder
val notificationManager = NotificationManagerCompat.from(mContext)
private val CHANNEL_ID = "My_Notification_Channel"
init {
createNotificationChannel()
initNotificationBuilder()
}
fun launchNotification(){
with(NotificationManagerCompat.from(mContext)) {
// notificationId is a unique int for each notification that you must define
notificationManager.notify(0, notificationBuilder.build())
}
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Channel Name"
val descriptionText = "Channel Description"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notifiManager: NotificationManager =
mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notifiManager.createNotificationChannel(channel)
}
}
private fun initNotificationBuilder() {
// Create an explicit intent for an Activity in your app
val sampleIntent = Intent(mContext, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(mContext, 0, sampleIntent, 0)
/***
* Notice that the NotificationCompat.Builder constructor requires that you provide a channel ID.
* This is required for compatibility with Android 8.0 (API level 26) and higher,
* but is ignored by older versions.
*/
notificationBuilder = NotificationCompat.Builder(mContext, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Notification Title")
.setContentText("Notification Body Text, Notification Body Text")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
// Automatically removes the notification when the user taps it.
.setAutoCancel(true)
}
}
AlarmUtils.kt
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import java.util.*
class AlarmUtils(context: Context) {
private var mContext = context
private var alarmMgr: AlarmManager? = null
private var alarmIntent: PendingIntent
init {
alarmMgr = mContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(mContext, AlarmReceiver::class.java).let { mIntent ->
// if you want more than one notification use different requestCode
// every notification need different requestCode
PendingIntent.getBroadcast(mContext, 100, mIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
fun initRepeatingAlarm(calendar: Calendar){
calendar.apply {
set(Calendar.HOUR_OF_DAY, 10)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
}
alarmMgr?.set( AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
alarmIntent)
}
AlarmReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import java.util.*
class AlarmReceiver:BroadcastReceiver() {
override fun onReceive(context: Context?, mIntent: Intent?) {
val notificationUtils = NotificationUtils(context!!)
notificationUtils.launchNotification()
val calendar = Calendar.getInstance()
calendar.add(Calendar.DAY_OF_YEAR, 1)
val daysNextCalendar = calendar
val alarmUtils = AlarmUtils(context)
alarmUtils.initRepeatingAlarm(daysNextCalendar)
}
}
AndroidManifest.xml
<receiver android:name=".AlarmReceiver" />
MainActivity.kt
val calendar = Calendar.getInstance()
val alarmUtils = AlarmUtils(this)
alarmUtils.initRepeatingAlarm(calendar)
If you want the alarm should work after rebooting the device you should do the following thing.
AlarmBootReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import java.util.*
class AlarmBootReceiver : BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == "android.intent.action.BOOT_COMPLETED") {
val calendar = Calendar.getInstance()
val alarmUtils = AlarmUtils(context)
alarmUtils.initRepeatingAlarm(calendar)
}
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".AlarmBootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Upvotes: 1