Android AlarmManager only sending last scheduled notification - android

I am creating a research app that should prompt the user 4 times a day to enter their mood - by sending a notification, which when clicked launches the correct Activity. I am able to schedule these notifications using AlarmManager, however only the last scheduled notification ever shows. So although I schedule them for 9AM, 2PM, 5PM, and 8PM, it only ever sends a notification at 8PM.
How can I get all of the scheduled notifications to show?
Here is my code for setting (one of) the alarms (from a notification manager class). Note that al alarms are set using the same instance of AlarmManager:
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, 9);
cal.set(Calendar.MINUTE, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), createPendingIntent(9, this));
Here is the createPendingIntent method (in the same notification manager class):
public static PendingIntent createPendingIntent(int hour, Context c){
Intent notificationIntent = new Intent(c, AlarmBroadcastReceiver.class);
notificationIntent.putExtra("time", hour);
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0 , notificationIntent , PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
Here is the BroadcastReceiver for the alarm:
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationSender.createNotification(context);
}
}
And finally the createNotification method:
public static void createNotification(Context c){
Log.e("notif?", "creating");
Intent intent = new Intent(c, UpdateMoodActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
int notificationId = new Random().nextInt();
PendingIntent pendingIntent = PendingIntent.getActivity(c, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(c, "com.lizfltn.phdapp.notifChannelID")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("SoftMood")
.setContentText("Please record your mood")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(c);
notificationManager.notify(notificationId, builder.build());
}
Yes I know this isn't the best-practice way of doing things, or even the neatest, but unfortunately I need to get code working ahead of writing good code :P
I've tried various configurations of setting the alarm, e.g. using elapsed realtime instead of RTC, only setting the alarm, setting the exact alarm, etc, but there might be something fundamental I'm not understanding about how those work.
Any help appreciated!

Can you try with same id in pending intent and notify.?
Notification id in createNotification() method is random id.
int notificationId = new Random().nextInt();
and id used in createPendingIntent method is 0.
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0 , notificationIntent , PendingIntent.FLAG_UPDATE_CURRENT);
Can you try with using same value for second parameter of getBroadcast?

Related

Android local notification doesn't arrive every time

I want my user to set a time to receive a daily reminder from my app. In my ReminderActivity I create the PendingIntent and the Alarm Manager, and then in my Alarm Receiver class I create the notification inside onReceive(). I tried both the FLAG_CANCEL_CURRENT and FLAG_UPDATE_CURRENT flags when creating the pending intent but still when I am testing the app and changing the reminder time then sometimes the notification doesn't arrive at all, or it arrives only when the app is running in the background and the screen is on. I would greatly appreciate any thought or ideas.
ReminderActivity code:
private void setNotification() {
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, chosenHour);
calendar.set(Calendar.MINUTE, chosenMinute);
calendar.set(Calendar.SECOND, 0);
//if user sets the alarm after their preferred time has already passed that day
if(now.after(calendar)) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
Intent intent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(ReminderActivity.this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager = (AlarmManager) getSystemService(Activity.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
Alarm Receiver code:
#Override
public void onReceive(Context context, Intent intent) {
Bitmap largeLogo = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ptwired_logo);
//create local notification
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, MainActivity.class);
//notificationIntent.putExtra("FromPTWired", true); //to track if user opens the app from the daily digest notification
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ptwired_logo)
.setLargeIcon(largeLogo)
.setContentTitle(context.getResources().getString(R.string.app_name))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setContentText(REMINDER_TEXT)
.setAutoCancel(true)
.setOngoing(false)
.build();
notificationManager.notify(1, notification);
}
}
Probably an issue of Doze mode, take a look in Android restriction:
Doze restrictions
The following restrictions apply to your apps while in Doze:
Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.

Displaying multiple notifications at user-defined times

