AlarmManager fires alarms at wrong time - android

I managed everything all right to create a notification service used to fire a notification as a result of an alarm. Unfortunately, setting the alarm using AlarmManager doesn't work right. It fires several minutes later (not exactly hours, which would indicate a timezone problem). The recurring period is 1 week, so I used the constant INTERVAL_DAY and multiplied it with 7. In order to make sure that one PendingIntent doesn't replace the other, I pass the dayOfWeek as second parameter to PendingIntent.getService(). I check the correctness of the time for the alarm to fire by logging it:
Log.d(TAG, "next alarm " + df.format(cal.getTime()));
Is there really no way to list all alarms set - at least those from my own app? I believe this is the only way to track down the error.
My code:
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
Log.d(TAG, "next alarm " + df.format(cal.getTime()));
Intent showNotificationIntent = new Intent(context, NotificationService.class);
dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
alarmIntent = PendingIntent.getService(context, dayOfWeek, showNotificationIntent, 0);
getAlarmManager(context).setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
INTERVAL_WEEK, alarmIntent);
I want to offer to have an alarm every day, but at various times, which can be set by the user. So I use up to 7 alarms, which should fire on a weekly basis.
Even after reading the numerous answers to similar questions (I don't intend to create a duplicate question), I haven't managed to find the problem.

For api levels below 19 you should use AlarmManager.setRepeating() and your alarms will trigger exactly at specified time. Thou on api levels 19 and above this will no longer work. There was change in android so that all repeating alarms are inexact. So if you would like to achieve exact repeating alarm you should schedule alarm with AlarmManager.setExact() and then when alarm triggers do it again for next week and so on every week.

Because of setInexactRepeating. Use setRepeating and it will be processed at the right time.
Instead of:
setInexactRepeating
use
setRepeating
setInexactRepeating, is OS and battery friendly, it batches together all the work to be done on Alarm receive and works through one by one, while as setRepeating instantly fires the alarm
Also a note: Alarms are wiped off once phone is rebooted, you might have to implement a boot broadcast receiver to make it persistent. Make sure you dont do that runtime, you need to implement it in the Manifest else when your app is not in background you will not receive any broadcasts.
A small example:
This is working code. It wakes CPU every 10 minutes until the phone turns off.
Add to Manifest.xml:
...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver android:process=":remote" android:name="Alarm"></receiver>
...
Code:
package YourPackage;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
Set Alarm from Service:
package YourPackage;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
public class YourService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
}
public void onStart(Context context,Intent intent, int startId)
{
alarm.SetAlarm(context);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
If you want set alarm repeating at phone boot time:
Add permission to Manifest.xml:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
...
<receiver android:name=".AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
...
And create new class:
package YourPackage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AutoStart extends BroadcastReceiver
{
Alarm alarm = new Alarm();
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
alarm.SetAlarm(context);
}
}
}

Related

AlarmManager is not repeating

I can't make AlarmManager repeating. I have tried a lot of examples, but for me they don't work. Alarm always fires only once, then nothing happens.
I ran all examples on my device (android 4.4.2) and all the examples work completely the same. Just one fire, and then nothing.
Can anybody tell me what I'm doing wrong?
Here is the code of the last example:
Receiver:
package net.desme.alarmtest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;
public class Alarm extends BroadcastReceiver {
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_SHORT).show(); // For example
wl.release();
}
public void setAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 6, pi); // Millisec * Second * Minute
}
public void cancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.desme.alarmtest" >
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".AlarmManagerActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".Alarm" android:process=":remote" />
</application>
</manifest>
Activity:
package net.desme.alarmtest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class AlarmManagerActivity extends Activity {
Alarm alarm = new Alarm();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_manager);
findViewById(R.id.start_repeating).setOnClickListener(mStartRepeatingListener);
findViewById(R.id.stop_repeating).setOnClickListener(mStopRepeatingListener);
}
private View.OnClickListener mStartRepeatingListener = new View.OnClickListener() {
public void onClick(View v) {
alarm.setAlarm(getApplicationContext());
}
};
private View.OnClickListener mStopRepeatingListener = new View.OnClickListener() {
public void onClick(View v) {
alarm.cancelAlarm(getApplicationContext());
}
};
}
Also i tried these:
https://developer.android.com/training/scheduling/alarms.html
http://www.coderzheaven.com/2011/07/31/how-to-setup-a-repeating-alarm-in-android/
and much more but i cant post it because the red tip says that i need at least 10 reputation
EDIT
The problem was that in API 19+ all alarms are inexact. Here is what the documentation says:
Note: as of API 19, all repeating alarms are inexact. If your
application needs precise delivery times then it must use one-time
exact alarms, rescheduling each time as described above. Legacy
applications whose targetSdkVersion is earlier than API 19 will
continue to have all of their alarms, including repeating alarms,
treated as exact.
And possible solutions:
Note: for timing operations (ticks, timeouts, etc) > it is easier and much more efficient to use Handler
If your application wants to allow the delivery times to drift in order to guarantee that at least a certain time interval always elapses between alarms, then the approach to take is to use one-time alarms, scheduling the next one yourself when handling each alarm delivery.
this is the solution for starting an alarm for repeating with 10 seconds interval, but it's pending intent is different, because i used this method to start service after 10 seconds interval, therefore use it according to your requirement,
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
Intent intent = new Intent(Main.this, Service_class.class);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
36000 * 1000, pintent);
Thanks
Your code works fine in Android 4.4.2 API 22. Maybe the AlarmManager on your device/API is acting differently; perhaps overriding the frequency since it's so short. Do you really need 6 seconds interval? Try increasing the frequency over a minute, i.e. > 60000.

