AlarmManager.setRepeating() not repeating on correct time - android

I am trying to make a prototype application in which the AlarmManager needs to repeatedly(like, in every 5 seconds) perform certain operation. Its repeating whatever execution of code in onRecieve() method of my BroadcastReciever but it repeats in 1 minutes something even if its supposed to repeat in every 5 seconds. I have followed all the tutorials, I am pretty sure I am following all steps. Can somebody help to find why its repeating late every time?
AlarmRecurring.java
public class AlarmRecurring extends AppCompatActivity {
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_alarm_recurring);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
setupButtons();
}
private void setupButtons()
{
findViewById(R.id.stopRepeating).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cancel();
}
});
findViewById(R.id.startRepeating).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startrepeating();
}
});
}
public void cancel() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show();
}
public void startrepeating() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
EditText secondsToRepeat =(EditText) findViewById(R.id.secondsToRepeat);
int repeat = Integer.parseInt(secondsToRepeat.getText().toString());
/* Repeating on every 20 minutes interval */
TimePicker tp = (TimePicker) findViewById(R.id.timePicker);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, tp.getCurrentHour());
calendar.set(Calendar.MINUTE, tp.getCurrentMinute());
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * repeat, pendingIntent);
Toast.makeText(this, "Repeating Alarm Started at every: " + repeat + "secs", Toast.LENGTH_SHORT).show();
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
MediaPlayer mp=null;
#Override
public void onReceive(Context context, Intent intent) {
// For our recurring task, we'll just display a message
Toast.makeText(context, "Repeating Alarm running at:" + new Date().toString(), Toast.LENGTH_SHORT).show();
mp = MediaPlayer.create(context , R.raw.short_notice);
mp.start();
}
}
Thanks :-)

As of API 22 the value of the interval will be forced up to 60000 ms if the given value is smaller.

there is some android targetsdkversion.
Beginning with API 19 (KITKAT) alarm delivery is not proper:
android OS will shift alarms in order to minimize wakeups and battery use. Te Os has given the new APIs to support applications which need strict delivery guarantees;
setWindow(int, long, long, PendingIntent);
setExact(int, long, PendingIntent);
Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

Related

Alarm is not triggering on the same Date

I want to reboot device on particular time so i am using alarm manager for that.below is the code of my activity.
public class MainActivity extends AppCompatActivity {
private static int timeHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
private static int timeMinute = Calendar.getInstance().get(Calendar.MINUTE);
AlarmManager alarmManager;
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(MainActivity.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 02);
alarmManager.cancel(pendingIntent);
// if(Calendar.getInstance().after(calendar)){
// // Move to tomorrow
// calendar.add(Calendar.DATE, 1);
// }
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, pendingIntent);
//
// alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
// SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY,
// AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
and this is my receiver
public class AlarmReceiver extends BroadcastReceiver {
public static void rebootDevice() {
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("reboot \n");
} catch (Throwable t) {
t.printStackTrace();
}
}
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Triggered", Toast.LENGTH_SHORT).show();
Log.d("Gajanand", "onReceive: Triggered");
rebootDevice();
}
}
Yes code is working fine but not on the exact date.for example if i run the same code now. alarm not triggers if i change the date it triggers. i am not getting what is the problem with code and there is 10 seconds delay in triggering alarm. any help
There are two problems with your code:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 02);
Here you're setting HOUR_OF_DAY and MINUTE but the SECOND field still has its initial value, so the alarm won't be triggered exactly on the minute
(unless you called calendar.setTimeInMillis(System.currentTimeMillis()) exactly on the minute, which is quite unlikely).
Should be something like this:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 2);
calendar.set(Calendar.SECOND, 0); // setting seconds to 0
setRepeating() is inexact and doesn't work with Doze.
For exact trigger times you should use exact alarms, check this answer for an example.
This is from the documentation
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 {#code targetSdkVersion} is earlier than API 19 will continue to have all
of their alarms, including repeating alarms, treated as exact.
Repeating alarms are always inexact so that they wont consume much battery. They may be fired a bit later than the expected time. If you want your alarm to exact, don't make it repeating. Set it again once you receive the alarm

how can I set repeating alarm every 5 second to show message

here is my code in application class inside oncreate method: But I can't see any message from my app. Can anyone help me to do this?
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
public void startAlarm() {
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 5000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}
And on the broadcast receiver class I have the following code
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// For our recurring task, we'll just display a message
Toast.makeText(arg0, "I'm running", Toast.LENGTH_SHORT).show();
}
}
Edited answer:
Use setInexactRepeating() instead of setRepeating(). setRepeating only takes set intervals with the shortest being INTERVAL_FIFTEEN_MINUTES. setInexactRepeating() is the only way to set a repeating interval as short as 1000ms, or 5000ms in your case.
Change:
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
to
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
If you are not getting the exact 5 second delay that you need, you will need to use a Handler. Any type of alarm with a 5 second delay will not work properly because as of Android 5.x basically all repeating alarms are inexact to save battery life.
I have modified your code to use a Handler:
startAlarm();
public void startAlarm() {
final Handler h = new Handler();
final int delay = 5000; //milliseconds
h.postDelayed(new Runnable(){
public void run(){
//do something
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
sendBroadcast(alarmIntent);
h.postDelayed(this, delay);
}
}, delay);
}
That alarm method will work with your current BroadcastReceiver and do an actual 5 second delay.

Alarm manager for background services

