I'm currently developing an application which makes use of Android's AlarmManager. I'm trying to add a new alarm to the AlarmManager, but after several hours of trying various things and checking various threads on SO, I'm still at a brick wall. Are there any problems with my code?
Main Activity - saveAlarm() function
/**
* Saves the current alarm. Adds to the database if it doesn't already exist, or updates if it does.
* Also sets alert with AlarmManager.
*/
public void saveAlarm() {
// Create Database instance
DbHandler db = new DbHandler(getApplicationContext());
if(alarm.getId() == -1) {
// Saving a new alarm
db.open();
alarm.setId(db.addAlarm(alarm));
db.close();
}
else {
db.open();
db.updateAlarm(alarm);
db.close();
}
// Create the wakeup intent
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("alarm_id", alarm.getId());
// Create the Pending Intent
PendingIntent sender = PendingIntent.getBroadcast(this, AlarmPlayer.REQUEST_ALARM + alarm.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Debug
Calendar now = Calendar.getInstance();
long dTime = alarm.getNextAlarmTime().getTimeInMillis() - now.getTimeInMillis();
Log.d(TAG, "Setting alarm for " + (dTime / 1000) + " seconds time");
// Add to Android Alarm Manager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, alarm.getNextAlarmTime().getTimeInMillis(), sender);
}
I've verified that the correct time is being passed into am.set (see the debug section above it).
AlarmReceiver.class
/**
* This class listens out for broadcasts from AlarmManager
* and launches the AlarmPlayer activity accordingly.
* #author Michael
*
*/
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
Log.d("RSS Alarm", "Waking up alarm");
// Launch the AlarmPlayer activity
Intent i = new Intent(c, AlarmPlayer.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(i);
}
}
I also have <receiver android:process=":remote" android:name="AlarmReceiver" /> set up in AndroidManifest.xml. I have no idea what's causing this problem, but it's happening nonetheless. Any help would be greatly appreciated, many thanks in advance.
Edit 1
Changing the timezone to UTC doesn't seem to solve anything, my calendar seems to default to UTC regardless. Current code:
// Debug
Calendar now = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
long dTime = alarm.getNextAlarmTime().getTimeInMillis() - now.getTimeInMillis();
Log.d(TAG, "Setting alarm for " + (dTime / 1000) + " seconds time");
// Add to Android Alarm Manager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Log.d(TAG, "Timezone offset is " + TimeZone.getDefault().getRawOffset());
Log.d(TAG, "UTC time is currently " + Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTimeInMillis() / 1000);
am.set(AlarmManager.RTC_WAKEUP, (alarm.getNextAlarmTime().getTimeInMillis() - TimeZone.getDefault().getRawOffset()), sender);
Is this possibly a case that AlarmManager.set(AlarmManager.RTC_WAKEUP, ...) needs the time in UTC? This causes problems if you're setting a 'local time' and don't adjust to UTC. In short, the alarm may be being properly added but it doesn't trigger when you expect it unless your time-zone is UTC.
From the docs...
public static final int RTC_WAKEUP Since: API Level 1
Alarm time in System.currentTimeMillis() (wall clock time in UTC), which will wake up the device when it goes off.
In your manifest, I believe you need android:name".AlarmReceiver" note the dot.
If that doesn't do it, post your manifest file. Also, does your logcat mention adding alarm and alarm triggering?
Edit: You might try this
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Other than that, I don't see anything jumping out at me. Good Luck
Related
I am building an alarm application in Android Java using the C# Xamarin framework. I have done almost everything according to the Android Java play book, but the Alarm Manager Service does not fire my alarm for some reason.
I have a TimePicker and DatePicker objects in my application, I use the TimePicker to read the time and minute set by the user and the the DatePicker to read the day of the week the user intends to be reminded of a certain event. When I do a check on a sample time, I have set as the trigger time, then everything seems to be okay, but there is this parameter of AlarmManager.Set(..,PendingIntent pIntent). I believe the object specifies the operation that needs to be performed when the Alarm has matured. Could that have something to do with why the application does not do anything when the time has matured?
I have declared all the required permissions in my manifest file as follows.
<uses-permission android:name="android.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
I then access a calendar instance and ask use my timepicker and datepicker objects to set it. I did this, because I was going to need the calendar time in milliseconds as a parameter in the AlarmManager.Set() call.
//adjust the time in the the calendar variable using the minute and hour from the timepicker
Calendar calendar= Calendar.Instance;
//make sure the instance fields are manipulated hierarchically
calendar.Set(mycalendar.Year,mycalendar.Month,mycalendar.DayOfMonth,timepicker.Hour,timepicker.Minute);
//use the alarm manager to set a new alarm with a pending Intent object
_alarmManager.Set(AlarmType.ElapsedRealtimeWakeup,calendar.TimeInMillis,alarmoperation);
//this pending intent specifies the kind of operation that will happen when
//the alarm goes live
This is the PendingIntent that gets called when the alarm matures
PendingIntent alarmoperation = CreatePendingResult(908, new Intent(), PendingIntentFlags.OneShot);
How do I program a pending intent to fire an alarm if that is what is causing the application not to fire? Is it because I used an empty intent as a constructor parameter when I created the pending intent?
I might be sure that this works:)
Open a Util class, i called it Scheduler, it can schedule notification task or a alarm task :)You choose alarm, since my app needs both :D
/**
* Set the context to use in AlarmManager/Database. They all require {#linkplain Context}
* for many different purposes
* <p>
* For this very reason, Scheduler requires you to provide context. Also, Util class {#link
* com.functionality.app.homepage.LifeStyleUtils} has most of its functions requiring {#link
* Context}.
* </p>
* #param ctx The context to use in issue raising in LifeStyleUitls, e.t.c.
*/
public Scheduler(Context ctx) {
this.ctx = ctx;
}
public int scheduleNotification(LocalDateTime time, Intent intent, int code) {
try {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.MINUTE, time.getMinute());
cal.set(Calendar.HOUR, time.getHour());
cal.set(Calendar.MONTH, time.getMonthValue());
cal.set(Calendar.YEAR, time.getYear());
cal.set(Calendar.DAY_OF_MONTH, time.getDayOfMonth());
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx,
code, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmService = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
alarmService.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000* 60 * 5,
pendingIntent);
return SUCCESS;
} catch(Exception e) {
return FAILURE;
}
}
/**
* Schedule a task outside the life cycle of app.
*
* #param time The time to set the task.
* #param intent The intent to use, including the Receiver class.
* #return failure or sucess.
*/
public int scheduleTask(LocalDateTime time, Intent intent, int code) {
try {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.MINUTE, time.getMinute());
cal.set(Calendar.HOUR, time.getHour());
cal.set(Calendar.MONTH, time.getMonthValue());
cal.set(Calendar.YEAR, time.getYear());
cal.set(Calendar.DAY_OF_MONTH, time.getDayOfMonth());
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx,
code, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmService = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
alarmService.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000* 60 * 5,
pendingIntent);
return SUCCESS;
} catch(Exception e) {
return FAILURE;
}
}
public static PendingIntent getPendingIntent(Intent intent, Context context) {
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
| PendingIntent.FLAG_IMMUTABLE);
}
public void cancelAlarm(PendingIntent pendingIntent) {
AlarmManager alarmManager= (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
public void cancelNotification(PendingIntent pendingIntent) {
AlarmManager alarmManager= (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
Note: use the function "scheduleTask" not "scheduleNotification". Also, If you need reciever code, just comment, i'll send you, i dont wanna send since it will expose my idea, not sending notification since you need alarm. Also, R.raw file is my mp3 samusng galaxy on horizon recording, cant send you that.
I'm trying to write a service that will check every midnight for new data from the server and will download it.
But when i start the app the mainActivity screen reloads after few seconds.
I'v checed it and it happens because of this service,
Why is this happening?
Her are the files:
MainActivity: i'v created an AlarmManager object to set pendingIntent:
//Set alarm
/* Retrieve a PendingIntent that will perform a broadcast */
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReciever.class);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 24 * 60 * 60;
/* Set the alarm to start at 10:30 AM */
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 00);
calendar.set(Calendar.MINUTE, 00);
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
AlarmReciever:
public class AlarmReciever extends BroadcastReceiver {
private Data newData = null;
public SharedPreferences settings;
ConnectivityManager cm = null;
NetworkInfo netInfo = null;
#Override
public void onReceive(Context context, Intent intent) {
newData = new Data(context);
// TODO Auto-generated method stub
newData.cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
newData.netInfo = newData.cm.getActiveNetworkInfo();
newData.settings = PreferenceManager.getDefaultSharedPreferences(context);
// System.out.print("-----------------" + newData.netInfo);
newData.checkOnline();
}
}
Data.java:
public void checkOnline(){
if (isOnline()){
System.out.print("**************** YES Internet");
firstAsyncTask task = new firstAsyncTask(this);
try {
Object dobj = task.execute("par1", "par 2", "par 3").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}else{
System.out.print("**************** NO Internet");
}
}
The data.java file is to big to post in here, but it seems that the "checkOnline" method in in causing the app to reload the MainActivity page, should i send the service differently?
Thanx for reading & answering.
Looks like you have written this line by mistake
pendingIntent = PendingIntent.getService(getApplicationContext(), 0, alarmIntent, 0);
It should be like this
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);
Because you are using BroadcastReciever.
Causes the following line network access?
Object dobj = task.execute("par1", "par 2", "par 3").get();
If so then the system might kill your process (ether for networking on main thread or for event loop timeout aka. ANR). And eventually restart it again if its a service.
In your Activity you do this:
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
This causes the BroadcastReceiver to be triggered immediately, since you have specified System.currentTimeMillis() as the time to trigger the first time.
You probably mean to use calendar.getTimeInMillis() as the first time to trigger the alarm. But even if you change it to that, it will still trigger immediately because you've set the time in your calendar to 00:00 of the current day, which has already passed! You need to either use calendar.getTimeInMillis() + interval (which would be 00:00 of the following day, or you can add 1 day to your calendar before using calendar.getTimeInMillis().
I have some doubts that I would like to clear regarding the AlarmManager class in Android.
I have an app that needs to:
Allow the user to set a time.
Start an alarm.
Then, even if the app is closed, it should start up on the preset time and do a certain function (like button.performClick()) in the main activity.
So, I have successfully created an activity called alarm.java, created the layout in res\layout and added it to AndroidManifest.xml. Also, I have successfully set the alarm as follows in my alarm.java class:
onCreate(){
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(context, MyActivity.class);
pi = PendingIntent.getBroadcast(this.getApplicationContext(), ALARM_ID, intent, 0);
}
onClick(){
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Toast.makeText(getApplicationContext(), "Alarm Set For " + hour + ":" + minute + " " + ampm, Toast.LENGTH_LONG).show();
}
Now, in my MyActivity.java class, which is the main activity, I have added the BroadcastReceiver
public BroadcastReceiver AlarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
/*This is the part I got from SO for starting an activity from `BroadcastReceiver`
Intent i = new Intent();
i.setClassName("com.kanishka.nightstalker.homeautomation", "com.kanishka.nightstalker.homeautomation.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);*/
Toast.makeText(getApplicationContext(), "APP STARTED", Toast.LENGTH_LONG).show();
button.performClick();
}
};
Obviously, this method isn't working as I see no Toast popping up after elapsed time. I kinda understand what the issue is, and I should be using a Service for this. But from what I know, AlarmManager itself runs in the background and SHOULD trigger the BroadcastReceiver of MyActivity.java on elapsed time. Where am I going wrong?
Where am I going wrong?
You are using setInexactRepeating(). Here, "inexact" means "not exact", and so the alarm will occur sometime within INTERVAL_DAY of your requested time.
You are taking the current time, then setting the hour and minute, which could result in a time in the past.
You are creating an Intent for MyActivity, which is probably not a BroadcastReceiver (or, if it is, MyActivity is a very odd name to choose).
If you want the alarm to go off "even if the app is closed", then you need to use a BroadcastReceiver that is registered in the manifest.
It is not possible to "do a certain function (like button.performClick()) in the main activity", as there will not be an activity "if the app is closed".
I'm trying out alarms and have hit a wall. I don't think my alarm is setting up properly because I never get a confirmation after the alarm is supposed to go off. Here's how I call on the alarm manager:
long alarmtime=new GregorianCalendar().getTimeInMillis()+10*1000;//run after 10 seconds
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmman = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmman.cancel(pi); // cancel any existing alarms
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
alarmtime, 10 * 1000, pi);//run every 10 seconds
And here's my AlarmReceiver.java:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "TEST", Toast.LENGTH_LONG).show();
}
}
However, the TEST text does not appear, and I can't figure out why.
Since you are using the AlarmManager.ELAPSED_REALTIME_WAKEUP argument, your initial alarm-time should be base on the elapsed real time of the device:
long alarmtime = SystemClock.elapsedRealtime() + 10 * 1000;
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmtime, 10 * 1000, pi);
(see this link).
For a BroadcastReceiver it's probably PendingIntent.getBroadcast() instead of PendingIntent.getService(). You are also cancelling the alarm, just update your PendingIntent like this and try not cancelling before:
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
Read the documentation thoroughly for further information.
Make sure that the BroadcastReceiver is being called by doing a System.out.println("TEST"); instead of Toast. If you are able to see that in your logcat, then the problem probably is that you need to run the Toast in UI thread.
I followed the instructions in this thread to create a daily alarm that starts a service at 12:30 each day which shows a notification. The problem I'm having is that setting the alarm also triggers the service (=> and the notification) every time the app starts.
Since I figured that the alarm will run only at the specified time (12:30) then I have no problem setting it when the app starts.
I realize that setting the alarm from scratch every time the app is launched is a bit ineffective since it only needs to be set once (I made it set on device boot as well), but it seemed like the easiest way.
So what's the best way to fix this? is there a way to set the alarm for the specified time without running the intent when setting?
Here's the code if you are interested (this function is called every time when launching the app):
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.setTimeZone(TimeZone.getTimeZone("GMT"));
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
thanks in advance.
After trying several things, I used the information in this thread to preform a check if an alarm already exists, and setting one only if there isn't one already.
code:
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
boolean alarmUp = (PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_NO_CREATE) != null);
// check if an alarm already exists
if (alarmUp == false)
{
// set an alarm in case there isnt one already set
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
if (dailyCheckTime.getTimeInMillis() < Calendar.getInstance()
.getTimeInMillis()) {
dailyCheckTime.set(Calendar.DATE,
dailyCheckTime.get(Calendar.DATE) + 1);
}
AlarmManager alarm = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}