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
Related
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.
I'm trying to set an alarm to fire every 5 minutes.
This is the code for setting the alarm :
#Override
public void scheduleAlarmManager() {
Timber.i("After SignIn sets AlarmManager");
// broadcast
Intent intent = new Intent(this, PatientAlarmReceiver.class);
intent.setAction(PATIENT_START_ALARM_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, REQUEST_CODE, intent, 0);
// and set alarmManager
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar currentCal = Calendar.getInstance();
long currentTIme = currentCal.getTimeInMillis();
// if there's not an Alarm already set then set one
if (!isAlarmSet(this)) {
Timber.i("Alarm not set - so set one");
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
currentTIme + TWO_MINS_DURATION, TWO_MINS_DURATION, pendingIntent);
}
}
and I can verify that I set the alarm correctly since I see in my logcat the messages I log with Timber.
My Receiver class is :
public class PatientAlarmReceiver extends BroadcastReceiver {
public static final String TAG = "PATIENT-ALARM-RECEIVER";
public static final String PATIENT_START_ALARM_ACTION = "bp.headsup.receivers.alarm.patient";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Inside OnReceive Patient");
Timber.i("Inside OnReceive Patient");
if (intent == null || intent.getAction() == null) {
return;
}
String action = intent.getAction();
if (PATIENT_START_ALARM_ACTION.equalsIgnoreCase(action)) {
onStartCheckForConnectionRequest(context);
}
}
/**
* If is connected to network starts services
*/
private void onStartCheckForConnectionRequest(Context context) {
NetworkUtils networkUtils = new NetworkUtils(context);
if (networkUtils.isNetworkConnected()) {
Intent checkForConnRequestIntent = new Intent(context, PatientCheckForConnectionRequestService.class);
context.startService(checkForConnRequestIntent);
Timber.i("Starts Service From PatientALARMMANAGER");
}
}
}
And I have declared in Manifest :
<!-- Receivers -->
<receiver
android:name="bp.headsup.receivers.PatientAlarmReceiver" />
Also if I run : adb shell dumpsys alarm
I can see :
ELAPSED_WAKEUP #0: Alarm{42d804e8 type 2 bp.headsup.mock}
operation=PendingIntent{42d0c230: PendingIntentRecord{42d0f000 bp.headsup.mock broadcastIntent}}
Mock in the above response is the sourceSet I'm using - dont know if it has anything to do with this I just mention it.
The problem is I never read in logcat the messages I have in onReceive on my Receiver class, and obviously no service starts. Anyone can help with that ? I'm using a device which runs with kitKat 4.4 (api 19) but I have tried it with an emulator too and the result was the same.
You're setting an ELAPSED_REALTIME alarm, which is based on the time since the last boot. However, you're passing it a starting time based on the "wall clock", so your alarm is actually set quite far in the future.
You can either change the alarm to an RTC type, or get the starting time from SystemClock.elapsedRealtime(). Given your described behavior, keeping the elapsed type and correcting the starting time seems appropriate.
I'm trying to set an alarm to fire every 5 minutes.
This is the code for setting the alarm :
#Override
public void scheduleAlarmManager() {
Timber.i("After SignIn sets AlarmManager");
// broadcast
Intent intent = new Intent(this, PatientAlarmReceiver.class);
intent.setAction(PATIENT_START_ALARM_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, REQUEST_CODE, intent, 0);
// and set alarmManager
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar currentCal = Calendar.getInstance();
long currentTIme = currentCal.getTimeInMillis();
// if there's not an Alarm already set then set one
if (!isAlarmSet(this)) {
Timber.i("Alarm not set - so set one");
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
currentTIme + TWO_MINS_DURATION, TWO_MINS_DURATION, pendingIntent);
}
}
and I can verify that I set the alarm correctly since I see in my logcat the messages I log with Timber.
My Receiver class is :
public class PatientAlarmReceiver extends BroadcastReceiver {
public static final String TAG = "PATIENT-ALARM-RECEIVER";
public static final String PATIENT_START_ALARM_ACTION = "bp.headsup.receivers.alarm.patient";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Inside OnReceive Patient");
Timber.i("Inside OnReceive Patient");
if (intent == null || intent.getAction() == null) {
return;
}
String action = intent.getAction();
if (PATIENT_START_ALARM_ACTION.equalsIgnoreCase(action)) {
onStartCheckForConnectionRequest(context);
}
}
/**
* If is connected to network starts services
*/
private void onStartCheckForConnectionRequest(Context context) {
NetworkUtils networkUtils = new NetworkUtils(context);
if (networkUtils.isNetworkConnected()) {
Intent checkForConnRequestIntent = new Intent(context, PatientCheckForConnectionRequestService.class);
context.startService(checkForConnRequestIntent);
Timber.i("Starts Service From PatientALARMMANAGER");
}
}
}
And I have declared in Manifest :
<!-- Receivers -->
<receiver
android:name="bp.headsup.receivers.PatientAlarmReceiver" />
Also if I run : adb shell dumpsys alarm
I can see :
ELAPSED_WAKEUP #0: Alarm{42d804e8 type 2 bp.headsup.mock}
operation=PendingIntent{42d0c230: PendingIntentRecord{42d0f000 bp.headsup.mock broadcastIntent}}
Mock in the above response is the sourceSet I'm using - dont know if it has anything to do with this I just mention it.
The problem is I never read in logcat the messages I have in onReceive on my Receiver class, and obviously no service starts. Anyone can help with that ? I'm using a device which runs with kitKat 4.4 (api 19) but I have tried it with an emulator too and the result was the same.
You're setting an ELAPSED_REALTIME alarm, which is based on the time since the last boot. However, you're passing it a starting time based on the "wall clock", so your alarm is actually set quite far in the future.
You can either change the alarm to an RTC type, or get the starting time from SystemClock.elapsedRealtime(). Given your described behavior, keeping the elapsed type and correcting the starting time seems appropriate.
I'm trying to set an alarm to fire every 5 minutes.
This is the code for setting the alarm :
#Override
public void scheduleAlarmManager() {
Timber.i("After SignIn sets AlarmManager");
// broadcast
Intent intent = new Intent(this, PatientAlarmReceiver.class);
intent.setAction(PATIENT_START_ALARM_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, REQUEST_CODE, intent, 0);
// and set alarmManager
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar currentCal = Calendar.getInstance();
long currentTIme = currentCal.getTimeInMillis();
// if there's not an Alarm already set then set one
if (!isAlarmSet(this)) {
Timber.i("Alarm not set - so set one");
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
currentTIme + TWO_MINS_DURATION, TWO_MINS_DURATION, pendingIntent);
}
}
and I can verify that I set the alarm correctly since I see in my logcat the messages I log with Timber.
My Receiver class is :
public class PatientAlarmReceiver extends BroadcastReceiver {
public static final String TAG = "PATIENT-ALARM-RECEIVER";
public static final String PATIENT_START_ALARM_ACTION = "bp.headsup.receivers.alarm.patient";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Inside OnReceive Patient");
Timber.i("Inside OnReceive Patient");
if (intent == null || intent.getAction() == null) {
return;
}
String action = intent.getAction();
if (PATIENT_START_ALARM_ACTION.equalsIgnoreCase(action)) {
onStartCheckForConnectionRequest(context);
}
}
/**
* If is connected to network starts services
*/
private void onStartCheckForConnectionRequest(Context context) {
NetworkUtils networkUtils = new NetworkUtils(context);
if (networkUtils.isNetworkConnected()) {
Intent checkForConnRequestIntent = new Intent(context, PatientCheckForConnectionRequestService.class);
context.startService(checkForConnRequestIntent);
Timber.i("Starts Service From PatientALARMMANAGER");
}
}
}
And I have declared in Manifest :
<!-- Receivers -->
<receiver
android:name="bp.headsup.receivers.PatientAlarmReceiver" />
Also if I run : adb shell dumpsys alarm
I can see :
ELAPSED_WAKEUP #0: Alarm{42d804e8 type 2 bp.headsup.mock}
operation=PendingIntent{42d0c230: PendingIntentRecord{42d0f000 bp.headsup.mock broadcastIntent}}
Mock in the above response is the sourceSet I'm using - dont know if it has anything to do with this I just mention it.
The problem is I never read in logcat the messages I have in onReceive on my Receiver class, and obviously no service starts. Anyone can help with that ? I'm using a device which runs with kitKat 4.4 (api 19) but I have tried it with an emulator too and the result was the same.
You're setting an ELAPSED_REALTIME alarm, which is based on the time since the last boot. However, you're passing it a starting time based on the "wall clock", so your alarm is actually set quite far in the future.
You can either change the alarm to an RTC type, or get the starting time from SystemClock.elapsedRealtime(). Given your described behavior, keeping the elapsed type and correcting the starting time seems appropriate.
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.