I have implemented the alarm manager to wake up the background services every 15 mins periodically. It is working fine, but since the inclusion of DOZE mode Android 6.0, the seems like behaving strange and not waking up in every 15 mins. Although, I am using the method alarm.setExactAndAllowWhileIdle(), but still not working in Idle state
here is my method for implementing Alarm Manager
private void serviceRunningBackground()
{
final Intent restartIntent = new Intent(this, service.class);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler;
restartServiceHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
Log.d(TAG, " Marshmellow "+ TIMER_START_TIME);
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 900000, pintent);
} else {
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 900000, pintent);
}
sendEmptyMessageDelayed(0, TIMER_START_TIME);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
Any help would be appreciated..thanks
Try this:
public class PollReceiver extends WakefulBroadcastReceiver{
static final String PERIOD = "period";
#Override
public void onReceive(Context context, Intent intent){
startWakefulService(context,new Intent(context,MyService.class));
long period = intent.getLongExtra(PERIOD,-1);
if(period>0){
scheduleExactAlarm(context,(AlarmManager)context.getSystemService(Context.ALARM_SERVICE),period)
}
}
static void scheduleExactAlarm(Context context,AlarmManager alarms, long period){
Intent i = new Intent(context,PollReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,0,i,0);
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1){
alarms.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + period,pi);
}
}
Ive tested scheduling alarms in this way in Doze and it works. They go off every 15 minutes. Check out https://commonsware.com , thats where I found this method of scheduling a repeating alarm.

setting alarm on boot time at a specific time every day

I have started alarm of 9:00 AM in android on Boot Completed. But fires alarm every minute after it has completed boot.
My Requirement is it should set Alarm after boot but only fires alarm at 9:00 AM.
Here is my code:
public class AlarmUtil {
private PendingIntent alarmIntent;
public static void setAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
calendar.set(Calendar.AM_PM, Calendar.AM);
//calendar.setTimeInMillis(calendar.getTimeInMillis());
calendar.add(Calendar.SECOND, 1);
Intent intent = new Intent(context, Services.class);
PendingIntent pintent = PendingIntent.getService(context, 123456789,
intent, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1 * 60 * 1000, pintent);
}
}
public class AlarmBroadcastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Toast.makeText(context, "Booted!", Toast.LENGTH_SHORT).show();
AlarmUtil.setAlarm(context);
}
}
}
services (My service Class)
public class Services extends IntentService {
public Services(String name) {
super("services");
// TODO Auto-generated constructor stub
}
public Services() {
super("services");
// TODO Auto-generated constructor stub
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyApp.counter += 1;
Toast.makeText(getApplicationContext(),
"Service started: " + MyApp.counter, Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onHandleIntent(Intent intent) {
Toast.makeText(getApplicationContext(), "handling intent",
Toast.LENGTH_LONG).show();
}
}
where i am lacking. Please help me. Thanks in advance.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1 * 60 * 1000, pintent);
By calling setRepeating(), you are instructing it to fire the intent on every minute. You probably meant to use set() or setExact() instead.
Additionally, you're setting the alarm for 9:00 on the current date. I'm not exactly sure what your objective is but if you want an alarm for the "next 9:00" (i.e. as an alarm clock) you should probably add a day if the current time is greater than 9:00. From the documentation:
If the stated trigger time is in the past, the alarm will be triggered
immediately.
EDIT: If what you need is to fire this alarm every day at 9:00, then setRepeating() is correct, but the time in milliseconds should be AlarmManager.INTERVAL_DAY. Be mindful of the note about past alarms, though. If you boot your phone, say, at 10:00 AM, and you use your current code, you will get an immediate alarm in addition to the future ones.
And, as #DerGolem pointed out, if you target API level 19 then these alarms will be inexact (and there is no setRepeatingExact()). If you need exact alarms, then you will have to schedule one with setExact(), then the next one when that one fires, and so on.
Hi I have used following code and able to generate alarm at 9 Am each day
alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmService.class);
PendingIntent pintent = PendingIntent.getService(this, 123456789,
intent, 0);
// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 9);
calendar.set(Calendar.MINUTE, 00);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1000 * 60 * 1 * 60 * 24, pintent);
you need to replace "1 * 60 * 1000" with AlarmManager.INTERVAL_DAY to set it daily

Alarm manager triggered immediately

Hi I am currently working with AlarmManager. I have written a code given below. As per code the AlarmManager should be triggered after 10 Sec, but here in my code the alarm manager triggers immediately. Please help.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long timeOrLengthofWait = 10000;
Intent intentToFire = new Intent(this, AlarmReciever.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0);
alarmManager.set(alarmType, timeOrLengthofWait, alarmIntent);
}
}
And My AlarmReciever Class
public class AlarmReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String phoneNumberReciever="5556";
String message="Alarm Triggered";
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumberReciever, null, message, null, null);
Toast.makeText(context," A message has been sent", Toast.LENGTH_LONG).show();
Log.d("Alarm ", "Alarm Has been triggered and sms send");
}
}
I have Already added required permissions in manifest.
You are using an alarm type of ELAPSED_REALTIME_WAKEUP. That means that the second parameter to set() must be the number of milliseconds from now, where now is expressed as SystemClock.elapsedRealtime().
If your goal is to have this occur 10000 milliseconds from the time you make the set() call, that set() call should be:
alarmManager.set(alarmType, SystemClock.elapsedRealtime()+timeOrLengthofWait, alarmIntent);
If you are creating PendingIntent of an alarm for past time it will be fired immediately. Example - Schedule alarm for today 8AM but executing code around 11AM will fire immediately.
Solution:
cal.add(Calendar.DATE, 1);
long delay = 24 * 60 * 60 * 1000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), delay,pendingIntent);`
This will fire the event on next day at specified time (i.e 8AM);

Categories

Resources