How to check if alarm is set - android

I'm trying to check if my alarm is active or not. The alarmIsSet method will return false before the alarm is set, true when the alarm is set. So far so good, however, after the alarm i canceled alarmIsSet will continue to return true until I reboot the device.
How do I fix this?
public class Alarm extends Activity {
private Intent intent = new Intent("PROPOSE_A_TOAST");
private void alarm (boolean activate) {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);
if(activate == true) {
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = 3000;
long triggerTime = SystemClock.elapsedRealtime();
am.setRepeating(type, triggerTime, interval, pi);
} else {
am.cancel(pi);
}
}
private boolean alarmIsSet() {
return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_NO_CREATE) != null;
}
}

You just have to add
pi.cancel();
after
am.cancel(pi);

After having some headaches with this stuff myself, I found out that if I somehow had created a pending intent while testing stuff, that it actually was not cleared between tests. Even killing the app didn't do it. The intent still stayed in the system and kept returning true when checking for it. I actually had to write some code to kill it before it tested right.

Easiest way is to check the values of the (date and) time in the alarm variable, if it is not the same value as when an alarm has not been set (for you to check once what that is) then it would indicate the alarm is active and at the time of the check in the program it is either a time that has passed and the alarm has sounded or it is a time that is yet to arrive and the alarm has not yet sounded or gone off. Note that the rules may permit only one alarm activation per device session before a reboot or power off or every 12 or 24 hours and that could be why the status is not cleared.

Related

Alarm intent entering rapid infinite loop

I'm trying to code a block of code that has to wake up a few times a day and notify a server. I'm trying to use an alarm intent and a broadcast receiver but the receiver is being rapidly triggered infinitely and I can't seem to stop this.
All of my code sits in one file. The process flow is simple.
Wake up on boot, check if we should communicate, attempt to communicate else set up one of two waiting conditions, activate alarm.
Wake up on alarm, attempt to communicate, re-activate alarm if necessary, otherwise kill it.
When I build and deploy this apk on my device the following process flow happens:
reboot
receiver receives boot intent just fine
alarm gets scheduled
alarm intent gets triggered after 80 seconds as intended
then after the next 80 seconds,
then log-cat shows the broadcast receiver being triggered very rapidly. Several times a second as if its being spammed.
I am completely baffled at why its behaving like this
private PendingIntent pendingIntent;
/**
* Receive a signal, in our case, the device has booted up
* #param context The Context in which the receiver is running.
* #param intent The Intent being received.
*/
#SuppressLint("UnsafeProtectedBroadcastReceiver")
#Override
public void onReceive(Context context, Intent intent) {
Log.d("autostart", "broadcast received");
if(intent.getAction()==null)return;
Intent alarmIntent = new Intent(context, autostart.class);
alarmIntent.setAction("device.activation.alarm");
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);//cancel flag seems to be ignored
cancel(context);//cancel command seems to be ignored
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
// Set the alarm here.
Log.d("autostart","We have booted");
RegisterActivation registerActivation = new RegisterActivation(context);
if(registerActivation.AlreadyActivated())
return;//no need
if(registerActivation.ActivationPending()){
//perform regular activation
return;
}
if(registerActivation.canComplete()){
boolean success = registerActivation.sendActivation();//talk to server
if(success) {
registerActivation.markCompleted();
cancel(context);
}
else {
registerActivation.markFileWaiting();
startPending(context);
}
return;
}
if(registerActivation.shouldWait()){//if can complete fails, then shouldWait will immediately return true
Log.d("autostart", "waiting");
registerActivation.markFileSimWait();
startWait(context);
return;
}
}
if(intent.getAction().equals("device.activation.alarm")){
Log.d("autostart","alarm triggered");
cancel(context);
RegisterActivation registerActivation = new RegisterActivation(context);
if(registerActivation.AlreadyActivated()){//for now always false
cancel(context);
return;
}
if(registerActivation.ActivationPending()){//for now always false
//same as before
return;
}
if(registerActivation.canComplete()){//glitch happens here
if(registerActivation.sendActivation()){
registerActivation.markCompleted();
cancel(context);
}else{
registerActivation.markFileWaiting();
startPending(context);//this immediatly triggers the broadcast recieve
}
return;
}
if(registerActivation.shouldWait()){
registerActivation.markFileSimWait();
startWait(context);
}
}
}
public void startPending(Context context) {
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int interval = 80000;//will later become 4 hours
manager.set(AlarmManager.RTC_WAKEUP,interval,pendingIntent);
Log.d("autostart", "alarm activated");
}
public void startWait(Context context) {//same function but different time interval
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int interval = 90000;// will later become 12 hours
manager.set(AlarmManager.RTC_WAKEUP, interval, pendingIntent);
}
public void cancel(Context context) {
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
}
thank you to Mike M.
https://stackoverflow.com/users/2850651/mike-m
I'd mark your comment as the answer but you only commented
I went from
manager.set(AlarmManager.RTC_WAKEUP,interval,pendingIntent);
to:
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+interval, interval, pendingIntent);
I had to add the interval to the intervalMillis paramater.
And as tested, the manager.set(...) function is really not responding all too well to what I want it to do so I just have to trigger a cancel at the start.
Thanks again Mike :)

