Setting repeating alarm when creating Application - why does it trigger immediately - android

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.

Related

Xamarin AlarmManager not firing when app sleeps

I have following code to fire an alarm at exact time. When my app goes to sleep/background, Alarm does not FIRE, however as soon as I unlock my phone, then it fires right away.
Intent i = new Intent(this, typeof(MyReceiver));
i.PutExtra("Speaker", txtSpeaker.Text);
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, i, 0);
string _date = DateTime.Today.ToString("MM-dd-yyyy") ;
string _time = tpick.Hour + ":" + tpick.Minute;
DateTime scheduleAt = Convert.ToDateTime(_date).Add(TimeSpan.Parse(_time));
DateTimeOffset dateOffsetValue = DateTimeOffset.Parse(scheduleAt.ToString());
var millisec = dateOffsetValue.ToUnixTimeMilliseconds();
AlarmManager alarmManager = (AlarmManager)GetSystemService(AlarmService);
alarmManager.SetExact(AlarmType.RtcWakeup, millisec, pi);
and here is my Receiver Class...
[BroadcastReceiver]
public class MyReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("FIRED");
String result = intent.Extras.GetString("Speaker");
Toast.MakeText(context, "Alarm Ringing!", ToastLength.Short).Show();
}
}
If the App is running on API 23 or newer, you might want to look into using the SetExactAndAllowWhileIdle method. According to the documentation it appears to me that this method will ignore whether the Device is in some low-power state or doze is enabled.

New alarm with different data overrides already set alarm

