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)
}
Related
guys, am currently building an application with compose, and i need to fire a notification at a given time to users, so whenever users click on a button on my list item, i want to get the time of that item and set an alarm pending intent for it, and fire it when the times reaches,
So am working with android alarm manager, but whenever i close my application the alarm doesn't broadcast my notification, but if i leave it open, it fires the alarm notification successfully, i dont know what i am doing wrong cause from what i know my application isnt responsible for firing the alarm, cause the android system does this for us,
so here is my code that i have tried with Alarm Manager
Funtion to Schedule Notification
`
#RequiresApi(api = Build.VERSION_CODES.M)
fun scheduleNotification(calendar: Calendar, context: Context, taskInfo:FixtureAlarm) {
val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager
// adding intent and pending intent to go to AlarmReceiver Class in future
val intent = Intent(context, FixtureNotificationReceiver::class.java)
intent.putExtra("fixture", taskInfo)
val pendingIntent = PendingIntent.getBroadcast(context, taskInfo.id, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
// when using setAlarmClock() it displays a notification until alarm rings and when pressed it takes us to mainActivity
val mainActivityIntent = Intent(context, MainActivity::class.java)
val basicPendingIntent = PendingIntent.getActivity(context, taskInfo.id, mainActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
// creating clockInfo instance
val clockInfo = AlarmManager.AlarmClockInfo(Calendar.getInstance().also { it.add(Calendar.SECOND,10) }.timeInMillis, basicPendingIntent)
// setting the alarm
alarmManager.setExact(AlarmManager.RTC_WAKEUP,Calendar.getInstance().also { it.add(Calendar.SECOND,10) }.timeInMillis, pendingIntent)
Toast.makeText(context, "Scheduled ", Toast.LENGTH_LONG).show()
}
`
My BroadCast Receiver
class FixtureNotificationReceiver() : BroadcastReceiver() {
private var notificationManager: NotificationManagerCompat? = null
override fun onReceive(p0: Context?, p1: Intent?) {
val taskInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
p1?.getParcelableExtra("fixture",FixtureAlarm::class.java)
} else {
p1?.getParcelableExtra("fixture") as? FixtureAlarm
}
Log.d("SVTRECIEVED","ALARTM RECIEVED ${taskInfo?.homeTeam.toString()}")
// tapResultIntent gets executed when user taps the notification
if(taskInfo!=null) {
val tapResultIntent = Intent(p0, MainActivity::class.java)
tapResultIntent.putExtra("fixture", taskInfo)
tapResultIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
val pendingIntent: PendingIntent =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getActivity(p0, 0, tapResultIntent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
} else {
getActivity(p0, 0, tapResultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
val notification = p0?.let {
NotificationCompat.Builder(it, FIXTURESCHANNEL_ID)
.setContentTitle("Fixture Reminder")
.setContentText("${taskInfo?.awayTeam} VS ${taskInfo.homeTeam} is about to start, open SportVectru and get live updates ")
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setDefaults(NotificationCompat.DEFAULT_SOUND)
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setPriority(NotificationCompat.PRIORITY_HIGH).build()}
val notificationtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
val r = RingtoneManager.getRingtone(p0, notificationtone)
r.play()
notificationManager = p0?.let { NotificationManagerCompat.from(it) }
notification?.let { taskInfo.let { it1 -> if (ActivityCompat.checkSelfPermission(
p0,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
Toast.makeText(p0, "Permission for showing notification is disabled", Toast.LENGTH_SHORT).show()
return
}
notificationManager?.notify(it1.id, it)
}
}
}
}
}
Added it to my Manifest
`
<receiver android:name=".dormain.notifications.pendingNotification.FixtureNotificationReceiver"
android:enabled="true"
/>
`
I even granted Permission
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
But it still doesnt work, notification is never shown when application is closed.
I have also disabled battery Optimization for my application, doesnt work.
I am showing a custom notification (FCM). custom notification has two buttons approve and deny.
I have managed to create pending intent and a broadcast receiver and now I know in onReceive when the button is clicked.
How can i differentiate between button clicks in onReceive, I tried to pass extras on the intent, but intent.getStringExtra("clicked") gave me null value.
what is the right way of knowing which button is clicked approve , deny
This is the code I tried.
Thanks for your help in advance
R
override fun onMessageReceived(message: RemoteMessage) {
Log.d("FCMService", "onMessageReceived START ${isAppOnForeground()}")
if(!isAppOnForeground()) {
val notificationLayout = RemoteViews(
packageName,
R.layout.plugin_requires_approval_notification_small
)
val notificationLayoutExpanded = RemoteViews(
packageName,
R.layout.plugin_requires_approval_notification_large
)
val title = message.data[MSG_TITLE]
val subTitle = message.data[MSG_SUB_TITLE]
notificationLayout.setTextViewText(R.id.tvTitle, title)
notificationLayout.setTextViewText(R.id.tvSubTitle, subTitle)
notificationLayoutExpanded.setTextViewText(R.id.tvTitle, title)
notificationLayoutExpanded.setTextViewText(R.id.tvSubTitle, subTitle)
// Apply the layouts to the notification
val customNotification = NotificationCompat.Builder(
this,
CarInfoProcessingService.NOTIFICATION_CHANNEL_ID
)
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationLayout)
.setCustomBigContentView(notificationLayoutExpanded)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
val switchIntent = Intent(this, SwitchButtonListener::class.java)
switchIntent.putExtra("clicked", "btnApprove")
val pendingSwitchIntent = PendingIntent.getBroadcast(
this, 0,
switchIntent, 0
)
//TWO BUTTONS WITH SAME PENDING SWITCH INTENT
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btnApprove, pendingSwitchIntent)
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btnDeny, pendingSwitchIntent)
val notificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, customNotification)
}
Log.d("FCMService", "onMessageReceived END")
}
class SwitchButtonListener : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("fcmService", "onReceive ${intent.getStringExtra("clicked")}")
}
}
Manifest
<receiver android:name=".messaging.FcmService$SwitchButtonListener" android:exported="true">
<intent-filter>
<action android:name="Button_Clicked"/>
</intent-filter>
</receiver>
EDIT : Updated code that might help others
override fun onMessageReceived(message: RemoteMessage) {
Log.d("FCMService", "onMessageReceived START ${isAppOnForeground()}")
if(!isAppOnForeground()) {
val notificationLayout = RemoteViews(
packageName,
R.layout.plugin_requires_approval_notification_small
)
val notificationLayoutExpanded = RemoteViews(
packageName,
R.layout.plugin_requires_approval_notification_large
)
val title = message.data[MSG_TITLE]
val subTitle = message.data[MSG_SUB_TITLE]
notificationLayout.setTextViewText(R.id.tvTitle, title)
notificationLayout.setTextViewText(R.id.tvSubTitle, subTitle)
notificationLayoutExpanded.setTextViewText(R.id.tvTitle, title)
notificationLayoutExpanded.setTextViewText(R.id.tvSubTitle, subTitle)
// Apply the layouts to the notification
val customNotification = NotificationCompat.Builder(
this,
CarInfoProcessingService.NOTIFICATION_CHANNEL_ID
)
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationLayout)
.setCustomBigContentView(notificationLayoutExpanded)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
val approveIntent = Intent(this, CustomNotificationListener::class.java)
approveIntent.putExtra("onClickListener", "approve")
val pendingApproveIntent = PendingIntent.getBroadcast(
this,
0,
approveIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btnApprove, pendingApproveIntent)
val denyIntent = Intent(this, CustomNotificationListener::class.java)
denyIntent.putExtra("onClickListener", "deny")
val pendingDenyIntent = PendingIntent.getBroadcast(
this,
1,
denyIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
notificationLayoutExpanded.setOnClickPendingIntent(R.id.btnDeny, pendingDenyIntent)
val notificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, customNotification)
}
Log.d("FCMService", "onMessageReceived END")
}
class CustomNotificationListener : BroadcastReceiver() {
#Inject
lateinit var chargeSessionRepo: ChargeSessionRepository
private var lastChargeStatus: ChargeStatusDTO? = null
override fun onReceive(context: Context, intent: Intent) {
Log.d("fcmService", "onReceive ${intent.getStringExtra("onClickListener")}")
when(intent.getStringExtra("onClickListener")) {
"approve" -> {
}
"deny" -> {
}
}
}
}
You need to use two distinct, up-to-date PendingIntent objects, wrapped around different Intent objects (e.g., ones with differing extras).
For "distinct", you need the IDs of the PendingIntent objects to be different. The ID is the second parameter to the PendingIntent.getBroadcast() call.
For "up-to-date", you need to update any existing PendingIntent that your code might have created previously. For that, pass PendingIntent.FLAG_UPDATE_CURRENT as the fourth parameter to the PendingIntent.getBroadcast() call.
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 trying to make a notification that get triggered after a certain amount of time has passed. In an attempt to achieve this I have this AlarmReceiver class that inherits from BroadCast receiver and works on devices running up to about API 23. It doesn't work on my emulator currently running API 27. Any clue what I'm doing wrong?
class AlarmReceiver : BroadcastReceiver() {
companion object {
val PRIMARY_CHANNEL = "dj"
}
override fun onReceive(context: Context, intent: Intent) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationIntent = Intent(context, NotificationActivity::class.java)
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(NotificationActivity::class.java)
stackBuilder.addNextIntent(notificationIntent)
val pendingIntent = stackBuilder.getPendingIntent(100, PendingIntent.FLAG_UPDATE_CURRENT)
if (android.os.Build.VERSION_CODES.O <= android.os.Build.VERSION.SDK_INT){
//I create the notification channel on the next line, but it doesn't seem to work
val notificationChannel = NotificationChannel(PRIMARY_CHANNEL,
"DailyJokes", NotificationManager.IMPORTANCE_DEFAULT)
notificationChannel.lightColor = Color.GREEN
notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
notificationManager.createNotificationChannel(notificationChannel)
val notification = Notification.Builder(context, PRIMARY_CHANNEL)
.setContentIntent(pendingIntent)
.setChannelId("dj")
.setContentText("KDW")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("CCC")
.build()
notificationManager.notify(1,notification)
} else {
var builder = NotificationCompat.Builder(context, "dj")
val sound = Uri.parse("android.resource://" + context.packageName + "/" + "raw/drumroll")
builder = builder
.setSmallIcon(R.mipmap.ic_launcher_round)
.setColor(Color.BLUE)
.setContentTitle("Content Title")
.setTicker("TICKER Text")
.setContentText("KDW setContentText")
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setChannelId("dj")
.setSound(sound)
notificationManager.notify(1, builder!!.build())
}
}
}
Here's the code that triggers the notification, anything off here?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_notification)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val notificationIntent = Intent("android.media.action.DISPLAY_NOTIFICATION")
notificationIntent.addCategory("android.intent.category.DEFAULT")
val broadcast = getBroadcast(this, 100, notificationIntent, FLAG_UPDATE_CURRENT)
val cal = Calendar.getInstance()
cal.add(Calendar.SECOND, 5)
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.timeInMillis, broadcast)
}
}
I also have a receiver in my Manifest:
<receiver android:name=".AlarmReceiver">
<intent-filter>
<action android:name="android.media.action.DISPLAY_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Even with all this the bug still lurks. I'm new to Kotlin, today makes a week since I started. My swift experience prepared me well but I just can't seem to get a hold on notifications :/
From what I can tell from your code , you need to register the receiver in either the Manifest or a context.
https://developer.android.com/guide/components/broadcasts.html
is your channel even created ?
your comparison is in the wrong direction ->
android.os.Build.VERSION_CODES.O <= android.os.Build.VERSION.SDK_INT it should be >= instead
and only the channel creation needs to be guarded against O, not the notification creation.