Is my alarmManager code, capable to send broadcast? - android

I'm trying to create an alarm Manager that sends notification every 24 hours at specific time consulted other Stackoverflow code. I tried this code below but onReceive() never gets executed. What i'm doing wrong?
private var HOUR_TO_SHOW_PUSH = 21
private var MINUTE_TO_SHOW_PUSH = 0
private val REQUEST_CODE = 100
private lateinit var alarmManager: AlarmManager
private lateinit var pendingIntent: PendingIntent
class MainActivity : AppCompatActivity() {
...
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val calendar = GregorianCalendar.getInstance().apply {
if (get(Calendar.HOUR_OF_DAY) >= HOUR_TO_SHOW_PUSH) {
add(Calendar.DAY_OF_MONTH, 1)
}
set(Calendar.HOUR_OF_DAY, HOUR_TO_SHOW_PUSH)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
AlertReceiver
class AlertReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "Alarm", Toast.LENGTH_LONG).show()
println("Alarm")
Log.e("Alarm","Alarm Triggered")
}
Manifest
<receiver
android:name=".AlertReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="MyBroadcastReceiverAction"/>
</intent-filter
</receiver>

Normally you would register your receiver in the AndroidManifest like this:
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
https://developer.android.com/guide/components/broadcasts

it depends on the battery optimization applied to the app by the device, it varies from a device manufacturer to other
Normally you will find it in Settings > Apps > "your app name" > Battery Saver Set it to No Restrictions

Related

Reschedule notifications

I have the following structure:
Main Class
private fun scheduleNotification()
{
val intent = Intent(applicationContext, Notification::class.java)
val title = binding.titleET.text.toString()
val message = binding.messageET.text.toString()
intent.putExtra(titleExtra, title)
intent.putExtra(messageExtra, message)
val pendingIntent = PendingIntent.getBroadcast(
applicationContext,
1 + (Random.nextInt(1, 100)),
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val time = getTime()
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
time,
pendingIntent
)
showAlert(time, title, message)
}
Notification Class
class Notification : BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent)
{
val notification = NotificationCompat.Builder(context, channelID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(intent.getStringExtra(titleExtra))
.setContentText(intent.getStringExtra(messageExtra))
.build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.notify(notificationID, notification)
}
}
Android Manifest
<receiver
android:name=".Notification"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
With this I am able to SCHEDULE a NOTIFICATION with DATE and TIME. But when the device is restarted all scheduled notifications are erased.
I tried to solve it by adding:
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Indeed it "works" but I get an empty notification and outside the scheduled time and I understand that it is an Android behavior, but is there any solution?

Android notification not comes

I have an Android app where i schedule some notifications at specific times every day with alarmManager and receiver like this
fun addNot() {
val alarmMgr = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager?
val intent = Intent(this.context!!, MyAlarmReceiverTest::class.java)
val pendingIntent = PendingIntent.getBroadcast(this.context!!, 0, intent, 0)
val current = Calendar.getInstance()
val time = createDate("13:58:00")
if(time < current) {
time.add(Calendar.DATE,1)
}
alarmMgr!!.setRepeating(AlarmManager.RTC_WAKEUP, time.timeInMillis ,AlarmManager.INTERVAL_DAY,pendingIntent)
}
fun createDate(str: String):Calendar {
val separated = str.split(":").toTypedArray()
val datetimeToAlarm = Calendar.getInstance()
datetimeToAlarm.set(Calendar.HOUR_OF_DAY,separated[0].toInt())
datetimeToAlarm.set(Calendar.MINUTE,separated[1].toInt())
datetimeToAlarm.set(Calendar.SECOND,separated[2].toInt())
return datetimeToAlarm
}
With this receiver
class MyAlarmReceiverTest : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val notification = Notification.Builder(MyApplication.appContext)
.setContentTitle("title goes here")
.setContentText("this is content")
.setSmallIcon(R.mipmap.app_logo_final)
.setLargeIcon(
BitmapFactory.decodeResource(
MyApplication.appContext.getResources(),
R.mipmap.app_logo_final
)
)
.setContentIntent(null)
.build()
notification.sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + MyApplication.appContext.getPackageName() + "/raw/a")
var notificationManager = MyApplication.appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager?.notify(45545454, notification)
}
}
And the manifest
<receiver
android:name=".MyAlarmReceiverTest"
android:enabled="true"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.simplemobiletools.applauncher.sendbroadcast" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
Questions :
1- the above notification sometimes triggers and sometimes not , why ?
2- should i use job or workmanager for this ?
App support is from api 21 if this matters