Why the alarm receiver is not trigger in android?

I am implement a simple alarm function, which is used to trigger some function at the specific date time.
The problem is I have set the time already, but the receiver seems never called.
Here is how I implement:......
1) in manifest :
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
and
<receiver android:name=".Listener.AlarmReceiver" />
2) in the main activity (I would like to trigger on 4th June 2014, 02:06 p.m.)
profilePic.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
GregorianCalendar date = new GregorianCalendar(2014,6,4,14,6);
long dateTime = date.getTimeInMillis();
Log.d("test1",date.toString());
AlarmManager alarmManager = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Intent intentAlarm = new Intent(ctx, AlarmReceiver.class);
alarmManager.set(AlarmManager.RTC_WAKEUP, dateTime, PendingIntent.getBroadcast(ctx, 1, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
}
});
And I have also log the time
java.util.GregorianCalendar[time=1404453960000,areFieldsSet=true,lenient=true,zone=Asia/Hong_Kong,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=6,WEEK_OF_YEAR=27,WEEK_OF_MONTH=1,DAY_OF_MONTH=4,DAY_OF_YEAR=185,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=6,SECOND=0,MILLISECOND=0,ZONE_OFFSET=28800000,DST_OFFSET=0]
3) Receiver
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("test1", "alarm");
Toast.makeText(context, "Alarm Triggered", Toast.LENGTH_LONG).show();
}
}
I waited until the 02:06p.m. but nothing happened, and receiver is not called. How to fix the problem? Also, is it possible to set more than one alarm, is it all I need to do is to create another datetime and fire the alarmManager.set() again, will it overwrite the old timer? Thanks for helping.
Updated
For the AlarmReceiver in the mainifest ,
I changed to
<receiver android:name="com.example.antismoke.Listener.AlarmReceiver" />
And the class is
package com.example.antismoke.Listener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("test1", "alarm");
Toast.makeText(context, "Alarm Triggered", Toast.LENGTH_LONG).show();
}
}
so I think package name is not the root cause? Thanks for helping
Instead of using GregorianCalendar , try to use Calendar.
Try the following, it should work:
Intent i = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(AlarmSample.this, 0, i, 0);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour); // set hour
calendar.set(Calendar.MINUTE, minuite); // set minute
calendar.set(Calendar.SECOND, 0); // set seconds
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
you should use package name correctly, if you have different package ,
receiver android:name="XXX.XXXXXXXXXXXXXXX.AlarmReceiver" />
check this out
1) You don't need this persmission (com.android.alarm.permission.SET_ALARM) to receive alarm.
2) Change this line:
<receiver android:name=".Listener.AlarmReceiver" />
to
<receiver android:name=".AlarmReceiver" />
replace alarmManager.set with alarmManager.setRepeating
or try to use this:
public static AlarmManager am = null;
public static PendingIntent sender;
Intent intent1 = new Intent(ctx, Reciver.class);
sender = PendingIntent.getBroadcast(ctx, 1, intent1, 0);
am = (AlarmManager) getSystemService(ALARM_SERVICE);
long l = new Date().getTime();
am.setRepeating(AlarmManager.RTC_WAKEUP, l, 1500, sender);
Ok , finally I figure out it is because the month start at 0 in GregorianCalendar. So June should use 5 instead of 6
I should have noticed the problem. Thanks for all you guys

Working repeating alarmmanager doesn't work, receiver doesn't start

