Hello guys i'm making app for tracking insulin injections for my mom. I want to make app that will create notification automatically every 7 p.m. Can you advice me how to do it? I tried to google it but i'm only found videos with notifications by clicking button but it will not work for me because i want my app to create notifications even when app is closed so i need something like Services that will always by alive even app is closed
You firstly need to instantiate a Broadcast Receiver class and override their onReceive function.
Don't forget to add this to your manifest.
<receiver android:name=".AlertReceiver" />
Override the function as talked.
class AlertReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Glide.with(context).asBitmap().load(R.drawable.ic_diagnosis_24dp).into(object : CustomTarget<Bitmap>() {
override fun onLoadCleared(placeholder: Drawable?) {}
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val notificationHelper = NotificationHelper(context,resource,intent.extras!!.getInt("requestCode"))
val nb = notificationHelper.channelNotification
notificationHelper.manager?.notify(1, nb.build())
}
})
}
}
You can prepare a Notification Helper just in case you want to deal with things in a better format.
class NotificationHelper(base: Context?, healthReportIcon: Bitmap, requestCode: Int) : ContextWrapper(base) {
private val healthIcon = healthReportIcon
private var mManager: NotificationManager? = null
private lateinit var beforeTime: String
private var intentActivity: Class<*>
#TargetApi(Build.VERSION_CODES.O)
private fun createChannel() {
val channel = NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH)
manager!!.createNotificationChannel(channel)
}
val manager: NotificationManager? get() {
if (mManager == null) {
mManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
return mManager
}
val channelNotification: NotificationCompat.Builder get() = NotificationCompat.Builder(applicationContext, channelID)
.setContentTitle("Reminder!")
.setContentText("Update medical records before $beforeTime")
.setSmallIcon(R.drawable.ic_round_local_hospital_24)
.setColor(ContextCompat.getColor(this,R.color.blue_diff))
.setLargeIcon(healthIcon)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setPriority(NotificationCompat.PRIORITY_MAX)
.setTimeoutAfter(1800000)
.setAutoCancel(true)
.setContentIntent(PendingIntent.getActivity(baseContext, 0, Intent(baseContext, intentActivity), 0))
companion object {
const val channelID = "phoneId"
const val channelName = "phoneChannel"
}
init {
when (requestCode) {
0 -> {
beforeTime = "12:30 AM"
}
1 -> {
beforeTime = "6:30 AM"
}
2 -> {
beforeTime = "12:30 PM"
}
3 -> {
beforeTime = "6:30 PM"
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannel()
}
intentActivity = if(FirebaseAuth.getInstance().currentUser!=null) {
HomeActivity::class.java
} else{
Splash::class.java
}
}
}
Finally, set or cancel your alarms in your codebase.
private fun startAlarms() {
val cal0 = Calendar.getInstance()
cal0[Calendar.HOUR_OF_DAY]=24
cal0[Calendar.MINUTE]=0
cal0[Calendar.SECOND]=0
val cal1 = Calendar.getInstance()
cal1[Calendar.HOUR_OF_DAY]=6
cal1[Calendar.MINUTE]=0
cal1[Calendar.SECOND]=0
val cal2 = Calendar.getInstance()
cal2[Calendar.HOUR_OF_DAY]=12
cal2[Calendar.MINUTE]=0
cal2[Calendar.SECOND]=0
val cal3 = Calendar.getInstance()
cal3[Calendar.HOUR_OF_DAY]=18
cal3[Calendar.MINUTE]=0
cal3[Calendar.SECOND]=0
if (cal0.before(Calendar.getInstance())) {
cal0.add(Calendar.DATE, 1)
}
if (cal1.before(Calendar.getInstance())) {
cal1.add(Calendar.DATE, 1)
}
if (cal2.before(Calendar.getInstance())) {
cal2.add(Calendar.DATE, 1)
}
if (cal3.before(Calendar.getInstance())) {
cal3.add(Calendar.DATE, 1)
}
val alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
intent.putExtra("requestCode",0)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal0.timeInMillis, PendingIntent.getBroadcast(this, 0,intent , PendingIntent.FLAG_UPDATE_CURRENT))
intent.putExtra("requestCode",1)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal1.timeInMillis, PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT))
intent.putExtra("requestCode",2)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal2.timeInMillis, PendingIntent.getBroadcast(this, 2,intent, PendingIntent.FLAG_UPDATE_CURRENT))
intent.putExtra("requestCode",3)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal3.timeInMillis, PendingIntent.getBroadcast(this, 3, intent, PendingIntent.FLAG_UPDATE_CURRENT))
}
private fun cancelAlarms() {
val alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
alarmManager.cancel(PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT))
alarmManager.cancel(PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT))
alarmManager.cancel(PendingIntent.getBroadcast(this, 2, intent, PendingIntent.FLAG_CANCEL_CURRENT))
alarmManager.cancel(PendingIntent.getBroadcast(this, 3, intent, PendingIntent.FLAG_CANCEL_CURRENT))
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT).cancel()
PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT).cancel()
PendingIntent.getBroadcast(this, 2, intent, PendingIntent.FLAG_CANCEL_CURRENT).cancel()
PendingIntent.getBroadcast(this, 3, intent, PendingIntent.FLAG_CANCEL_CURRENT).cancel()
}
Hope this helped you out. Happy Coding! :)
Related
I'm trying stopping running coroutineWorker from notification button. I tried 3 methods and 2 of them calls "Result.failure()" & working fine. However another one doesn't.
Below CoroutineWorker shows foregroundInfo and Starts ringtone.
class RingWork(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
companion object {
val ALARM_CHANNEL_ID = "alarm_channel6"
}
lateinit var ringtoneSound: Ringtone
val context = applicationContext
#RequiresApi(Build.VERSION_CODES.Q)
override suspend fun doWork(): Result {
return try {
val alarmId = inputData.getInt("alarmId", 0)
val notificationMgr =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//CHANNEL
val alarmChannel = NotificationChannel(
ALARM_CHANNEL_ID, "alarm" ,NotificationManager.IMPORTANCE_HIGH
)
alarmChannel.setSound(null, null)
alarmChannel.enableVibration(false)
alarmChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationMgr.createNotificationChannel(alarmChannel)
val fullScreenIntent = Intent(context, LockscreenActivity::class.java).putExtra("alarmId", alarmId)
//This calls "failure" properly
val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
//This calls "failure" properly
val stop1PendingIntent =
WorkManager.getInstance(context).createCancelPendingIntent(getId())
val s2Intent = Intent(context, StopAlarmReceiver::class.java).putExtra("alarmId", alarmId)
//This is not.
val stop2PendingIntent = PendingIntent.getBroadcast(context, 1, s2Intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, ALARM_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle("title")
.setFullScreenIntent(fullScreenPendingIntent, true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setAutoCancel(true)
.setSound(null)
.setVibrate(null)
.addAction(R.drawable.ic_stat_name, "Stop1", stop1PendingIntent)
.addAction(R.drawable.ic_stat_name, "Stop2", stop2PendingIntent)
setForeground(
ForegroundInfo(1999999, builder.build(), FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
)
ringtoneSound =
RingtoneManager.getRingtone(context, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
ringtoneSound.play()
delay(30000L)
ringtoneSound.stop()
Result.success()
} catch (e: Exception) {
Result.failure()
} finally {
cleanup()
}
}
fun cleanup(){
ringtoneSound.stop()
}
}
In LockScreenActivity, there is a button to stop ringtone.
binding.stoppingbutton.setOnClickListener {
val workMgr = WorkManager.getInstance(applicationContext)
workMgr.cancelUniqueWork("RingWork-$alarmId")
finish()
}
This calls "result.failure" and "finally" then ringtone will stop, notification will disapear. working fine.
However, if I press "Stop2" button on the notification.
class StopAlarmReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val alarmId = intent.getIntExtra("alarmId", 0)
val workMgr = WorkManager.getInstance(context)
workMgr.cancelUniqueWork("RingWork-$alarmId")
}
}
It cancels worker, but it won't call "result.failure" and "finally", so ringtone won't stop. Notification also won't disappear.
fullScreenPendingIntent and stop2PendingIntent are doing the same thing, but why it won't behave same?
You can edit your PendingIntent like this and it will trigger onReceive:
val stop2PendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
PendingIntent.getBroadcast(context, downloadFile.productId, cancelIntent, PendingIntent.FLAG_IMMUTABLE)
else
PendingIntent.getBroadcast(context, downloadFile.productId, cancelIntent, 0)
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?
How can I cancel an alarm set with setAlarmClock()?
val alarmReceiver = Intent(applicationContext, AlarmReceiver::class.java)
val alarmReceiverPi = PendingIntent.getBroadcast(applicationContext, 0, alarmReceiver, 0)
val alarmInfo = AlarmManager.AlarmClockInfo(time, alarmReceiverPi)
alarmManager.setAlarmClock(alarmInfo, alarmReceiverPi)
The id to used to locate the PendingIntent, following is my example:
fun setAlarm() {
val alarmPendingIntent = getAlarmPendingIntent(alarmId)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, _timeLong.value, alarmPendingIntent)
showToast("Alarm has been set")
}
fun cancelAlarm() {
val alarmPendingIntent = getAlarmPendingIntent(alarmId)
alarmManager.cancel(alarmPendingIntent)
showToast("Alarm has bee canceled")
}
private fun getAlarmPendingIntent(id: Long): PendingIntent {
val intent = Intent(getApplication(), AlarmReceiver::class.java)
return PendingIntent.getBroadcast(getApplication(), id.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT) //will override if same id
}
Helpful reading:
How to cancel alarm from AlarmManager
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.
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())
}
}