Notification in Kotlin repeating every day at the same time

None of the other Stackoverflow code I found works. All is either Java, or I'm too dumb to make it work.
How to fire notification at the same time every day? So basic thing and I can't find anything for Kotlin.
Use this code to schedule showing notification each day at 22:00 (or any other hour in HOUR_TO_SHOW_PUSH):
private val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager
private val alarmPendingIntent by lazy {
val intent = Intent(context, AlarmReceiver::class.java)
PendingIntent.getBroadcast(context, 0, intent, 0)
}
private const val HOUR_TO_SHOW_PUSH = 22
fun schedulePushNotifications() {
val calendar = GregorianCalendar.getInstance().apply {
if (get(Calendar.HOUR_OF_DAY) >= HOUR_TO_SHOW_PUSH) {
add(Calendar.DAY_OF_MONTH, 1)
}
set(Calendar.HOUR_OF_DAY, HOUR_TO_SHOW_PUSH)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
alarmPendingIntent
)
}
It will trigger BroadcastReceiver called AlarmReceiver, so you'll have to implement it too:
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
showPushNotification() // implement showing notification in this function
}
}
Don't forget to register it in your AndroidManifest.xml:
<receiver android:name="com.your-package-name.AlarmReceiver" android:enabled="true"/>
Also note that to schedule these notifications you have to call schedulePushNotifications(), meaning that the app has to be launched at least once after each reboot. If you want your notifications to be shown after a reboot without launching your app, consider implementing BootReceiver that will be triggered immediately after reboot:
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == "android.intent.action.BOOT_COMPLETED") {
schedulePushNotifications()
}
}
}
Don't forget to register it in AndroidManifest.xml too:
<receiver android:name="com.your-package-name.BootReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>

How to use Android AlarmManager in Fragment in Kotlin?

I can't seem to get the AlarmManager to work inside a Fragment. My receiver's onReceive() method never gets executed. I assume that I might use context in a wrong way but then again I also couldn't get it to work inside an Activity. I've also registered the receiver in my manifest.
MyFragment.kt
class MyFragment : Fragment() {
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var alarmMgr: AlarmManager? = null
lateinit var alarmIntent: PendingIntent
alarmMgr = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, Receiver::class.java).let { intent ->
PendingIntent.getService(context, 0, intent, 0)
}
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
// The EditText includes a time in 24-hour format (e.g. 12:34)
set(Calendar.HOUR_OF_DAY, editText.text.toString().substringBefore(":").toInt())
set(Calendar.MINUTE, editText.text.toString().substringAfter(":").toInt())
}
Log.d("ALARM", "CREATED")
alarmMgr?.set(
AlarmManager.RTC,
calendar.timeInMillis,
alarmIntent
)
}
}
Receiver.kt
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("ALARM", "RECEIVED")
}
}
AndroidManifest.xml
<application
...
<receiver android:name="com.example.name.Receiver" />
</application>
First things first:
AndroidManifest.xml
<receiver
android:name="com.example.name.Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
Then, in this case in your Fragment, however, I suggest doing this somewhere else:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, Receiver::class.java)
// Used for filtering inside Broadcast receiver
intent.action = "MyBroadcastReceiverAction"
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
// In this particular example we are going to set it to trigger after 30 seconds.
// You can work with time later when you know this works for sure.
val msUntilTriggerHour: Long = 30000
val alarmTimeAtUTC: Long = System.currentTimeMillis() + msUntilTriggerHour
// Depending on the version of Android use different function for setting an
// Alarm.
// setAlarmClock() - used for everything lower than Android M
// setExactAndAllowWhileIdle() - used for everything on Android M and higher
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(alarmTimeAtUTC, pendingIntent),
pendingIntent
)
} else {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
alarmTimeAtUTC,
pendingIntent
)
}
In your Broadcast Receiver, we then do the following:
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// We use this to make sure that we execute code, only when this exact
// Alarm triggered our Broadcast receiver
if (intent?.action == "MyBroadcastReceiverAction") {
Log.d("ALARM", "RECEIVED")
}
}
}

