I am attempting to use CommonsWare's WakefulIntentService in a new application, specifically its ability to easily schedule the intent service to run at a later time.
I have a PreferenceActivity that allows the user to pick the schedule that the service is run (daily at 5am for example). Once the user makes a change to the preference value, I call:
AutoDownloadIntentServiceAlarmListener alarmListener = new AutoDownloadIntentServiceAlarmListener();
alarmListener.setForcedHour(5); // we want to schedule alarm for 5am everyday.
WakefulIntentService.scheduleAlarms(alarmListener, this, true);
For some reason, the desired IntentService (that extends WakefulIntentService) immediately starts up and performs its work.
Here is the implementation of of AutoDownloadIntentServiceAlarmListener:
public class AutoDownloadIntentServiceAlarmListener implements WakefulIntentService.AlarmListener {
private static final String TAG = "AutoDownloadIntentServiceAlarmListener";
private int mForcedHour = -1;
#Override
public long getMaxAge() {
return AlarmManager.INTERVAL_DAY * 2;
}
public void setForcedHour(int forcedHour) {
mForcedHour = forcedHour;
}
#Override
public void scheduleAlarms(AlarmManager alarmManager, PendingIntent pendingIntent, Context context) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
String autoDownloadTimePref = MyApplication.getInstance().getPrefs().getString("autoDownloadEpisodesSchedule", "0");
int hourOfAlarm = Integer.parseInt(autoDownloadTimePref);
// if this class has been created with a specific hour
// use it instead of the value obtained from SharedPreferences above.
if (mForcedHour > -1) {
Log.w(TAG, "Forced hour has been set for this AlarmListener. " + mForcedHour);
hourOfAlarm = mForcedHour;
}
calendar.set(Calendar.HOUR_OF_DAY, hourOfAlarm);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.d(TAG, String.format("Scheduled inexact alarm for %d", hourOfAlarm));
}
#Override
public void sendWakefulWork(Context context) {
Intent serviceIntent = new Intent(context, AutoDownloadIntentService.class);
WakefulIntentService.sendWakefulWork(context, serviceIntent);
}
}
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day. (and continues to repeat on this schedule indefinitely, or until the user elects to disable or change its schedule)
What am I doing wrong?
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day.
Except that's not what your code does, ~80% of the time. Your code says that it should run at 5am today, as you are getting the current time and not changing the day. Most of the time, 5am today is in the past, and so AlarmManager will immediately do its work.
You need to see if your calculated Calendar is older than now, and if so, add a day.
Related
public static boolean setupAlarm(String flightName, long columnId, int time,int requestCode, Context context) {
AlarmManager alarmManager;
FlightTimeObject timeObject = DataCheckingUtils.getConvertedTime(time);
try {
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context.getApplicationContext(), ProcessAlarmReceiver.class);
intent.putExtra(IntentActions.INTENT_REQUEST_CODE, requestCode);
intent.putExtra(IntentActions.INTENT_SEND_STRING_FLIGHT, flightName);
intent.putExtra(IntentActions.INTENT_SEND_FLIGHT_COLUMN_ID, columnId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent,0);
//Get calendar instance
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//get hour
if (timeObject.getHour()!= -1) {
int hour = timeObject.getHour();
calendar.set(Calendar.HOUR_OF_DAY, hour);
}
//get minute
if (timeObject.getMinute()!=-1){
int minute = timeObject.getMinute();
calendar.set(Calendar.MINUTE, minute);
}
calendar.set(Calendar.SECOND, 0);
assert alarmManager != null;
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
pendingIntent);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Hello everyone. The above code gets called within a for loop, underneath.
private static void setupAlarmToFlight(ArrayList<FlightObject> flightArray, Context context) {
int numberOfAlarms = 0;
int requestCode = 0;
for (int i = 0; i < flightArray.size(); i++){
FlightObject flight = flightArray.get(i);
String name = flight.getFlightName();
long flightColumnId = flight.getColumnId();
int flightActualTime = flight.getActualArrivalTime();
int scheduledTime = flight.getFlightScheduledTime();
int timeToParse = -2;
if (flightActualTime == -2){
timeToParse = scheduledTime;
}else{
timeToParse = flightActualTime;
}
boolean alarmSet = ExtractFlightUtilities.setupAlarm(
name,
flightColumnId,
timeToParse,
requestCode,
context);
if (alarmSet){
numberOfAlarms++;
requestCode++;
}
}
Intent intent = new Intent(IntentActions.ALARM_SET);
intent.putExtra(IntentActions.INTENT_SEND_INT, numberOfAlarms);
context.sendBroadcast(intent);
}
This code basically sets alarms for different flight arrival times from an arraylist that will start a service. The first alarm always fires right on time, but the rest never fire. I even stopped the service so it would just get to the receiver, but only the first fires. I also stopped the for loop at 2-3 alarms, but nothing.
I made sure that the hours and minutes are set correctly, and used another loop that would just set alarm in one minute after each but no luck.
Any help would be greatly appreciated.
EDITED:
I tried the suggestion and still not firing the alarms.
Something interesting I noticed, when setting breakpoints, the debugger gives preview values, and the first alarm that goes off okay, it's values, such as the requestCode and the Calendar values are green. All other following alarms are red.
For the first alarm.
The request code is green.
The pending intent looks all green.
The calendar value looks all green.
For all the other alarms.
The request code is red.
The pending intent request code red:
The calendar value is red
Again thank you for your time.
Since you set exact time, it might be because you did not check if the alarm time set is not passed already. E.g. consider the current date/time is 1-Jan-2018 11:30PM. If you set alarm for 01:00AM, based on your code, the alarm will be set for 1-Jan-2018 01:00AM since you used:
calendar.setTimeInMillis(System.currentTimeMillis())
which returns 1-Jan-2018 11:30PM and the you set time to 01:00AM which change the date to 1-Jan-2018 01:00AM which is passed. In this case you should add to alarm date one day. Something like this:
/**
* adjust time and date of alarm (alarms set in some previous years, will updated to today).
* if time is passed in today, date will +1
*
* #param alarmTimeCalendar time which may need adjustments
* #return adjusted time for alarm
*/
public static Calendar adjustAlarmTime(Calendar alarmTimeCalendar) {
Calendar adjustedDateCalendar = Calendar.getInstance();
int hour = alarmTimeCalendar.get(Calendar.HOUR_OF_DAY);
int minute = alarmTimeCalendar.get(Calendar.MINUTE);
adjustedDateCalendar.set(Calendar.HOUR_OF_DAY, hour);
adjustedDateCalendar.set(Calendar.MINUTE, minute);
adjustedDateCalendar.set(Calendar.SECOND, 0);
Date currentDate = adjustedDateCalendar.getTime();
Date alarmDate = adjustedDateCalendar.getTime();
long difference = alarmDate.getTime() - currentDate.getTime();
if (difference < 0) {
adjustedDateCalendar.add(Calendar.DATE, 1);
}
return adjustedDateCalendar;
}
So after trying multiple ways of approaching the problem, I solved it by setting the alarm as only RTC and not RTC_WAKEUP. Now all the alarms are firing right on time.
Thank you all.
I wrote an application which is able to set alarms based on some specif times. These specific times change day by day. For example, sunrise time changes every day. So, I defined a main activity which is responsible to call setExact() method every night at 11:55 p.m and then it has to set tomorrow's alarms based on the specific times for tomorrow. The issue is, it does not work! When I set the alarm, it just works for one time, and it is not going to be set for the second time. I really need help. Thank you :)
public class MainPage extends AppCompatActivity {
private Calendar calendar = new GregorianCalendar();
protected GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setMainAlarm();
}
private void setMainAlarm() {
AlarmManager alarmMgr = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(".mainAlarmReciever");
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar alertCalendar = Calendar.getInstance();
alertCalendar.set(Calendar.HOUR,23);
alertCalendar.set(Calendar.MINUTE,54);
alertCalendar.set(Calendar.SECOND,59);
if (Build.VERSION.SDK_INT >= 23) {
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alertCalendar.getTimeInMillis(), alarmIntent);
}else{
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, alertCalendar.getTimeInMillis(), alarmIntent);
}
}
This is the related receiver class for that:
public class mainAlarmReciever extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
AlarmSetter.createOrUpdateAllAlarms(context);
this.completeWakefulIntent(intent);
}
The issue is you do not set the mainAlarm for tomorrow on your mainAlarmReciever.
Imagine that your mainAlarmReciever->onRecieve run at 11:54:59 P.M tonight. And it does whatever tasks you want to do. You should also set the mainAlarm for Tomorrow at 11:54:59 P.M in your onRecieve function.
Another option is using setRepeating (as CommonsWare mentioned it is not exact after API 19+).
I have done an application that fire an alarm in certain time, and i am stuck on implementing remind me after half an hour functionality
what can i do to implement receiver, or service or anything that runs after half an hour of clicking the button of reming me after half an hour
any suggestions ?
Edited the code from Android execute a function after 1 hour to half an hour.
// the scheduler
protected FunctionEveryHalfHour scheduler;
// method to schedule your actions
private void scheduleEveryHalfHour(){
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(WAKE_UP_AFTER_HALF_HOUR),
PendingIntent.FLAG_UPDATE_CURRENT);
// wake up time every 1 hour
Calendar wakeUpTime = Calendar.getInstance();
wakeUpTime.add(Calendar.SECOND, 30 * 60);
AlarmManager aMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
aMgr.set(AlarmManager.RTC_WAKEUP,
wakeUpTime.getTimeInMillis(),
pendingIntent);
}
//put this in the creation of service or if service is running long operations put this in onStartCommand
scheduler = new FunctionEveryHalfHour();
registerReceiver(scheduler , new IntentFilter(WAKE_UP_AFTER_HALF_HOUR));
// broadcastreceiver to handle your work
class FunctionEveryHalfHour extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// if phone is lock use PowerManager to acquire lock
// your code to handle operations every half hour...
// after that call again your method to schedule again
// if you have boolean if the user doesnt want to continue
// create a Preference or store it and retrieve it here like
boolean mContinue = getUserPreference(USER_CONTINUE_OR_NOT);//
if(mContinue){
scheduleEveryHalfHour();
}
}
}
You can write a simple service with a timer and whenever the time is up.it can do your thing.all you need to do is start a service with a timer inside of it
I have an application object declared in the manifest and this code runs when the application runs. What I want to accomplish is to set an alarm:
#Override
public void onCreate() {
super.onCreate();
singleton = this;
persister = new Persister();
am = (AlarmManager) getSystemService(ALARM_SERVICE);
sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
sharedPref.registerOnSharedPreferenceChangeListener(this);
registerAlarms();
}
public void registerAlarms() {
String sleepString = sharedPref.getString("time_sleepLog", "08:00");
String[] pieces = sleepString.split(":");
int sleepHour = Integer.parseInt(pieces[0]);
int sleepMinute = Integer.parseInt(pieces[1]);
String eveningString = sharedPref.getString("time_eveningLog", "20:00");
pieces = null;
pieces = eveningString.split(":");
int eveningHour = Integer.parseInt(pieces[0]);
Log.v(TAG, "eveningHour in registerAlarms: " + eveningHour);
int eveningMinute = Integer.parseInt(pieces[1]);
// create calendar objects pointing to the next time this clock will
// occur
Calendar sleepCal = Calendar.getInstance();
sleepCal.set(Calendar.HOUR_OF_DAY, sleepHour);
sleepCal.set(Calendar.MINUTE, sleepMinute);
sleepCal.set(Calendar.SECOND, 0);
Calendar eveningCal = Calendar.getInstance();
eveningCal.set(Calendar.HOUR_OF_DAY, eveningHour);
eveningCal.set(Calendar.MINUTE, eveningMinute);
sleepCal.set(Calendar.SECOND, 0);
Intent syncIntent = new Intent(this, SleepNotificationReceiver.class);
syncIntent.putExtra("MoodSleepLogAlarm", 0);
PendingIntent sleepPending = PendingIntent.getBroadcast(this, 0,
syncIntent, 0);
// then set the alarms
am.setRepeating(AlarmManager.RTC_WAKEUP, sleepCal.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, sleepPending);
Log.v(TAG, "Alarm for sleep registered at " + sleepCal.getTime());
}
I log in the broadcastreceiver to check if it runs with:
Log.v(TAG, "Context: " + context.getClass().getName())
I can see this in logcat 4 seconds after starting my application as 0
6-27 17:59:29.492: V/SleepNotificationReceiver(2609): Context: android.app.ReceiverRestrictedContext
When I call the registerAlarms() via a button it doesn't happend. So it is only when called onCreate.
Why does it run the broadcast receiver after 4 seconds? (It does also run the broadcastreceiver with the same context given at the given times in my settings screen - but I need it to not run when I set it.)
When you are setting the alarm repeating, the second parameter indicates when the alarm has to go off the first time, so I think that if you type sleepCal.getTimeInMillis() and you are in the "future" compared to this time, the alarm is going off instantly.
Check that second parameter if it's in the future because I think that you are not setting the day or month in your calendar.
I am new to Android. I am trying to develop an Alarm Application, which is actually a speaking clock. I just want the clock to use TextToSpeech API and speak out the greeting stuff and the current time as soon as the alarm time is ticked. The speech part is done. And now I want to implement the Alarm functionality. But Initially I am just trying to display a toast after 10 secs in order to check whether my classes are working properly. And I am not getting the desired response and I don't know why ? Following are the classes
Main Class aClockActivity
public class aClockActivity extends Activity {
/** Called when the activity is first created. */
private PendingIntent mAlarmSender;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button1 = (Button)findViewById(R.id.buttonOn);
button1.setOnClickListener(mStartAlarmListener);
Button button2 = (Button)findViewById(R.id.buttonOff);
button2.setOnClickListener(mStopAlarmListener);
}
private OnClickListener mStartAlarmListener = new OnClickListener() {
public void onClick(View v) {
// We want the alarm to go off 30 seconds from now.
//long firstTime = SystemClock.elapsedRealtime();
EditText Ehour = (EditText) findViewById(R.id.hour);
EditText Eminute = (EditText) findViewById(R.id.minute);
CharSequence CharHour = Ehour.getText();
CharSequence CharMinute = Eminute.getText();
int hour = Integer.parseInt(CharHour.toString());
int minute = Integer.parseInt(CharMinute.toString());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
// calendar.add(Calendar.MINUTE, 1);
cal.add(Calendar.SECOND, 10);
mAlarmSender = PendingIntent.getBroadcast(aClockActivity.this,
0, new Intent(aClockActivity.this, Alarm_Broadcast.class), 0);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), mAlarmSender);
// Tell the user about what we did.
Toast.makeText(aClockActivity.this, "The Alarm is Set",
Toast.LENGTH_LONG).show();
}
};
private OnClickListener mStopAlarmListener = new OnClickListener() {
public void onClick(View v) {
// And cancel the alarm.
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.cancel(mAlarmSender);
// Tell the user about what we did.
Toast.makeText(aClockActivity.this, "Setting off the alarm",
Toast.LENGTH_LONG).show();
}
};
Second Class Alarm_Broadcast
public class Alarm_Broadcast extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked", Toast.LENGTH_LONG).show();
}
}
Note: Just ignore the Edittext part in the OnClick() method, I'd use it later on.
Apart from the above problem there are few questions that I would like to ask.
1) How can I implement this app so that when the alarm is set, it can actually run as a service in the notification bar where the original AlarmClock runs. So that even if the app is closed its still running to invoke the alarm message at the right time.
2) I cannot show any Dialog box or can use TTS if the AlarmManager invokes a Class that extends either Service or BroadcastReciever.
3) I would appreciate if some one give me the idea to implement this app, I am sure there are many experts who would have gone through the same application.
Regards
Omayr
Here is some sample code i used in an alarm clock app hope it helps.
To set the alarm:
private void setAlarm(){
Context context = getApplicationContext();
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
myCal = Calendar.getInstance();
myCal.setTimeInMillis(TIME_THE_ALARM_SHOULD_GO_OFF_AS_A_LONG);
mgr.set(AlarmManager.RTC_WAKEUP, myCal.getTimeInMillis(), pi);
Log.i(myTag, "alarm set for " + myCal.getTime().toLocaleString());
Toast.makeText(getApplicationContext(),"Alarm set for " + myCal.getTime().toLocaleString(), Toast.LENGTH_LONG).show();
}
This goes in the onAlarmReceiver class:
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AlarmActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
this will start AlarmActivity whenever it needs to go off. In your case you'd put the toast and speech into the AlarmActivity.
How can I implement this app so that when the alarm is set, it can actually run as a service in the notification bar where the original AlarmClock runs. So that even if the app is closed its still running to invoke the alarm message at the right time.
Do not do this. Having a service stick around in memory 24x7 to watch a clock is a waste of RAM and will get you attacked by task killers, reducing your app's effectiveness. Please stick with AlarmManager.
I cannot show any Dialog box or can use TTS if the AlarmManager invokes a Class that extends either Service or BroadcastReciever.
Start an activity, perhaps a dialog-themed activity.
Just got the answer, whatever service, receiver, activity and etc you are using, you need to register it in your AndroidManifest.xml. Or else it wont work