I'm creating a simple app that will turn my wifi off/on at specified time in future. For example I have wifi on and I want to switch its state (turn it off) at 10PM and switch back and 8 AM (Turn on).
To do that, I've written some block of code which has one bug.
Well, when I set first alarm (let's accord to the example above) at 10PM and second at 8AM only the second one will fire.
According to the answer here:
Editing scheduled pending intends
about pending intents I checked those alarms' pending intents while setting them and they were different.
Okay, I'll provide some code, I will not give whole bunch of code to set up calendar because the bug is not there.
WiFi.class
//This class also stores and loads scheduled alarm from database,
//that's why here is variable Uri = mUri.
private void setAlarm(){
ContentValues values = new ContentValues();
values.put(AlarmReminderEntry.KEY_TITLE, title);
values.put(AlarmReminderEntry.KEY_DATE, mDate);
values.put(AlarmReminderEntry.KEY_TIME, mTime);
values.put(AlarmReminderEntry.KEY_REPEAT, repeat);
values.put(AlarmReminderEntry.KEY_YEAR, mYear);
values.put(AlarmReminderEntry.KEY_MONTH, mMonth);
values.put(AlarmReminderEntry.KEY_DAY, mDay);
values.put(AlarmReminderEntry.KEY_HOUR, mHour);
values.put(AlarmReminderEntry.KEY_MINUTE, mMinute);
values.put(AlarmReminderEntry.KEY_REPEAT_NO, mRepeatNo);
if (mUri == null) {
Uri newUri =
getContentResolver().insert(AlarmReminderEntry.CONTENT_URI, values);
if (newUri == null) {
Toast.makeText(context, "error saving alarm",
Toast.LENGTH_SHORT).show();
} else {
//WiFiScheduler() is an instance of another class, see code below
//setAlarm(Context context, long timeInMilis, Uri uri)
new WiFiScheduler().setAlarm(getApplicationContext(),
calendar.getTimeInMillis(), mUri);
Toast.makeText(context, "Alarm will fire one time
only", Toast.LENGTH_SHORT).show();
Log.v("Alarm time",
String.valueOf(calendar.getTime()));
}
WifiScheduler.class --> class where the method setAlarm is called from.
public class WiFiScheduler {
public void setAlarm(Context context, long alarmTime, Uri
reminderTask) {
AlarmManager alarmManager = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
Log.v("AlarmManager", "Initializing AM");
//Here in PendingIntent instance there is another class called called
// WiFiService
PendingIntent operation =
WiFiService.getReminderPendingIntent
(context,reminderTask);
if (Build.VERSION.SDK_INT >= 23) {
assert alarmManager != null;
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
alarmTime, operation);
} else {
assert alarmManager != null;
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
alarmTime,operation);
}
}
}
And finally WiFiService.class
public class WiFiService extends IntentService {
private static final String TAG = WiFiService.class.getSimpleName();
public static PendingIntent getReminderPendingIntent(Context context,
Uri uri) {
Intent action = new Intent(context, WiFiService.class);
action.setData(uri);
Log.v(TAG, "uri passed into intent");
String pi = String.valueOf(PendingIntent.getService(context, 0,
action, PendingIntent.FLAG_UPDATE_CURRENT));
Log.v(TAG, pi); <--
Those outputs of 2 alarms I'll give in the end of this post, but they were different
return PendingIntent.getService(context, 0, action,
PendingIntent.FLAG_UPDATE_CURRENT);
}
public WiFiService() {
super(TAG);
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
WifiManager wifiManager = (WifiManager)
getApplicationContext().getSystemService(WIFI_SERVICE);
if (wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(false);
Log.v(TAG, "Wifi is turning off");
} else {
wifiManager.setWifiEnabled(true);
Log.v(TAG, "Wifi is turning on");
}
Calendar calendar = Calendar.getInstance();
int h = calendar.get(Calendar.HOUR_OF_DAY);
int m = calendar.get(Calendar.MINUTE);
int ms = calendar.get(Calendar.SECOND);
Log.v("Time", String.valueOf(h) + ":" + String.valueOf(m) + ":" +
String.valueOf(ms));
}
}
WiFiService.class defined in Manifest as:
service android:name=".WiFiScheduler.WiFiService"
android:exported="false"
No brackets above, page didn't want to accept them, in the code obviously they are.
And now outputs of PendingIntent.getBroadcast, read twice,
first after first alarm was set and second after second was set.
V/WiFiService: PendingIntent{d3aacca: android.os.BinderProxy#dd4e3b}
V/WiFiService: PendingIntent{3acdbb: android.os.BinderProxy#d5ac2d8}
So, where may I did an error?
And for the end, may I ask where can I find Oreo stock alarm app source code or app alike? (It must be written for Marshmallow and above, most apps on GitHub are written for Lollipop and above, I found just 2 for Nougat)
Bests
Check the Uri that you put in the Intent and ensure that the 2 Uris are different for the 2 different calls. Also, make absolutely sure that the times are correct that you pass to AlarmManager.
The other thing you can do is, after you set each alarm, do adb shell dumpsys alarm and check that the alarm has been set with the correct values. See this question if you need help understanding how to read the output of adb shell dumpsys alarm

Android multiple alarms not working

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.

How to use Alarm Manager to schedule my android app to run in especial time?

I am new with android and I wanna make a alarm app that gets a time from user and make android system to run application in that time.Now I calculate the time between current and the entered time and use the following code to sleep app but doesn't work when my app close or even minimized:
start_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
TimePicker tp = (TimePicker) findViewById(R.id.timepicker1);
int hour = tp.getCurrentHour();
int min = tp.getCurrentMinute();
Integer res = min + hour*60;
Calendar c = Calendar.getInstance();
cur_hour = c.get(Calendar.HOUR_OF_DAY);
cur_min = c.get(Calendar.MINUTE);
Integer cur_res = cur_min + cur_hour*60;
if(cur_res > res)
{
res_min =1440-( cur_res - res);
}
else
{
res_min = res-cur_res;
}
res_min *= 60000;
new Handler().postDelayed(new Thread(){
#Override
public void run() {
super.run();
PlayMusic();
}
},res_min);
}
});
I searched hardly for solution and I find out that Alarm Manager is the answer but I couldn't find a proper code to work in this situation.I'm looking for a simple way to perform that.I don't know if there is a better way or not.
Thanks!
Did you try to use the AlarmManager? If you have, post the code that you've tried.
Look at the Google Developer API for classes such as these. They are fantastically documented.
http://developer.android.com/reference/android/app/AlarmManager.html
An example:
//You must set permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<receiver android:process=":remote" android:name="Alarm"></receiver>
//In your code
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(), milli, sec, min, pi);

WakefulIntentService starts immediately after scheduling

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.

Categories

Resources