After I call schedulePing my alarm fires at set time period. With pingScheduled I can see if pending intent exists. However, if I cancel the alarm with cancelPing the pingScheduled still return true.
fun schedulePing(context: Context) {
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, EventReceiver::class.java)
intent.action = EventReceiver.PING
val pendingIntent = PendingIntent.getBroadcast(context, PING, intent,
PendingIntent.FLAG_CANCEL_CURRENT)
val s = SettingsUtil.load(context)
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + s.periodPing, s.periodPing,
pendingIntent)
}
fun cancelPing(context: Context) {
if (pingScheduled(context).not()) return
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, EventReceiver::class.java)
intent.action = EventReceiver.PING
val pendingIntent = PendingIntent.getBroadcast(context, PING, intent,
PendingIntent.FLAG_CANCEL_CURRENT)
am.cancel(pendingIntent)
}
fun pingScheduled(context: Context): Boolean {
val intent = Intent(context, EventReceiver::class.java)
intent.action = EventReceiver.PING
return PendingIntent.getBroadcast(context, PING,
intent, PendingIntent.FLAG_NO_CREATE) != null
}
am.cancel(pendingIntent) cancel alram, but does not discard the pending intent. So it is important to call
pendingIntent.cancel after am.cancel to be able to check correct presence with PendingIntent.FLAG_NO_CREATE
Related
I have an app where the user creates its own local notifications. User declares name, date and time the nofication should popup and specifies the repeating frequency.
Then the notifications are listed in a recyclerview in another fragment.
The user is able to delete notification by swiping its recyclerview item to the left.
But when I create a notification, delete it then it still pops up at the specified time.
I am storing the notificationID in SharedPreferences as a date when its created (so that I can store it in my DB). I am passing it as a string with putExtra to my BroadcastReceiver class, I am getting the notificationID as a String in my BroadcastReceiver class with getStringExtra. Then passing the same notificationID.toInt() to my pendingIntent.getActivity. Then in my Fragment with recyclerView I am passing the same notificationID for cancelling and it still doesn't cancel.
Perhaps I'm using wrong flags?
Thanks a lot for any help.
Here's my BroadcastReceiver class:
const val titleExtra = "titleExtra"
const val descriptionExtra = "descriptionExtra"
val notificationID = "notificationID"
class Notification: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val intentToRepeat = Intent(context, MainActivity::class.java)
val id = intent.getStringExtra(notificationID).toString()
val pendingIntent = PendingIntent.getActivity(context, id.toInt(), intentToRepeat, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(context, channelID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(intent.getStringExtra(titleExtra))
.setContentText(intent.getStringExtra(descriptionExtra))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (intent.action == "cancel") {
manager.cancel(id.toInt())
}
else {
manager.notify(id.toInt(), notification)
}
}
}
My AndroidManifest:
<receiver android:name=".powiadomienia.Powiadomienie" android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="cancel"/>
<action android:name="create" />
</intent-filter>
</receiver>
In my recyclerview with notifications listed:
val currentNotification: SetNotification = listAdapter.getNotificationByPosition(viewHolder.bindingAdapterPosition)
if(direction == ItemTouchHelper.LEFT) {
// CANCEL
//val manager = requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//manager.cancel(currentPowiadomienie.notificationId!!)
val alarmManager = requireActivity().getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(requireContext(), Notification::class.java)
intent.action = "cancel"
val pendingIntent = PendingIntent.getService(requireContext(), currentNotification.notificationId!!.toInt(), intent, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE)
pendingIntent?.let { _pendingIntent ->
alarmManager.cancel(_pendingIntent)
}
Neither manager.cancel() nor alarmManager.cancel() works.
The notification creates but how to cancel it?!
I think you need to call notifydatasetchanged() method after the alarmManager.cancel() like this:
val currentNotification: SetNotification =
listAdapter.getNotificationByPosition(viewHolder.bindingAdapterPosition)
if(direction == ItemTouchHelper.LEFT) {
val alarmManager =
requireActivity().getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(requireContext(), Notification::class.java)
intent.action = "cancel"
val pendingIntent = PendingIntent.getService(requireContext(),
currentNotification.notificationId!!.toInt(), intent,
PendingIntent.FLAG_CANCEL_CURRENT or
PendingIntent.FLAG_IMMUTABLE)
pendingIntent?.let { _pendingIntent ->
alarmManager.cancel(_pendingIntent)
notifyDataSetChanged()
}
I've solved my issue for not canceling coming notifications:
I think I was passing the wrong context. Check if you're passing the right one
To cancel a notification:
private fun removeAlarm(id: Int){
val alarmManager = activity?.getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Notification = BroadcastReceiver class
val intent = Intent(requireContext(), Notification::class.java)
val pendingIntent = PendingIntent.getBroadcast(requireContext(), id, intent, PendingIntent.FLAG_IMMUTABLE)
alarmManager.cancel(pendingIntent)
}
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'm trying to schedule notifications using the AlarmManager but for whatever reason, the onReceive method on my receiver isn't firing.
Here's how I'm scheduling the alarm
val intent = Intent(this, ReminderReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
val cal: Calendar = Calendar.getInstance()
cal.add(Calendar.SECOND, 5)
val amanager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
amanager.set(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
and here's the onReceive method
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context,"notification", Toast.LENGTH_SHORT).show()
}
I tried manually sending a broadcast to see if it works and there's no problem there so the issue shouldn't be related to the manifest.
I'm running this on MIUI12 android 10
I see no issue with your logic if your problem still prevails, try the following as a workaround
val intent = Intent(this, ReminderReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
// val cal: Calendar = Calendar.getInstance()
// cal.add(Calendar.SECOND, 5)
val triggerTime = SystemClock.elapsedRealtime() + 5_000 // five seconds from now
val amanager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// amanager.set(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(
amanager,
AlarmManager.ELAPSED_REALTIME_WAKEUP,
triggerTime,
pendingIntent
)
Have 2 methods:
addAlarm()
val myIntent = Intent(context, AlarmReceiver::class.java)
if (SDK_INT > Build.VERSION_CODES.M) {
myIntent.action = "ADD_ALARM"
} else {
myIntent.putExtra("alarm", alarm)
}
val pendingIntent = PendingIntent.getBroadcast(context, 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (SDK_INT < Build.VERSION_CODES.M)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
else
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
/*
if I try to cancel alarm after creating like this:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.cancel(pendingIntent)
it would work and alarm would be canceled. Seems like problem is
in pendingIntent.
*/
deleteAlarm()
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
var myIntent = Intent(context, AlarmReceiver::class.java)
//with flag FLAG_NO_CREATE return null
val pendingIntent = PendingIntent.getBroadcast(context, 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.cancel(pendingIntent)
Everything works great on api 23, but on api 24 alarm do not canceling. Is it problem with intent.action? What did i miss?
Ok, I solved it with adding intent.action like this:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
var myIntent = Intent(context, AlarmReceiver::class.java)
if (SDK_INT > Build.VERSION_CODES.M) {
myIntent.action = "ADD_ALARM"
}
val pendingIntent = PendingIntent.getBroadcast(context, 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.cancel(pendingIntent)
I'm trying to set an alarm with AlarmManager, but my BroadcastReceiver never gets called. Here is my snippet.
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
//Never gets hit
}
}
context.registerReceiver(receiver, IntentFilter(LOCAL_NOTIFICATION))
val intent = Intent()
intent.action = LOCAL_NOTIFICATION
val alarmManager = context.getSystemService(ALARM_SERVICE) as? AlarmManager
val pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val calendar = Calendar.getInstance()
calendar.add(Calendar.SECOND, 10)
alarmManager?.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
I've tried registering a broadcast receiver in AndroidManifest.xml but nothing seems to be working.
I just noticed that I was calling getService() on PendingIntent instead of getBroadcast()
After changing that, it works perfectly!
In addition to the preferred answer, I set the class of the intent before it worked. See the example below:
val intent = Intent()
intent.action = LOCAL_NOTIFICATION
intent.setClass(context, MyBroadCastReceiver::class.java) //this line
before passing the intent to the pendintIntent.
hope it helps