I've been programming in Android for over a year but have never used notifications before, which I need for one of my apps.
In the app, there are events that can be set at different times. Obviously, the user can choose to change these times or add/remove events.
I plan to use notifications to notify the user 5 minutes before their event starts.
I've read through the Android developer docs for Building a Notification and Services (which I am also new to). I have decided to use Services because I figured that the notification would need to be shown even when the app not running. To help me, I have been referring to one particular SO answer as guidance.
I begun by experimenting a little with the notification builder classes in my NotificationService class like so:
public class NotificationService extends IntentService {
private static final int NOTIFICATION_ID = 1;
public NotificationService() {
super(NotificationService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
showNotification();
}
private void showNotification() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle("Test notification")
.setSmallIcon(R.drawable.ic_event_black_24dp)
.setContentText("Test description")
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID, builder.build());
}
}
I also use the following to start this Service in the splash screen of my app:
Intent serviceIntent = new Intent(this, NotificationService.class);
startService(serviceIntent);
To display notifications at specific times, I've read about AlarmManager, mainly through SO questions like this one. I also know that to display multiple notifications, I would need different notification ids (like my constant NOTIFICATION_ID).
However, what I am unsure of is dynamically updating the times that notifications would be shown each time an event is added, removed, or its times changed.
Could someone provide me some guidance on how I could achieve this?
You implement notification part. For notify user at Specific time you should set AlarmManager. I paste whole code you need then explain each part:
public class AlarmReceiver extends WakefulBroadcastReceiver {
AlarmManager mAlarmManager;
PendingIntent mPendingIntent;
#Override
public void onReceive(Context context, Intent intent) {
int mReceivedID = Integer.parseInt(intent.getStringExtra(AddReminderActivity.EXTRA_REMINDER_ID));
// Get notification title from Reminder Database
ReminderDatabase rb = new ReminderDatabase(context);
ApiReminderModel reminder = rb.getReminder(mReceivedID);
String mTitle = reminder.getName();
// Create intent to open ReminderEditActivity on notification click
// handling when you click on Notification what should happen
Intent editIntent = YourActivity.createActivity(context, reminder.getChannelId(), reminder.getStartTime());
PendingIntent mClick = PendingIntent.getActivity(context, mReceivedID, editIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Create Notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_logo))
.setSmallIcon(R.drawable.ic_logo)
.setContentTitle(context.getResources().getString(R.string.app_name))
.setTicker(mTitle)
.setContentText(mTitle)
.setContentIntent(mClick)
.setSound(ringtoneUri)
.setAutoCancel(true)
.setOnlyAlertOnce(true);
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.notify(mReceivedID, mBuilder.build());
}
public void setAlarm(Context context, Calendar calendar, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Put Reminder ID in Intent Extra
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(AddReminderActivity.EXTRA_REMINDER_ID, Integer.toString(ID));
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Calculate notification time
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using notification time
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + diffTime, mPendingIntent);
// Restart alarm if device is rebooted
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
public void cancelAlarm(Context context, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Cancel Alarm using Reminder ID
mPendingIntent = PendingIntent.getBroadcast(context, ID, new Intent(context, AlarmReceiver.class), 0);
mAlarmManager.cancel(mPendingIntent);
// Disable alarm
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
As you see we have setAlarm which notify users at specific time. I also pass calendar instance which is initiated before ( assign a time which user should be notify).
Calendar mCalendar = Calendar.getInstance();
mCalendar.add(Calendar.DAY_OF_YEAR, 7);// assume you want send notification 7 days later
new AlarmReceiver().setAlarm(getApplicationContext(), mCalendar, id);
We have another method cancelAlarm. If you want to delete a Alaram just pass unique ID of Alarm (Which already used for creation of Alarm).
Also don't forget to add this Service to your AndroidManifest.xml:
<receiver android:name=".service.AlarmReceiver" />
There is only on thing remain When you reboot your device you should set AlarmsManager again so you need a BootRecivier service.

How to cancel a repeating notification on a particular date

Well I have tried enough to look for the answer to the question mentioned above, but my efforts have been futile so far.
I have created an alarm with the help of the alarmmanager class which will fire up the notification at regular intervals of time(probably about 5 days).
Below is the code for the implementation of the alarm happening inside onClick() of a button.
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent("android.media.action.DISPLAY_NOTIFICATION");
notificationIntent.addCategory("android.intent.category.DEFAULT");
PendingIntent broadcast = PendingIntent.getBroadcast(this, 100, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar cal = Calendar.getInstance();
if(fromDateEtxt.getText().toString().length()>0) {
cal.add(Calendar.HOUR_OF_DAY, 10);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), 5 * 24 * 60 * 60 * 1000, broadcast);
}
The code for the broadcast receiver.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent notificationIntent = new Intent(context, NotificationActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(NotificationActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Notification notification = builder.setContentTitle("Demo App Notification")
.setContentText("New Notification From Demo App..")
.setTicker("New Message Alert!")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent).build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}}
The onClick() method apart from starting of the alarm changes the activity also. Now the problem I am facing is I dont know really how to stop the repeating alarm. I want to stop the alarm on a particular date. Secondly, I was confused whether to use the alarm.cancel for cancelling the alarm or to use another alarm for cancellation of the previous alarm as shown here. Apart from this, I wanted to know if the alarm could be cancelled from another activity or does the point seems unnecessary and the limit to the date could be set beforehand?