How is this resetting the alarm?

I am have been reading over this tutorial for creating repeating apps:
http://rdyonline.net/android-bytes-alarms/
I have followed the instructions and it is working beautifully. However I don't like using something if I don't understand how it works.
Alarm manager is using an version >= 19 so instead of alarm repeating (exact) it requires a one off alarm that is reset on exiting the intent.
Now as I said it is working, Every 15 minutes it is going off (in my version). I can see that they are bundling data with the intent, but I really have no understanding what is re-triggering the single shot alarm.
This is their code:
Repeating alarms
If you’re targeting any Android version before API 19 (KitKat), or,
you don’t need them to be exact then repeating alarms are nice and
easy. All you need in this case is to use the setRepeating call.
In some cases, it will be important that you set a repeating alarm
that is accurate, I’ll go in to a little more detail on how to handle
this.
The trick here is to make sure you schedule the next alarm once the
previous alarm goes off. You’ll have to check whether the alarm you
have set is intended to be repeated and also make sure the platform
you’re running on is above API 19
#Override
public void onReceive(android.content.Context context,
android.content.Intent intent) {
WrappedAlarmManager am = new WrappedAlarmManager(context);
Bundle extras = intent.getExtras();
if (am.isSingleAlarm(extras)) {
Toast.makeText(context, "Single alarm", Toast.LENGTH_SHORT).show();
} else if (am.isRepeatAlarm(extras)) {
Toast.makeText(context, "Repeat alarm", Toast.LENGTH_SHORT).show();
if (android.os.Build.VERSION.SDK_INT >= 19) {
am.scheduleRepeatingAlarm(context);
}
}
}
A quick check to see if it’s a repeating alarm and then the repeating
alarm is scheduled again. Below are the two pertinent methods to deal
with this logic:
public boolean isRepeatAlarm(Bundle extras) {
return extras.containsKey(KEY_REPEAT) && extras.getBoolean(KEY_REPEAT);
}
public void scheduleRepeatingAlarm(Context context) {
Intent intent = new Intent(context, NotificationReceiver.class);
Bundle extras = new Bundle();
extras.putBoolean(KEY_REPEAT, true);
intent.putExtras(extras);
PendingIntent pIntent = PendingIntent.getBroadcast(context,
REPEAT_ALARM_ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar futureDate = Calendar.getInstance();
futureDate.add(Calendar.SECOND, (int) (INTERVAL_SEVEN_SECONDS / 1000));
if (android.os.Build.VERSION.SDK_INT >= 19) {
setSingleExactAlarm(futureDate.getTime().getTime(), pIntent);
} else {
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, futureDate
.getTime().getTime(), INTERVAL_SEVEN_SECONDS, pIntent);
}
}
Thanks for your help
To schedule a repeating alarm in SDK versions >= 19, when alarm broadcast is received , the boolean value KEY_REPEAT is checked and if it is true then a single exact alarm is scheduled for INTERVAL_SEVEN_SECONDS / 1000 seconds later.
After INTERVAL_SEVEN_SECONDS / 1000 seconds later the broadcast is again received and next alram is set.
This receiving broadcast and scheduling next alarm cycle repeats continuously.

unit test: check if alarm was cancelled

I am writing unit tests for my app and i want to test, if the alarm is properly cancelled, but i can't find the right solution to do that. I am familiar with the method of checking if the alarm is active by using the PendingIntent.getBroadcast() with FLAG_NO_CREATE flag.
I managed to successfully use the getBroadcast() function repeatedly in same test by first checking if the alarm is not set at the launch of the app and then later to check if the alarm is set, both times returning the expected boolean values.
public void testTimerButtonStartProcess(){
Intent intent = new Intent (appContext, OnAlarmReceiver.class);
intent.putExtra(Scheduler.PERIOD_TYPE, 1);
intent.putExtra(Scheduler.DELAY_COUNT, 0);
intent.setAction(Scheduler.CUSTOM_INTENT_ALARM_PERIOD_END);
boolean alarmUp = (PendingIntent.getBroadcast(appContext, 0, intent,PendingIntent.FLAG_NO_CREATE) != null);
assertFalse("the alarm manager wasnt running when app is lauched", alarmUp);
solo.clickOnView(timerLayout);
instr.waitForIdleSync();
solo.sleep(5000);
alarmUp = (PendingIntent.getBroadcast(appContext, 0, intent,PendingIntent.FLAG_NO_CREATE) != null);
assertTrue("the alarm is set", alarmUp);
}
But when i try to do that in reverse order (first checking if the alarm is set and then later - if it is no longer set), my test failed, because after the second check (when the alarm should be cancelled) the getBroadcast() returned true (i expected to get false).
public void testTimerButtonLongPress(){
solo.clickOnView(timerLayout);
instr.waitForIdleSync();
Intent intent = new Intent (appContext, OnAlarmReceiver.class);
intent.putExtra(Scheduler.PERIOD_TYPE, 1);
intent.putExtra(Scheduler.DELAY_COUNT, 0);
intent.setAction(Scheduler.CUSTOM_INTENT_ALARM_PERIOD_END);
boolean alarmUp = (PendingIntent.getBroadcast(appContext, 0, intent,PendingIntent.FLAG_NO_CREATE) != null);
assertTrue("the alarm manager is running", alarmUp);
solo.clickLongOnView(timerLayout, 1500);
instr.waitForIdleSync();
solo.sleep(3000);
alarmUp = (PendingIntent.getBroadcast(appContext, 0, intent,PendingIntent.FLAG_NO_CREATE) != null);
assertFalse("the alarm manager was not running anymore", alarmUp);
}
I also tried to use the getBroadcast only once after the app cancelled the alarm, but i still got returned true.
Meanwhile i am assured, that the cancellation of the alarm works as expected, because app stops alarming after being "turned off".

