Skip to content

Instantly share code, notes, and snippets.

@GibsonRuitiari
Created February 12, 2024 06:00
Show Gist options
  • Save GibsonRuitiari/5f0656351624b0353b891fb09da16dcb to your computer and use it in GitHub Desktop.
Save GibsonRuitiari/5f0656351624b0353b891fb09da16dcb to your computer and use it in GitHub Desktop.
Shows how to use alarm manager
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
requestNotificationPermission()
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
/* if you use AlarmManager.setRepeating(timeInMillis, timeInterval), note that the system will always delay your
alarm by 5 seconds and the interval must be at least 60 seconds+. However there's virtually no difference between
setRepeating and setInexactRepeating other than the exactness nature. Behind the scenes,
setInexactRepeating uses setRepeating. Though, it is reccomended to use setInexactRepeating because its
implementation uses less resources*/
val alarmTimeAtUTC = System.currentTimeMillis() + 10 * 4_000L
val timeInterval = 10_000L * 6
// schedule an arlam at 23:26 basically 11:26pm, you can also include day here
val calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY,23)
set(Calendar.MINUTE,26)
}
val intent_ = Intent(this,AlarmReceiver::class.java).apply {
action="RECEIVER.ACTION"
putExtra("MSG","Alarm called Yippy!")
putExtra("Time",calendar.timeInMillis)
}
// flag can be mutable if you want to get the alarm count
val pendingIntent = PendingIntent.getBroadcast(this,0,intent_,PendingIntent.FLAG_MUTABLE)
/* sets a repeating alarm. The inexactness nature of this api is caused by the fact that the alarm
may go off within a window of the AlarmManager.Interval. For instance, if the alarm is set at 8:30am with an
repeating interval of 15 minutes so that the first alarm goes off at 8:30am then the second one after 15 minutes and so on
, the second & subsequent alarms might go off either immediately after 15 minutes window period or
the 15 minutes window period + some minutes/seconds. In essence, the variance/divergence is around 1-5 minutes at most
so your alarm will be 1-5 minutes late in most cases. This works even when the device is in doze mode + idle state*/
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
pendingIntent)
/* sets a non-repeating alarm at a particular time. This is similar to setInexactRepeating only that it is a one-shot alarm
and can be used whenever you want to the alarm to go off even when the device is in idle mode. Note that,
the usage of RTC depends on the user's wall clock, so if your alarm is local sensitive i.e, must go off at 8:30am regardless,
of the locality (GMT+3, GMT, UTC etc), you might want to handle that to prevent inconcitensies*/
// alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
// calendar.timeInMillis, pendingIntent)
/* to cancel the alarm just do alarmManager.cancel(pendingIntent) */
}
}
/* a static receiver that is defined in the manifest as so
<receiver android:name=".AlarmReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="RECEIVER.ACTION"/>
</intent-filter>
</receiver>
*/
class AlarmReceiver:BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
if (intent.action=="RECEIVER.ACTION"){
// fire the notification first
context?.let {
fireNotification(it)
}
// do something with the extra data?
val msg=intent.getStringExtra("MSG")
val time = intent.getLongExtra("Time",0L)
println("message received---> ${msg}")
println("fired---> $time")
}
}
}
// just creates a notification channel
private fun createNotificationChannel(notificationManager:NotificationManager) {
val channel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel(
CHANNEL_ID,
"Important Notification Channel",
NotificationManager.IMPORTANCE_HIGH,
).apply {
description = "This notification contains important announcement, etc."
}
} else {
TODO("VERSION.SDK_INT < O")
}
notificationManager.createNotificationChannel(channel)
}
companion object {
const val CHANNEL_ID = "dummy_channel"
}
fun fireNotification(context:Context){
val notificationManager: NotificationManager by lazy {
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
createNotificationChannel(notificationManager)
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Congratulations! 🎉🎉🎉")
.setContentText("You have post a notification from alarm manager")
.setPriority(NotificationCompat.PRIORITY_HIGH)
if (context.checkNotificationsPermission()){
with(NotificationManagerCompat.from(context)) {
notify(1, builder.build())
}
}else {
context.requestNotificationPermission()
}
}
}
// can be made more robust
fun Context.requestNotificationPermission(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!checkNotificationsPermission())
ActivityCompat.requestPermissions(this as Activity, arrayOf(Manifest.permission.POST_NOTIFICATIONS),100)
}
}
fun Context.checkNotificationsPermission():Boolean{
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ActivityCompat.checkSelfPermission(this,Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
} else {
true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment