cant push notification by date in kotlin - android

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())
}
}

Related

Testing Intent that will be triggered by an alarm

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?

How to schedule recurring notifications in kotlin?

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

Prevent old notifications from firing

I'm making an app that i schedule notifications for a day say morning , evening and night - the problem is if i opened the app at night the old notifications of morning and evening shows . i use below code
val alarmMgr = MyApplication.appContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager?
val intent = Intent(MyApplication.appContext, MyAlarmReceiver::class.java)
intent.putExtra("Title",title)
intent.putExtra("Body",body)
intent.putExtra("Id",id)
intent.putExtra("Sound",sound)
val pendingIntent = PendingIntent.getBroadcast(MyApplication.appContext, id, intent, 0)
alarmMgr!!.setRepeating(AlarmManager.RTC_WAKEUP,time,AlarmManager.INTERVAL_DAY,pendingIntent)
With this part inside onReceive of alarm
private fun sendNotification( intent: Intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationID = intent.extras!!.getInt("Id")!!
val title = intent.extras!!.getString("Title")
val body = intent.extras!!.getString("Body")
val sound = intent.extras!!.getString("Sound")
val channelID = "com.ebookfrenzy.notifydemo.news"
val resultIntent = Intent(MyApplication.appContext, MainActivity::class.java)
resultIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(
MyApplication.appContext,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val notification = Notification.Builder(MyApplication.appContext,
channelID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setChannelId(channelID)
.setContentIntent(pendingIntent)
.build()
sound?.let {
notification.sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + MyApplication.appContext.getPackageName() + "/raw/$it")
}
var notificationManager = MyApplication.appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager?.notify(notificationID, notification)
} else {
}
}

Notification is not working(Android Studio)

I am new to android studio. I was trying to create a notification when user click on a button embedded in recyclerView
user has to give time in Hours and Minutes only. I take user input as a string. And input is stored in SQLite database.
notifyMeUpdate function is working fine but Toast in Receiver class is not shown(I think Receiver class is not triggered).
Please ignore typo
Here is my code:
class User{
var id = 0
var time = ""
var amp = ""
var text = ""
var notifyMe = false
}
My User Class:
fun notifyMeUpdate(user: User) {
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
var hour = 0
var min = 0
for(i in 0 until user.time.length) {
if (user.time[i] == ':'){
var str = user.time.subSequence(0, i).toString()
var minStr = user.time.subSequence(i+1, user.time.length).toString()
if(user.amp == "AM"){
hour = str.toInt()
min = minStr.toInt()
}
else{
hour = str.toInt() + 12
min = minStr.toInt()
}
}
}
val cur_cal: Calendar = GregorianCalendar()
cur_cal.timeInMillis = System.currentTimeMillis()
val cal: Calendar = GregorianCalendar()
cal.add(Calendar.DAY_OF_YEAR, cur_cal[Calendar.DAY_OF_YEAR])
cal[Calendar.HOUR_OF_DAY] = hour
cal[Calendar.MINUTE] = min
cal[Calendar.SECOND] = 0
cal[Calendar.MILLISECOND] = cur_cal[Calendar.MILLISECOND]
cal[Calendar.DATE] = cur_cal[Calendar.DATE]
cal[Calendar.MONTH] = cur_cal[Calendar.MONTH]
val intent = Intent(context, Receiever::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
}
And here is my Receiever class
class Receiever: BroadcastReceiver(){
lateinit var notificationManager: NotificationManager
lateinit var notificationChannel: NotificationChannel
lateinit var builder: Notification.Builder
private var channelId = "package com.example.recyclerpractise"
private var description = "Text Notification"
override fun onReceive(context: Context?, intent: Intent?){
Toast.makeText(context, "Triggred", Toast.LENGTH_SHORT).show()
val intent = Intent(context, LauncherActivity::class.java)
val pintent = PendingIntent.getActivity(context, 0 , intent, PendingIntent.FLAG_UPDATE_CURRENT)
if (context != null) {
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel =
NotificationChannel(channelId, description, NotificationManager.IMPORTANCE_HIGH)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.GREEN
notificationChannel.enableVibration(true)
notificationManager.createNotificationChannel(notificationChannel)
if (context != null) {
builder = Notification.Builder(context, channelId)
.setContentTitle("Hello Moto")
.setContentText("Test Notification")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.ic_launcher_foreground))
.setContentIntent(pintent)
}
else{
builder = Notification.Builder(context)
.setContentTitle("Hello Moto")
.setContentText("Test Notification")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setLargeIcon(BitmapFactory.decodeResource(context?.resources, R.drawable.ic_launcher_foreground))
.setContentIntent(pintent)
}
notificationManager.notify(19867, builder.build())
}
}
}
Here is my onBindViewHolder of recycler list
override fun onBindViewHolder(p0: ViewHolder, p1: Int) {
val user: User = userList[p1]
p0.time.text = user.time
p0.text.text = user.text
p0.img.setOnClickListener{
val popup = PopupMenu(activity, p0.img)
popup.inflate(R.menu.schedulemenu)
popup.setOnMenuItemClickListener {
when(it.itemId){
R.id.menu_delete->{
activity.dbHelper.deleteData(userList[p1].id.toLong())
activity.refreshList()
}
R.id.menu_update->{
activity.updateUser(userList[p1])
}
R.id.notify->{
activity.notifyMeUpdate(userList[p1])
}
}
true
}
popup.show()
}
}
Thanks for Help
Thanks for all who tried. After several hours of debugging. I found that I did a very stupid mistake that haven't register my receiver in manifest file now it's working fine.