How to start an alarm if the mobile is switch off

In my app, I use the AlarmManager class to set an alarm. To trigger the alarm after the mobile is rebooted I have used BroadcastReceiver. All works fine and my alarm is triggered at regular intervals. Now the problem arises in this case :
Suppose my current time is 2:30 pm and I set my alarm at 2:35 pm. After that, I switch off the mobile. After an hour when I switch on my mobile, no alarm is pop-up as the time on which the alarm is set. This is happening because the current time exceeds the time on which I set the alarm. To solve this issue what should I do. I have posted my code for setting alarm in the AlarmManager class. Please help me to solve this out
public class AlarmReceiver extends BroadcastReceiver {
#SuppressWarnings("static-access")
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Intent myIntent = new Intent(context, MyAlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, i, myIntent, i);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MILLISECOND, (int) Utilities.diff(NoteManager.getSingletonObject().getAlarmTime(i)));
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
}
public static long diff(Date date) {
long difference = 0;
try {
// set current time
Calendar c = Calendar.getInstance();
difference = date.getTime() - c.getTimeInMillis();
if (difference < 0) {
// if difference is -1 - means alarm time is of previous time then current
// then firstly change it to +positive and subtract form 86400000 to get exact new time to play alarm
// 86400000-Total no of milliseconds of 24hr Day
difference = difference * -1;
difference = 86400000 - difference;
}
}
catch (Exception e) {
e.printStackTrace();
}
return difference;
}
In The Manifest File
<receiver android:name=".AlarmReciever">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
better way is to store that alarm details in database and retrieve it on boot via broadcast receiver as you are saying you implemented one. once notified remove the details from the database. this way u can track all your alarms. even you can start a Service on startup and do this operation
The Alarm app in the Android does the same, if your phone is switched off and there is Alarm to ring up, It will make your phone switch On , ring the alarm and go to sleep again.
Here is the link of source of Alarm app Git_Alarm app you can download it and see how it is doing this.
and if you are doing something else in your alarm reciever then to ring Alarm up. you can basically set alarmreciever again in the phone Boot up, here is the one answer which may help you Alarm problem if phone is switched off
Edit :- one link was broken, replaced it

AlarmManager.RTC not working?

I changed AlarmController.java in ApiDemo a little bit, so I want the alarm not to go off when the phone is sleeping by using AlarmManager.RTC.
Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
0, intent, 0);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
firstTime += 15*1000;
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, //AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 15*1000, sender);
The receiver code is like below:
public class RepeatingAlarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("DEBUG", "In RepeatingAlarm.onReceive, intent=" + intent);
Toast.makeText(context, R.string.repeating_received, Toast.LENGTH_SHORT).show();
}
}
I ran the modified app, but I still see many log messages as below after the phone wento sleep (the screen was black):
D/DEBUG ( 1390): In RepeatingAlarm.onReceive, intent=Intent { flg=0x4 cmp=com.example.android.apis/.app.RepeatingAlarm (has extras) }
This means the flag AlarmManager.RTC didn't work. Can someone tell me why?
Thanks.
Since you are using elapsedRealtime to get the alarm start time, I think you need to use the ELAPSED_REALTIME flag instead of the RTC flag.
My guess is that the alarm manager is thinking it's missed a ton of alarms because you are using the RTC flag which means the alarm manager is expecting you to send a time value in milliseconds since Jan 1st 1970, but instead you are sending elapsed milliseconds since the device booted, which is going to be a much much smaller number.
If you use the RTC flags you need to use System.currentTimeMillis() or get the time in milliseconds from a Java Date or Calendar object. If you use ELAPSED_REALTIME flags then you need to use SystemClock.elapsedRealtime().

Categories

Resources