I wrote the below code:
var alarmMgr: AlarmManager? = null
lateinit var alarmIntent: PendingIntent
class MainActivity : AppCompatActivity() {
alarmMgr = this.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(this, MyAlarm::class.java).let { intent ->
PendingIntent.getBroadcast(this, 0, intent, 0)
}
alarmMgr?.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, AlarmManager.INTERVAL_FIFTEEN_MINUTES, alarmIntent)
}
With MyAlarm class as:
class MyAlarm : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(context, "Alarm Triggered", Toast.LENGTH_SHORT).show()
}
}
My intention is to get the alert run after 15 minutes, but what is happening in real, is I'm getting the toast immediately upon the app startup, what mistake did I made, and how to fix it?
The second parameter to setExactAndAllowWhileIdle() is the time when the alarm should occur, expressed in the timebase of the first parameter.
Your first parameter is ELAPSED_REALTIME, so the second parameter needs to be SystemClock.elapsedRealtime() plus some amount, to schedule the alarm for that amount of time in the future.
Right now, you just have INTERVAL_FIFTEEN_MINUTES as the second parameter. The value of that constant happens to be 15 minutes in milliseconds. However, that will schedule the alarm to go off 15 minutes from whenever your phone last rebooted, which probably is a time in the past.
So, replace:
alarmMgr?.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, alarmIntent)
with:
alarmMgr?.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime()+AlarmManager.INTERVAL_FIFTEEN_MINUTES, alarmIntent)
Related
I have an android app where I try to set an alarm. My code inside activity:
fun setAlarm() {
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, NotificationReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
alarmManager!!.set(AlarmManager.RTC_WAKEUP, /*calculateAlarmTime()*/1, pendingIntent)
Timber.i("setAlarm executed")
}
I set this alarm, calling setAlarm method. This is my NotificationReceiver class:
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Timber.i("onReceive called");
}
}
Why I have only "setAlarm executed" in logcat, and not "onReceive called"? I set alarm to 1 millisecond and it should trigger immeditately. Why nothing happens?
Your second parameter is wrong. It isn't how long from now you want the alarm to occur, it's the Unix timestamp of when you want it to occur. So 1 would have happened back in 1970. You would need to, at minimum, go System.currentTimeMillis()+1. Although that may well cause race conditions, I wouldn't count on an alarm being set for less than a second in the future working.
You set the AlarmManager with RTC_WAKEUP, so you should supply the exact date and time. Instead you set the time to 1 ms, which is interpreted as 1ms after 1-1-1970, 00h00m00s.
If you want to use an relative time from setting the alarmManager you should get the current RTC time, add a few seconds and set the alarmManager with that time. As this method is inexact, allow a few seconds leeway.
See here for description RTC_WAKEUP
I am currently trying to make an app that sends the user a message every morning. However, my alarm triggers immediately when I open my app if the alarm's trigger time is earlier than the current time.
This is my code:
This in my onCreate:
// Get AlarmManager instance
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Intent part
val intent = Intent(this, AlarmReceiver::class.java)
intent.action = "FOO_ACTION"
intent.putExtra("KEY_FOO_STRING", "Alarm triggered!")
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, 21)
set(Calendar.MINUTE, 42)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
And my receiver just in my MainActivity:
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Is triggered when alarm goes off, i.e. receiving a system broadcast
if (intent.action == "FOO_ACTION") {
val fooString = intent.getStringExtra("KEY_FOO_STRING")
Toast.makeText(context, fooString, Toast.LENGTH_LONG).show()
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
vibrator.vibrate(200)
}
}
}
I found a solution to one of the major problems I was having in this question. I found a way to keep my alarm from triggering if the date I want it to trigger is in the past-
if (calendar.timeInMillis < System.currentTimeMillis()) { // checks if alarm time is earlier than system time
calendar.add(Calendar.DAY_OF_YEAR, 1) // goes to next day
}
I had another problem here initially, but I realized this was probably too many things to cram into a single StackOverflow question. I edited my question to just include this issue, and am leaving this code snippet here for people who might have this issue in the future.
I want to be able to set a variable alarm from the background whenever my service is run. I am using the following code:
...
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
...
Intent i = new Intent(AlarmClock.ACTION_SET_ALARM);
i.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
i.putExtra(AlarmClock.EXTRA_HOUR, 9);
i.putExtra(AlarmClock.EXTRA_MINUTES, 9);
i.putExtra(AlarmClock.EXTRA_MESSAGE, "Good Morning");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
...
I am aware that an activity cannot be started from the background. But is there any other way or a hack to be able to accomplish what I need to do here?
Looking at Schedule Repeating Alarms documentation, you could use AlarmManager with a PendingIntent as seen below.
When you start the service, you could always set up the alarm and set the alarm to trigger straight away using the current time.
When the alarm goes off, it sends out a intent to a Broadcast Reciever (which is AlarmReceiver in the case below - just make your own). You can then do whatever you want from AlarmReceiver.
It is probably worth running through the full documentation as I found it super useful. It will only take maximum 15 minutes, is really clear and it should meet your requirement.
private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
PendingIntent.getBroadcast(context, 0, intent, 0)
}
// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, 8)
set(Calendar.MINUTE, 30)
}
// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
1000 * 60 * 20,
alarmIntent
)
I am trying to schedule alarm which will perform some task after every hour. For testing purpose, I have set the alarm to trigger after every 5 seconds but it triggers only once.
private fun register30MinSchedule() {
val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(this, AlarmReceiver::class.java).let { intent ->
PendingIntent.getBroadcast(applicationContext, LocationTrack_Service_ID, intent, 0)
}
alarmMgr?.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(),
System.currentTimeMillis() + 5000 ,
alarmIntent
)
}
AlarmReceiver is called only once. Can anyone please point me the mistake I am making?
Regards,
I was able to figure out the issue. All methods of AlarmManager requires the precise time. In my scenario, i was using the variable time for 2nd and 3rd parameter triggerTimeMillis i.e. System.currentTimeMillis() + 5000. So, the correct way of setting repeating alarm is:
val initialTime = System.currentTimeMillis()
val repeatingInterval = initialTime + 5000
alarmMgr?.setInexactRepeating(AlarmManager.RTC_WAKEUP, initialTime, repeatingInterval,alarmIntent)
This is trigger after every repeating interval. Hope this helps.
I got a problem with the AlarmManager. When the alarm is set, if the alarm's hour has already passed the intent is started which is great. But sometimes there is a very long time (from 30 secondes to 3 minutes) before the intent is started. If anyone knows why, I'm curious to understand.
Here is my code :
public static void setAlarm()
{
Intent intent = new Intent(Application.Context, typeof(AlarmReceiver));
intent.SetAction("ExchangeGo");
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, intent, PendingIntentFlags.CancelCurrent);
Calendar dayCalendar = Calendar.GetInstance(Java.Util.TimeZone.Default);
dayCalendar.Set(CalendarField.HourOfDay, 8);
dayCalendar.Set(CalendarField.Minute, 30);
dayCalendar.Set(CalendarField.Second, 0);
dayCalendar.Set(CalendarField.Millisecond, 0);
AlarmManager alarm = Application.Context.GetSystemService(Context.AlarmService).JavaCast<AlarmManager>();
alarm.Cancel(pendingIntent);
alarm.SetRepeating(AlarmType.RtcWakeup, dayCalendar.TimeInMillis, AlarmManager.IntervalDay, pendingIntent);
}
And here the intent :
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
private String SOMEACTION = "ExchangeGo";
public override void OnReceive(Context context, Intent intent)
{
String action = intent.Action;
if (SOMEACTION.Equals(action))
{
Intent intentService = new Intent(context, typeof(ExchangeService2));
context.StartService(intentService);
}
}
}
There is no problem with manifest cause it works, just a bit too long sometimes. And the problem is not from my second intent because I put a breakPoint just before and the waiting time is before the break point.
Anyone ?
Thanks for reading me.
As setRepeating() doesn't guarantee that it will happen at precise time.
That's why you are getting delay of 30 secondes to 3 minutes.
Replace setRepeating() with setExact() refer documentation from Here
manager.setExact(AlarmManager.RTC, startTime.getTimeInMillis(), operation);
To repeat this what you can do is, to schedule this alarm again after executing your current event. So when your 1st intent gets executed schedule alarm for 2nd event using setExact() only. This will guarantee the time accuracy you are expecting