Hi I am implementing a alarm system in my app. I have an alarm manager that triggers a notification everyday in a certain time. It doesn't work as it intended the notification is not displayed at all. Please can anyone help me with these thank you.
my Alarm set code:
val calender = Calendar.getInstance()
calender[Calendar.HOUR_OF_DAY] = hour
calender[Calendar.MINUTE] = minute
calender[Calendar.SECOND] = 0
calender[Calendar.MILLISECOND] = 0
val pendingIntent = PendingIntent.getBroadcast(
requireContext(),
0,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
alarmManager.setInexactRepeating (
AlarmManager.RTC_WAKEUP,
calender.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
Broadcast receiver:
class AlarmReceiver : BroadcastReceiver() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, p1: Intent?) {
val notificationManager =
context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationCompatBuilder =
NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ID)
notificationCompatBuilder
.setContentTitle("Prescript")
.setContentText("Medicine time.")
.setSmallIcon(R.mipmap.ic_launcher).priority = NotificationCompat.PRIORITY_DEFAULT
notificationManager.notify(666, notificationCompatBuilder.build())
Log.d("TAG", "onReceive: $notificationCompatBuilder")
// Toast.makeText(context, "Alarm....", Toast.LENGTH_LONG).show();
}
}
Related
I'm trying to send notifications using AlarmManager and they are being sent very late. Sometimes they do get sent around the time they're supposed to be sent, but other times they're being sent 2 hours or even 6 hours later than the original time that was set.
This is the BroadcastReceiver() for the notification:
#RequiresApi(Build.VERSION_CODES.O)
class NotificationAlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val i = Intent(context, SplashActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
context,
0,
i,
PendingIntent.FLAG_IMMUTABLE
)
val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification_icon)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentTitle(context.getString(R.string.notification))
.setContentText(NOTIFICATION_CONTEXT_TEXT)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setStyle(NotificationCompat.BigTextStyle().bigText(NOTIFICATION_CONTEXT_TEXT))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
with(NotificationManagerCompat.from(context)) {
notify(Constants.NOTIFICATION_NOTIFICATION_ID, builder.build())
}
}
companion object {
private val NOTIFICATION_CONTEXT_TEXT: String by lazy { "Lorem ipsum" }
}
}
And this is the code for sending the notification:
notificationCalendar = Calendar.getInstance()
notificationCalendar[Calendar.HOUR_OF_DAY] = 8
notificationCalendar[Calendar.MINUTE] = 0
notificationCalendar[Calendar.SECOND] = 0
notificationCalendar[Calendar.MILLISECOND] = 0
if ((Calendar.getInstance().timeInMillis - notificationCalendar.timeInMillis) > 0) {
notificationCalendar.add(Calendar.DAY_OF_MONTH, 1)
}
notificationAlarmMgr = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
notificationAlarmIntent = Intent(
context,
NotificationAlarmReceiver::class.java
).let { intent ->
PendingIntent.getBroadcast(
context,
NOTIFICATION_ID,
intent,
PendingIntent.FLAG_IMMUTABLE
)
}
notificationAlarmMgr?.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
notificationCalendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
notificationAlarmIntent
)
Why are my notifications being sent so late? What can I do to ensure they get sent at least within a minute of the desired time?
I'm trying to set unit test for my android app. I have to test a notifications services that looks like that :
This class provide function to set notification in a context
class DeadlineNotification {
companion object {
private lateinit var alarmManager: AlarmManager
private lateinit var pendingIntent: PendingIntent
/*
Create a notification channel for reminder notifications
Creating an existing notification channel with its original values performs no operation,
so it's safe to call this code when starting an app.
*/
fun createNotificationChannel(context: Context){
val channelName :CharSequence = "reminders channel"
val description = "channel for reminders notifications"
val channel = NotificationChannel("remindersChannel", channelName, NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = context.getSystemService(NotificationManager::class.java)
channel.description=description
notificationManager.createNotificationChannel(channel)
}
/*
Set a notification that will be triggered in a given time in ms.
you can pass a title/description and Id in parameter
*/
fun setNotification(timeMS: Long, title: String, description: String, id: Int, context: Context){
alarmManager = context.getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager //this get an service instance of AlarmManager
val intent = Intent(context, ReminderBroadcastReceiver::class.java) //this create an intent of broadcast receiver
//Adding extra parameter that will be used in the broadcase receiver to create the notification
intent.putExtra("title", title)
intent.putExtra("description", description)
intent.putExtra("id", id)
//set the receiver as pending intent
pendingIntent = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_IMMUTABLE)
//set an alarm that will wake up the pending intent (receiver)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeMS, pendingIntent)
}
fun getAlarmManager():AlarmManager = this.alarmManager
}
}
setNotification will set an Alarm that will launch an intent of ReminderBroadcastReceiver :
//this class is a BroadcastReceiver that will send a notification when it is triggered
class ReminderBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
var channelId = "remindersChannel"
//retrieving some parameters for the notification
var title = intent!!.getStringExtra("title")
var content = intent!!.getStringExtra("description")
var notifId = intent!!.getIntExtra("id", 0)
val intent2 = Intent(context, MainActivity::class.java)
intent2!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
//this is the intent where the user will be send when clicking on the notification
val pendingIntent = PendingIntent.getActivity(context, 0, intent2, PendingIntent.FLAG_IMMUTABLE)
//Builder of the notification
val notifBuilder = NotificationCompat.Builder(context!!, channelId)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title + notifId.toString())
.setContentText(content)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_REMINDER)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
//send the notification
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(notifId, notifBuilder.build())
}
}
This will create a NotificationManager and send the notification.
The code above is working as expected.
Now I'm trying to write unit test for it, I tried this :
#RunWith(AndroidJUnit4::class)
class DeadlineNotificationTest {
#Test
fun `notification is triggered at currentTime and redirect to MainActivity`() {
val activity: MainActivity = Robolectric.setupActivity(MainActivity::class.java) //main Activity
DeadlineNotification.setNotification(System.currentTimeMillis(), "title", "empty description", 1, activity) //this create an alarm
//here we're looking for the notificationManager that have been
val notificationService: NotificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val shadowNotificationManager =
shadowOf(notificationService)
assertEquals(1, shadowNotificationManager.size())
val notification: Notification = shadowNotificationManager.allNotifications[0]
val contentIntent: PendingIntent = notification.contentIntent
val nextIntent = shadowOf(contentIntent).savedIntent
val nextClassName = nextIntent.component!!.className
assertEquals(nextClassName, MainActivity::class.java.getName())
}
}
But the first assertion fails, so I assume the shadowNotificationManager cannot see the notification.
Do you have any Idea how I should proceed to have a working test?
I've been looking for this for a couple of hours but I haven't found anything helpful. Right now, I have an activity (called other_recurringreminder) that sets a time (fomartted calendar, HH:mm; string), repetition frequency (int), repetition unit (like minutes, hours, days; string), whether it's on or off (bool), and a name (string)
In other_recurringreminder.kt, I have this function:
fun sendnotification()
{
val channelID = "channel1"
val notificationID = 1
val sharedPreferences: SharedPreferences = getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val builder = NotificationCompat.Builder(this, "channelID")
.setSmallIcon(R.drawable.centr)
.setColor(resources.getColor(R.color.purple))
.setContentTitle(sharedPreferences.getString("Alarm1Name_USERPREFS", "Reminder 1"))
.setContentText(getString(R.string.notif_recurringreminders))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
with(NotificationManagerCompat.from(this)) {
notify(notificationID, builder.build())
}
}
Which sends the notification when called.
How can I make it so that my app sends this notification at a time from SharedPreferences, with a title from SP, and repeats every x units from SP?
Should this function be in another kotlin file?
Can this work even after a restart, when my app hasn't yet been opened?If I want to schedule more than one notif with different values, do I need to duplicate anything?
Sorry if it's a dumb question, I'm fairly new to kotlin. and thanks!
you can use alarm manager for it.
first create a class with broadcast receiver like
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
Log.d("this", "notify")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val intent = Intent(context, AlarmActivity2::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val builder = NotificationCompat.Builder(context, "111")
.setSmallIcon(R.drawable.blue_stringart)
.setContentTitle("Alarm is running")
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setDefaults(NotificationCompat.DEFAULT_SOUND)
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.addAction(R.drawable.ic_baseline_stop_24,"Stop",pendingIntent)
.setContentIntent(pendingIntent)
val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
val r = RingtoneManager.getRingtone(context, notification)
r.play()
val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.notify(123, builder.build())
}
}
}
after that go to your activity class make 2 method and call in oncreate
private fun setAlarm1() {
var calender: Calendar
calender = Calendar.getInstance()
calender.set(Calendar.HOUR_OF_DAY, PUT_YOUR_ALARM HOUR)
calender.set(Calendar.MINUTE, PUT_YOUR_ALARM MINUTE)
calender.set(Calendar.SECOND, 0)
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val thuReq: Long = Calendar.getInstance().timeInMillis + 1
var reqReqCode = thuReq.toInt()
if (calender.timeInMillis < System.currentTimeMillis()) {
calender.add(Calendar.DAY_OF_YEAR, 1)
}
val alarmTimeMilsec = calender.timeInMillis
val intent = Intent(this, AlarmReceiver::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
val pendingIntent = PendingIntent.getBroadcast(this, reqReqCode, intent, 0)
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calender.timeInMillis,
HERE_PUT_YOUR_HOUR * 60 * 60 * 1000,
pendingIntent
)
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Alarmclock Channel"
val description = " Reminder Alarm manager"
val importance = NotificationManager.IMPORTANCE_HIGH
val notificationChannel = NotificationChannel(CHANNELID, name, importance)
notificationChannel.description = description
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(notificationChannel)
}
}
Note - Must to do(go to your app setting and give notification permission on) 1.alarmManager.setRepeating here you can use your alarm type as your wish. 2.requestcode must be unique for each alarm. 3. you must take a alarm time and keep in calender.timeInMillis which is you expecting alarm time.
still problem comments below
I'm testing for sending notification using alarm manager when the app is closed. Right now after clicking a button a notification is triggered after 10 seconds and I close the app.
The notification is showing when the app is open but not when closed.
Here is my code:
Triggering notification in TimeTableScheduleActivity:
private fun setUpAlarm(c: Calendar){
val cal = Calendar.getInstance()
cal.add(Calendar.SECOND, 10)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
Toast.makeText(this, "notification in 10 secs", Toast.LENGTH_SHORT).show()
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
}
AlertReceiver class:
class AlertReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
val intent = Intent(context, TimeTableScheduleActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
val pendingIntent = PendingIntent.getActivity(context, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context!!, Navigation.CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_stat_call_white)
.setLargeIcon(BitmapFactory.decodeResource(context!!.getResources(), R.mipmap.icon_round))
.setContentTitle("title")
.setContentText("body")
.setColor(Color.parseColor("#138FF7"))
.setContentIntent(pendingIntent)
.setVibrate(longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400))
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setLights(Color.WHITE, 500, 500)
.setPriority(NotificationCompat.PRIORITY_HIGH)
val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.notify(1, builder.build())
Toast.makeText(context,"alert receive",Toast.LENGTH_LONG).show()
}
}
I try to push notification by date to my app. I allready build the broadcast reciever and for some reason it didn't push the notification.
This is my code:
saveTime?.setOnClickListener() //save time notification
{
val hour: Int = tp!!.hour
val min: Int = tp!!.minute
var text = "" + hour + ":" + min
var calendar: Calendar = Calendar.getInstance()
calendar.set(Calendar.DAY_OF_WEEK,1)
calendar.set(Calendar.DAY_OF_WEEK,Calendar.FRIDAY)
calendar.set(Calendar.HOUR_OF_DAY,hour)
calendar.set(Calendar.MINUTE,min)
calendar.set(Calendar.SECOND, 0);
val intent = Intent()
val pendingIntent = PendingIntent.getActivity(this.activity,0,intent,PendingIntent.FLAG_UPDATE_CURRENT)
var alarmManager = this.activity.getSystemService(ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.timeInMillis, AlarmManager.INTERVAL_DAY,pendingIntent)
}
And here you'll see my broadcast reciever class:
class MyReciver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val timeAlert = System.currentTimeMillis()
val notificationManager = context
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
val pendingIntent = PendingIntent.getActivity(context, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//val alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notification = Notification.Builder(context)
.setContentTitle("some title:")
.setContentText("some text")
.setSmallIcon(R.drawable.notification_icon_background)
.setAutoCancel(true).setWhen(timeAlert)
.setContentIntent(pendingIntent)
notificationManager.notify(0, notification.build())
}
}