How to set multiple alarms in kotlin?

so I'm new to coding and I'm making an app for Muslims prayer times and I want an alarms to be set repeatedly on these times
I tried to many things but It doesn't works!
I have a praytimes class and if anyone wants it I'll put it
I will be more thankful, if you could help me on how to set an alarm for 1 prayer so I could do the rest.
Main Activity
val latitude = 30.354802
val longitude = 42.2461069
val timezonoffset = 3.0
val timeZoneId = "Middle East/Alowiqila"
val prayTimes = PrayTimes()
prayTimes.timeFormat = prayTimes.time12//
prayTimes.calcMethod = prayTimes.makkah// Muslim World League (MWL)
prayTimes.asrJuristic = prayTimes.hanafi// Shafii (standard)
prayTimes.adjustHighLats = prayTimes.angleBased
val offsets = intArrayOf(0, 0, 0, 0, 0, 0, 0) // {Fajr,Sunrise,Dhuhr,Asr,Sunset,Maghrib,Isha}
prayTimes.tune(offsets)
val cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId))
cal.time = Date()
val times = prayTimes.getPrayerTimes(cal, latitude, longitude, timezonoffset)
println("prayer times for Alowiqila")
System.out.println("Fajr : " + times.get(0))
System.out.println("Sunrise : " + times.get(1))
System.out.println("Duhr : " + times.get(2))
System.out.println("Asr : " + times.get(3))
System.out.println("Sunset : " + times.get(4))
System.out.println("Magrib : " + times.get(5))
System.out.println("Isha : " + times.get(6))
// I want the Alarm to be set to the code above it
fun startAlarm(isNotification:Boolean, isRepeat:Boolean) {
val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val myIntent= Intent(this#MainActivity, AlarmReceiver::class.java)
val pendingIntent:PendingIntent
// SET TIME HERE
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 15)
calendar.set(Calendar.MINUTE, 20)
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0)
if (!isRepeat)
manager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 3000, pendingIntent)
else
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, pendingIntent)
}
AlarmReceiver.kt
and here is my alarm receiver in witch I've added me notifications
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val builder = NotificationCompat.Builder(context)
val myIntent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
context,
0,
myIntent,
FLAG_ONE_SHOT
)
builder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setContentTitle("موعد الاذان")
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS or Notification.DEFAULT_SOUND)
.setContentInfo("Info")
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(1, builder.build())
}
You have to put different requestCode in pending intent, each alarm manager requires different requestCode.
in your mainActivity
pendingIntent = PendingIntent.getBroadcast(this, (0..2147483647).random(), myIntent, 0)

Categories

Resources