notification showing up instantly

am trying to schedule a notification with desired time and un the below code my desired time if after 10 seconds but i don't know why its showing up the notification instantly , am i doing anything wrong ? or missing anything please correct me if am wrong anywhere , and am using BlueStacks Emulator for testing (built version 4.4.2 Api 19)
notification = new NotificationCompat.Builder(this);
notification.setAutoCancel(true);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent("android.media.action.DISPLAY_NOTIFICATION");
notificationIntent.addCategory("android.intent.category.DEFAULT");
PendingIntent broadcast = PendingIntent.getBroadcast(this, 100, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), broadcast);
// why its showing up instantly insted of after 10 seconds
//alarmManager.setExact(AlarmManager.RTC_WAKEUP,20,broadcast);
Intent intent = new Intent(this , MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent , PendingIntent.FLAG_UPDATE_CURRENT);
Intent switchIntent = new Intent(this, switchButtonListener.class);
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 0, switchIntent, 0);
notification.setSmallIcon(R.drawable.ok);
notification.setWhen(20);
notification.setTicker("you've got a meesage");
notification.setContentTitle("new message");
notification.setContentText("wanna take a ride?");
// notification.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(uniqueID, notification.build());
notification showing up instantly
When you call notificationManager.notify() in your last line, it displays the notification immediately.
I assume that you wanted to use an AlarmManager to display a notification and you don't quite understand what it does. An AlarmManager is used schedule an Intent to be broadcasted. An Intent can be used to perform a variety of task such as starting an Activity or Service. As far as i know it is not possible to use an Intent to display notification.
What you should be looking at is to use postDelayed() method in Handler class. For example:
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
// Create your notification using NotificationCompat.Builder
// and call notificationManager.notify()
}
};
handler.postDelayed(r, /*time to delay for in ms*/);
Edit: If you really want to use AlarmManager and broadcast to display a notification, you will need to extend a BroadcastReceiver and have it listen for your PendingIntent broadcast. Next, you will schedule the PendingIntent to be broadcasted using AlarmManager. When the AlarmManager fire off the PendingIntent after 10 seconds, your BroadcastReceiver will receive the broadcast and call notificationManager.notify() to display the notification. This is quite a roundabout way of displaying notification.

Alarm + Notification: nothing happens

I am trying to implement an alarm that would display a notification everyday at the same hour of the day.
Here is the function I'm calling in my activity:
private void restartNotify() {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// Intent for our BroadcastReceiver
Intent intent = new Intent(this, AlarmReceiver.class);
// PendingIntent for AlarmManager
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT );
// In case we have already set up AlarmManager, we cancel.
am.cancel(pendingIntent);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+10000, pendingIntent);
}
And here is my broadcast receiver class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.icon_notif, context.getString(R.string.NotificationLaunchMssg), System.currentTimeMillis());
// This is intent we want to launch when user clicks on the notification.
Intent intentTL = new Intent(context, MyClass.class);
notification.setLatestEventInfo(context, context.getString(R.string.NotificationTitle), context.getString(R.string.NotificationBody),
PendingIntent.getActivity(context, 0, intentTL, PendingIntent.FLAG_CANCEL_CURRENT));
nm.notify(1, notification);
//Here we set next notification, in day interval
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+10000, pendingIntent);
}
}
As you can see in this code I am using a test value (+10000 milliseconds) because I am simply trying to trigger the alarm 10 seconds after my app has started. But it doesn't work, nothing is displayed.
I don't know if the alarm has a problem, or the notification, nothing is happening.
Do you have any idea why?
Thanks for your help
EDIT: after adding some test code in AlarmReceiver method, it turns out this code is never run. So I probably don't call it properly, what is wrong?
Do not use this approach try setInexactRepeating(...) or setRepeating(...) instead. Why are u giving extra work to the BroadcastReceiver for setting alarm every time it receives the intent.
here is a little code:
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
0, 10000, pendingIntent);
// The pending intent will the same as yours. 10000 is the
// interval for between consecutive alarms
as azertiti mentioned in comments " By the time it's registered that time will already be in the past." so use 0 or System.currentTimeMillis().

Categories

Resources