In the below code, it is doing the main thing what I want so far:
- Repeats every hour at the same time
Can someone verify if or what I need to do to make sure of the following items?
(1) The alarm will eventually be based on days of a month. As long as it goes off when they wake their phone up (to save battery). It is not hour or minute specific. Only day. How can this be achieved?
(2) If the Activity is destroyed or the phone is rebooted, I am not sure if my AlarmManager stays awake?
(3) Lastly, This code is repeated every time the app starts (thus overwriting any existing AlarmManagers; is this a proper way of doing things, or should I be checking to see if an Alarm exists?
for (int i : AlarmDays) {
if (String.valueOf(i) == null ) {
continue;
}
Calendar cal = Calendar.getInstance();
if (cal.get(Calendar.MINUTE) >= i)
cal.add(Calendar.HOUR, 1);
cal.set(Calendar.MINUTE, i);
Intent intent = new Intent(this, TimeAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, i,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
60 * 60 * 1000, pendingIntent);
}
// TimeAlarm.class
public void onReceive(Context context, Intent intent) {
String DebtName = null;
nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
CharSequence from = "Payment Due";
CharSequence message = "Open App and Update your Balance";
Intent notificationIntent = new Intent(context, ManageDebts.class);
notificationIntent.getExtras();
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
Notification notif = new Notification(R.drawable.icon, "Pay "
+ DebtName + " today!", System.currentTimeMillis());
notif.setLatestEventInfo(context, from, message, contentIntent);
notif.defaults = Notification.DEFAULT_SOUND
| Notification.DEFAULT_LIGHTS;
nm.notify(1, notif);
}
And in my application tag in my manifest:
EDIT:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<Application>
<receiver
android:name=".TimeAlarm"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</Application>
The AlarmManager will not persist across the phone being rebooted. However, it will persist across the application being killed by the Android scheduler. Because of this, you basically need to:
Store your schedule somewhere, and come up with a scheduling algorithm for deciding the next time you want an AlarmManager to fire.
Each time you get an alarm, schedule a new one.
Start the AlarmManager on boot, by catching the BOOT_COMPLETED broadcast.
Related
I'm developing my first android app for a client. The launch is scheduled on Saturday, everything works all right... but one thing.
I need the app to connect to the client's website once every 3 days, download events' info, then show a notification and (in some cases) send an email.
What is happening right now is that the app doesn't show any notification, but sends multiple mails every day instead: that should mean that the Alarm fires multiple times per day instead of once every 3.
In my manifest, i have these two receivers:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
[...]
<receiver android:name=".Helper.AlarmDownload"/>
<receiver
android:name=".Helper.AlarmBootReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
AlarmDownload.java does many thing. They all work, so i won't annoy you with the full code. Just the end:
Intent intentToRepeat = new Intent(context, Caricamento.class);
intentToRepeat.putExtra(Costanti.string_notif_idcorso,notifica.getInt(Costanti.sp_notifiche_idcorso,0));
//set flag to restart/relaunch the app
intentToRepeat.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//Pending intent to handle launch of Activity in intent above
PendingIntent pendingIntent =
PendingIntent.getActivity(context, NotificationHelper.ALARM_TYPE_RTC, intentToRepeat, PendingIntent.FLAG_UPDATE_CURRENT);
//Build notification
String titolonotifica = notifica.getString(Costanti.sp_notifiche_titolonotifica,"");
String subtitolo = notifica.getString(Costanti.sp_notifiche_subtitolo,"");
Notification repeatedNotification = buildLocalNotification(context, pendingIntent,titolonotifica,subtitolo).build();
//Send local notification
NotificationHelper.getNotificationManager(context).notify(NotificationHelper.ALARM_TYPE_RTC, repeatedNotification);
[...]
public NotificationCompat.Builder buildLocalNotification(Context context, PendingIntent pendingIntent, String titolo, String subtitolo) {
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(context, "fisicamente")
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.icona_app)
.setContentTitle(titolo)
.setContentText(subtitolo)
//.setStyle(new NotificationCompat.BigTextStyle()
//.bigText(testo))
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_EVENT);
return mBuilder;
}
So, the real issue should be in NotificationHelper.java:
public class NotificationHelper {
public static int ALARM_TYPE_RTC = 100;
private static AlarmManager alarmManager1;
private static PendingIntent alarmIntent1;
public static void scheduleRepeatingRTCNotification(Context context) {
SharedPreferences pref_login = context.getSharedPreferences(Costanti.SP_LOGIN, Context.MODE_PRIVATE);
Boolean primavolta = pref_login.getBoolean("primavolta",false);
//primavolta means first time
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
Random r1 = new Random();
int casuale1 = r1.nextInt(100);
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, casuale1);
if (primavolta && calendar.before(Calendar.getInstance())) calendar.add(Calendar.DAY_OF_MONTH, 1);
//I don't want to show the notification on the first login of the user, so i'm adding one day to the calendar.
Intent intent = new Intent(context, AlarmDownload.class);
alarmIntent1 = PendingIntent.getBroadcast(context, ALARM_TYPE_RTC, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager1 = (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager1.setInexactRepeating(AlarmManager.RTC,
calendar.getTimeInMillis(), 3 * AlarmManager.INTERVAL_DAY, alarmIntent1);
}
This is what i do in MainActivity.java, the first time the user logs in:
Boolean primavolta = preferenze.getBoolean("primavolta",false);
if (primavolta) {
//Apre il drawer
drawer.openDrawer(GravityCompat.START);
//Notifiche
NotificationHelper.scheduleRepeatingRTCNotification(getApplicationContext());
}
The drawer opens only during the first login, so the schedulerepeatingRTCNotification void doesn't fire more than once.
Any idea?
Thank you very much in advance!
Edited: there was a reference to a costant instead of 3 in the code.
I have been fighting with this for quite a while now, I am using alarm manager to schedule an alarm, I have a receiver declared in my manifest file. The alarm and the receiver work as intended while the app is running or in the background, I am unable to get my alarms to fire after the app has been closed by the user. I'm essentially just trying to have local notifications in my application. None of the other "answers" here have been much help. Is it possible to have a local notification fire when the app has been closed?
public static void writtenGoalsNotification(Context context) {
final int _id = 15;
pref = context.getSharedPreferences("userpref", 0);
Notification notification = getNotification("Don't forget to write your daily goals!", context, "none", "Goals");
Intent notificationIntent = new Intent(context, NotificationReceiver.class);
notificationIntent.putExtra(NotificationReceiver.NOTIFICATION_ID, "written goals notification");
notificationIntent.putExtra(NotificationReceiver.NOTIFICATION, notification);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, _id, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Integer hour = pref.getInt(NotificationKeys.Goals.ReminderTime.hour, 10);
Integer minute = pref.getInt(NotificationKeys.Goals.ReminderTime.minute, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.MILLISECOND, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000 * 60 * 60 * 24, pendingIntent);
}
Here is my receiver,
public class NotificationReceiver extends WakefulBroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String NOTIFICATION = "notification";
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
startWakefulService(context, intent);
WakeLocker.acquire(context);
WakeLocker.release();
}
}
This is in my manifest,
<receiver
android:name=".Controllers.NotificationReceiver"
</receiver>
Broadcast receiver is deprecated in API level 26.
The main reason you do not get alram received is because the process of App you are using is finished and cleared if there is low memory in device. Instead you should use service so that it has higher priority.
So for this I suggest you to use BroadcastReceiver class instead of WakeupBroadcastReceiver because android docs says this-
(It is generally not safe to start a service from the receipt of a broadcast, because you don't have any guarantees that your app is in the foreground at this point and thus allowed to do so.)
Thus your process of setting alram may be destroyed. So use BroadcastReceiver.
In manifest do this
<receiver
android:name=".NotificationReceiver"
</receiver>
In my app, I want to do a certain task everyday and after that task is completed I want to trigger multiple notifications at different times (these times will be calculated while doing that task).
After googling I found out that using AlarmManager is my best option:
This class provides access to the system alarm services. These allow you to schedule your application to be run at some point in the future. When an alarm goes off, the Intent that had been registered for it is broadcast by the system, automatically starting the target application if it is not already running. Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
My problems are:
1. Notification is shown only for that first time, not after that.
2. AlarmManager is triggered every time I restart that app and that past notification is shown.
PS.: I am a newbie in android and any help is appreciated
Here is what I tried:
Funtion in my activity from I am setting up this Alarm:
private void handleNotification() {
Intent alarmIntent = new Intent(this, AlarmReciever.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
This is my AlarmReciever class:
public class AlarmReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ArrayList<String> times = new ArrayList();
GPSTracker gpsTracker = new GPSTracker(context);
//calculate the times arraylist
DateFormat format;
Date date = null;
for (String s : times) {
if (hour12) {
format = new SimpleDateFormat("hh:mm a", Locale.ENGLISH);
try {
date = format.parse(s);
} catch (ParseException e) {
}
} else {
format = new SimpleDateFormat("hh:mm", Locale.ENGLISH);
try {
date = format.parse(s);
} catch (ParseException e) {
}
}
Intent alarmIntent = new Intent(context, NotificationReciever.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
Log.d(Constants.LOG_TAG, calendar.getTime().toString());
if (Build.VERSION.SDK_INT < 19) {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
}
}
And this is my NotificationReciever class:
public class NotificationReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Constants.D) Log.d(Constants.LOG_TAG, "NOTIFICATION RECIEVER");
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.sc_logo_final)
.setContentTitle(context.getResources().getString(R.string.app_name))
.setContentText(context.getResources().getString(R.string.app_name));
Intent resultIntent = new Intent(context, NavigationDrawerActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(NavigationDrawerActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
In my AndroidManifest.xml,
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".AlarmReciever">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".NotificationReciever">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
First of all, this code is most likely setting up an alarm to happen at midnight of the current day, which is almost certainly in the past compared to the current time, which means you'll receive the alarm very quickly:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
According to the javadoc for setRepeating():
If the stated trigger time is in the past, the alarm will be triggered
immediately, with an alarm count depending on how far in the past the
trigger time is relative to the repeat interval.
Your Alarm does not repeat because you're using the flag INTERVAL_DAY, which only works with setInexactRepeating().
If you want to run something at midnight of the next day, you will need to add one day to the calendar. You might also consider setting the seconds field to 0 as well.
If you're registering the alarm every time the app starts, you'll keep getting that early alarm every time. Also according to the javadoc:
If there is already an alarm scheduled for the same IntentSender, it
will first be canceled.
The alarm is not repeating because you're passing an interval that is only valid for setInexactRepeating().
I have a small problem about alarmmanager but I couldn't find a answer which fits to my code.
My question is simple. I have a list of alarms which is set to future. While my app is running, I can recieve Notification.
But when I close my app, It doesn't send notification to me and if I run my app again, past notifications can be seen in notification center.
Here is my codes.
In MainActivity.java I use this method which can take a Person List and sets alarm of each of Person. I run this method in onCreate()
private void createScheduledNotification(List<Person> people)
{
for(int i = 0; i<people.size();i++) {
// Get new calendar object
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, people.get(i).getMonth());
calendar.set(Calendar.DAY_OF_MONTH, people.get(i).getDay());
calendar.set(Calendar.YEAR, Calendar.getInstance().get(Calendar.YEAR));
calendar.set(Calendar.HOUR_OF_DAY, people.get(i).getHour());
calendar.set(Calendar.MINUTE, people.get(i).getMinute());
calendar.set(Calendar.SECOND, 0);
// Retrieve alarm manager from the system
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(getBaseContext().ALARM_SERVICE);
// Every scheduled intent needs a different ID, else it is just executed once
int id = (int) System.currentTimeMillis();
// Prepare the intent which should be launched at the date
Intent intent = new Intent(this, TimeAlarm.class);
intent.putExtra("person", people.get(i));
// Prepare the pending intent
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Register the alert in the system. You have the option to define if the device has to wake up on the alert or not
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
And I have a TimeAlarm class which extends BroadcastReciever.
public class TimeAlarm extends BroadcastReceiver {
private Person person;
#Override
public void onReceive(Context context, Intent paramIntent) {
Bundle bundle = paramIntent.getExtras();
person = (Person) bundle.getSerializable("person");
// Request the notification manager
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Create a new intent which will be fired if you click on the notification
Intent intent = new Intent("android.intent.action.VIEW");
// Attach the intent to a pending intent
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Create the notification
Notification notification = new Notification(R.drawable.logo24px, "Never Forget", System.currentTimeMillis());
//
notification.setLatestEventInfo(context, "It's " + person.getName() + " " + person.getSname() + "'s Birthday!", "Celebrate his/her birthday! ",pendingIntent);
// Fire the notification
notificationManager.notify(1, notification);
}
}
Also I add these lines to AndroidManifest.xml
<receiver android:name=".TimeAlarm" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
It works fine when app is running but when I close my app in Active Applications page, it doesn't send any notification.
Try use this when you create your intent
Bundle extras = new Bundle();
extras.putSerializable("person", people.get(i));
intent.putExtras(extras);
And in your BroadcastReciver check if the action is a boot completed action. (it could also be your alarm).
#Override
public void onReceive(Context context, Intent paramIntent) {
//CHECK IF IS BOOT COPLETED
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
/* Setting the alarm here Alarm are automatically cleaned on phone shutdown*/}
else{
Bundle bundle = paramIntent.getExtras();
person = (Person) bundle.getSerializable("person");
// Request the notification manager
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Create a new intent which will be fired if you click on the notification
Intent intent = new Intent("android.intent.action.VIEW");
// Attach the intent to a pending intent
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Create the notification
Notification notification = new Notification(R.drawable.logo24px, "Never Forget", System.currentTimeMillis());
//
notification.setLatestEventInfo(context, "It's " + person.getName() + " " + person.getSname() + "'s Birthday!", "Celebrate his/her birthday! ",pendingIntent);
// Fire the notification
notificationManager.notify(1, notification);}
}
}
Also check this
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
because it seems that you are continusly updating the same intent, is what you want?
Edit:
Sorry I didn't remember to insert it, your reciever declaration sholuld be like this.
<receiver android:name=".TimeAlarm"
android:process=":remote"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I'm developing a live wallpaper for Android. To refresh the wallpaper at set times I use AlarmManager. Most of the times this works great, but occasionally my alarm isn't received. On top of that I can't replicate this behaviour, it just randomly happens. I've run into this using at least 3 ROMs.
Now for the code.
I use this PendingIntent:
mRefreshIntent = new Intent()
.setComponent(new ComponentName(mContext, RefreshBroadcastReceiver.class))
.setAction("my.package.name.REFRESH_WALLPAPER");
mPendingRefreshIntent = PendingIntent.getBroadcast(
mContext,
0,
mRefreshIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
This is my code to set the alarm:
mAlarmManager.set(AlarmManager.RTC_WAKEUP, time, mPendingRefreshIntent);
where time is the UTC time in milliseconds. I often verified if the alarm is set as intended using adb shell dumpsys alarm, which it is.
The receiving side:
public class RefreshBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("DayNight", "onReceive ; " + System.currentTimeMillis());
DayNightService.refresher.refresh();
Log.d("DayNight", "onReceive done; " + System.currentTimeMillis());
}
}
Associated manifest lines:
<application>
...
<receiver
android:name="RefreshBroadcastReceiver">
<intent-filter>
<action android:name="my.package.name.REFRESH_WALLPAPER" />
</intent-filter>
</receiver>
...
</application>
Alarms which are not fired always exist in the queue (dumpsys alarms) beforehand, and are not in the alarm log afterwards. Seems like they get 'lost' at T minus zero.
I will be very happy if one of you can solve this problem for me.
I use following code:
Intent intent = new Intent(ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);
Log.d(LOG_TAG, "pending intent: " + pendingIntent);
// if no intent there, schedule it ASAP
if (pendingIntent == null) {
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// schedule new alarm in 15 minutes
alarmService.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(),300000, pendingIntent);
Log.d(LOG_TAG, "scheduled intent: " + pendingIntent);
}
Note, that I request inexact repeating alarm and RTC ( not RTC_WAKEUP ) - if phone is sleeping deep inside jeans pocket, user is not interested on changes of your live wallpaper - no need to waste battery juice and wake phone up
You may also need to register boot complete broadcast receiver to start update scheduling
on reboot.