public void schedule()
{
Long time = new GregorianCalendar().getTimeInMillis()+10*1000;
Intent intent = new Intent(getActivity(), AlarmReceiver.class);
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, time, 10*1000, PendingIntent.getBroadcast(getActivity(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
}
Above this is my method in a Fragment. Also tried in Activity. Weirdly this code works on an empty test project. The problem as I've seen here is that the last part, alarmManager.setInexactRepeating() does not start the AlarmReceiver.class at all.
What am I doing wrong here?
my Manifest file:
<receiver android:name=".AlarmReceiver"/>
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
also my receiver:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "Alarm Triggered and SMS Sent", Toast.LENGTH_LONG).show();
}
}
Because of setInexactRepeating. Use setRepeating and it will be processed at the right time.
Instead of:
setInexactRepeating
use
setRepeating
setInexactRepeating, is OS and battery friendly, it batches together all the work to be done on Alarm receive and works through one by one, while as setRepeating instantly fires the alarm
Also a note: Alarms are wiped off once phone is rebooted, you might have to implement a boot broadcast receiver to make it persistent. Make sure you dont do that runtime, you need to implement it in the Manifest else when your app is not in background you will not receive any broadcasts.
A small example:
This is working code. It wakes CPU every 10 minutes until the phone turns off.
Add to Manifest.xml:
...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver android:process=":remote" android:name="Alarm"></receiver>
...
Code:
package YourPackage;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
Set Alarm from Service:
package YourPackage;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
public class YourService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
}
public void onStart(Context context,Intent intent, int startId)
{
alarm.SetAlarm(context);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
If you want set alarm repeating at phone boot time:
Add permission to Manifest.xml:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
...
<receiver android:name=".AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
...
And create new class:
package YourPackage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AutoStart extends BroadcastReceiver
{
Alarm alarm = new Alarm();
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
alarm.SetAlarm(context);
}
}
}

Using a broadcast receiver to start AlarmManager in Android?

I am writing a program that fires off an intent to start a service periodically, to do this I have decided to use alarmmanager, I was able to make this do what I wanted in an activity fairly easily but I'm getting an error when attempting to do it in a receiver that I'm unable to figure out.
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
tells me that ALARM_SERVICE can't be resolved to a variable
here is my complete code for that receiver:
package com.testapp21.second.activities;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
public class PhoneOnReceiver extends BroadcastReceiver {
private PendingIntent mAlarmSender;
#Override
public void onReceive(Context context, Intent intent) {
mAlarmSender = PendingIntent.getService(context,
0, new Intent(context, StatsCheckerService.class), 0);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 30*1000, mAlarmSender);
}
}
Try
AlarmManager am = (AlarmManager)context.getSystemService(Service.ALARM_SERVICE);
I found that if you are in a fragment you can do this
AlarmManager am = (AlarmManager)getActivity().getSystemService(Service.ALARM_SERVICE);

How to implement yearly and monthly repeating alarms?

I want to set monthly and yearly alarm in my app.I did this for weekly. AlarmManager.INTERVAL_DAY helped me for that.But i could not find good way to implement monthly and yearly repeat.
Searched so far:
http://www.satyakomatineni.com/akc/display?url=displaynoteimpurl&ownerUserId=satya&reportId=3503
http://groups.google.com/group/android-developers/browse_thread/thread/9f946e40307073c4?pli=1
Is any other way available to do this? Any help appreciated.
I think that, you have two inherent issues with this approach:
AlarmManager will not accept large time intervals because the number of millis will overflow the argument
I do not think Alarms will survive reboots of your phone that will most certainly happen during such a long period of time.
I advice that you store each alarm in a safe place and use a combination of AlarmManager and onBoot receivers to check if one of the alarms from your list must be fired this very day and just reschedule an alarm to wake you up tomorrow if none does.
public class AlarmService extends Service {
//compat to support older devices
#Override
public void onStart(Intent intent, int startId) {
onStartCommand(intent, 0, startId);
}
#Override
public int onStartCommand (Intent intent, int flags, int startId){
//your method to check if an alarm must be fired today
checkForTodayAlarmsAndBehaveAppropriately();
//reschedule me to check again tomorrow
Intent serviceIntent = new Intent(AlarmService.this,AlarmService.class);
PendingIntent restartServiceIntent = PendingIntent.getService(AlarmService.this, 0, serviceIntent,0);
AlarmManager alarms = (AlarmManager)getSystemService(ALARM_SERVICE);
// cancel previous alarm
alarms.cancel(restartServiceIntent);
// schedule alarm for today + 1 day
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
// schedule the alarm
alarms.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), restartServiceIntent);
}
}
To start your service at boot time use this :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class serviceAutoLauncher extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context,AlarmService.class);
context.startService(serviceIntent);
}
}
Finally add this to your manifest to schedule your serviceAutoLauncher to be launched at each boot:
<receiver android:name="serviceAutoLauncher">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
<category android:name="android.intent.category.HOME"></category>
</intent-filter>
</receiver>
I solved the issue. In my app,multipal alarms were set with different repeating time intervals.So in my broadcast receiver for alarm,i re-scheduled the alarm based on for what time it was scheduled to be repeated.I used calendar object to add month and year accordinly and again set it for next alarm.i used code like this(for scheduling it for next month)-
PendingIntent sender = PendingIntent.getBroadcast(context,Integer.parseInt(Long.toString(id)), intent1, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(calendar.getTimeInMillis());
calendar.add(Calendar.SECOND, 30);
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
calendar.add(Calendar.MONTH, 1);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
To add to Laurent's response. To abstract from calculating recurrence manually I suggest to take a look at this RFC-2445 implementation. It works fine on Android and can save you a lot of pain.

Categories

Resources