alarmmanger sometimes works or not when the app is killed in android

I want to notify at midnight. So I used alrammanager. the alrammanager is working well when it is in foreground or background. But the problem is occured when my app is killed. The alrammanager sometimes works or not. I don't understand this weird happening...
For example, when the notification occurs every three minutes, the app works well even if it is in the foreground or background. But when the app kiiled, the notification is occured or not even though there is no change in code. Please help me...
MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val picker = findViewById(R.id.timePicker) as TimePicker
picker.setIs24HourView(true)
val nextNotifyTime: Calendar = GregorianCalendar()
val nextDate: Date = nextNotifyTime.getTime()
val currentTime: Date = nextNotifyTime.getTime()
val HourFormat = SimpleDateFormat("kk", Locale.getDefault())
val MinuteFormat = SimpleDateFormat("mm", Locale.getDefault())
val pre_hour: Int = HourFormat.format(currentTime).toInt()
val pre_minute: Int = MinuteFormat.format(currentTime).toInt()
if (Build.VERSION.SDK_INT >= 23) {
picker.hour = pre_hour
picker.minute = pre_minute
} else {
picker.currentHour = pre_hour
picker.currentMinute = pre_minute
}
val button: Button = findViewById(R.id.button) as Button
button.setOnClickListener {
val hour: Int
val hour_24: Int
val minute: Int
if (Build.VERSION.SDK_INT >= 23) {
hour_24 = picker.hour
minute = picker.minute
} else {
hour_24 = picker.currentHour
minute = picker.currentMinute
}
if (hour_24 > 12) {
hour = hour_24
}
else {
hour = hour_24- 12
}
val calendar: Calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
if(calendar.after(Calendar.getInstance())) {
//calendar.add(Calendar.DATE, 1)
}
diaryNotification(calendar)
}
}
fun diaryNotification(calendar: Calendar) {
val pm = this.packageManager
val receiver = ComponentName(this, DeviceBootReceiver::class.java)
val alarmIntent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 60*1000, pendingIntent)
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)
}
AlarmReceiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = (Intent.FLAG_ACTIVITY_CLEAR_TOP
or Intent.FLAG_ACTIVITY_SINGLE_TOP)
var notification = CustomNotification.getNotificationBuilderInstance(context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelName = "channel name"
val importance = NotificationManager.IMPORTANCE_LOW
val channel = NotificationChannel(CHANNEL_ID, channelName, importance)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(NOTIFICATION_ID, notification.build())
}
}
DeviceBootReceiver
class DeviceBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Objects.equals(intent.action, "android.intent.action.BOOT_COMPLETED")) {
val alarmIntent = Intent(context, AlarmReceiver::class.java)
val pendingIntent =
PendingIntent.getBroadcast(context, 0, alarmIntent, 0)
val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val millis = Calendar.getInstance().timeInMillis
manager.setRepeating(
AlarmManager.RTC_WAKEUP, millis,
60*1000, pendingIntent
)
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.haii.alarmdemo">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:name=".GlobalApplication"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".DeviceBootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
</application>
</manifest>
go to settings -> app -> YOUR APK NAME -> enable AUTOSTART (or something similar)
now even if your app is killed you will receive your notification
Also I suggest you to take a look at this link: LINK
Hope this "solution" can help you, cya ;)

Categories

Resources