I'm trying to set events with AlarmManager, but I'm getting notifications only when the app is opened. I tried with set, setExact and setExactAndAllowWhileIdle but with no luck : when i close the app, even when I don't turn off the screen, I won't get notified.
Adding notification
public void addNotification(Task task) {
Intent intent = new Intent(context, NotificationPublisher.class);
intent.putExtra("NOTIFICATION",getNotification(task));
intent.putExtra("TASK_ID",(int)task.getTaskId());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if(DateUtility.isTimePast(new Time(task.getNotificationTime()))) // if missed, notify now
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, today.getTime()+3000, pendingIntent);
else
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, task.getNotificationTime(), pendingIntent);
}
Notification publisher , called by the alarm manager
public class NotificationPublisher extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra("NOTIFICATION");
int id = intent.getIntExtra("TASK_ID", 0);
if(notification!=null&&id!=0)
notificationManager.notify(id, notification);
}
}
My custom classes or methods aren't involved, since I'm getting notified correctly when my app isn't closed.
I set my alarms again on boot with RECEIVE_BOOT_COMPLETED too, which notifies me of late notifications only (if my phone was turned off during an event, I will be notified at next boot). So alarms are set correctly, but a few seconds later it dies. Thanks for your help!
Related
I have a kind of weird problem. I know that I am missing something but I don't know what.
I am adding approximatly 5 notifications per day that I create each two to three hours.
If we have the scenario below:
Notification 1 is created at 8:00 and should be fired at 12:00.
When Notification 1 is received, it is processed and Notification 2 is created and needs to be fired at 14:00.
When Notification 2 is received, it is processed and Notification 3 is created and should be fired at 17:00
When Notification 3 is received, it is processed and Notification 4 is created and should be fired at 8:00 the next Day.
Notification 4 will not be received until I manually unlock/unsleep the phone. The time of the notification is 8:00 even if I unlocked the phone at 9:00.
So my problem is when the phone goes to sleep for a long time, the notifications are not processed until I manually pressed the wake button on my Samsung S7. Also, I am playing a media each time the notification is received thru a Service. For Notification 4 the media does not play until I manually wake the phone. Also, I have some style applied to the content, It displays correctly for Notification 1,2 and 3 but not on Notification 4.
I thought that maybe when I am creating Notifications for the next day, there is a problem registering them so I tried to play with my date manually and everything works ok.
This is how I create my Notification:
public Notification getNotification(String notificationName, long notificationTime) {
Intent intent = new Intent( context, NotificationPlayerService.class );
intent.setAction( NotificationPlayerService.ACTION_STOP );
PendingIntent pendingIntent = PendingIntent.getService(context, 1, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("Notification");
builder.setContentText(notificationName);
builder.setSmallIcon(R.drawable.icon);
builder.setColor(ContextCompat.getColor(context, R.color.teal_500));
builder.setLights(Color.GREEN, 3000, 3000);
builder.setVibrate(new long[]{0,750});
builder.setWhen(notificationTime);
builder.setShowWhen(true);
Uri sound= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
builder.setSound(sound);
builder.setDeleteIntent(pendingIntent);
return builder.build();
}
And this is how I schedule them:
#SuppressLint("NewApi")
public void scheduleNotification(Notification notification, long notificationTime, String action, int id) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.setAction(action);
if(id!=-1){
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, id);
}
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT > 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, notificationTime, pendingIntent);
}
}
This is how I receive them:
public void onReceive(Context context, Intent intent) {
this.context = context;
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
String action = intent.getAction();
int id = intent.getIntExtra(NOTIFICATION_ID, -1);
Log.e("NOTIFICATION_RECEIVER","Notification received " + action +"-"+ id);
if(id != -1){
Notification notification = intent.getParcelableExtra(NOTIFICATION);
notificationManager.notify(id, notification);
}
Intent serviceIntent = NotificationService.startNotificationService(context);
if (serviceIntent != null) {
startWakefulService(context, serviceIntent);
}
}
And Finally I am using an IntenService to create my notifications:
#Override
protected void onHandleIntent(Intent intent) {
try{
startNotifications();
}
finally {
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
}
startNotification uses methods getNotification and scheduelNotification shown above. Basically it gets some settings from SharedPreferences and calculates when the notifications should be fired.
Thank you
I am trying to develop an alarm system in android that would function after the application closes, making multiple simultaneous alarms possible (which should be repeatable and cancelable, but I have read documentation for such functions).
Currently, I only have the UI (which fires off intents to receiver at scheduled times through AlarmManager) and the Receiver class (which extends BroadCastReceiver). Although the alarm somehow functions, there have been issues like the alarm not sounding at appropriate times until I open app again and not providing the correct alarm.
I have read that a service is commonly used in such apps to provide functionality of the application when the activity is closed. Thus, I am interested in what a service would provide in the context of the application, and whether my problems are solvable through service.
I have searched answers and read that a service is useful for running background operations (i.e. mp3 or alarm) For example, google states that "Another application component can start a service and it will continue to run in the background even if the user switches to another application. ". The following answer states that to use "alarm simultaneously you must use Service class for that".
Therefore, I think that a service may be useful for providing the functionality for the alarm. However, some people seem to represent a service as a either or with AlarmManager, which I am currently using. Most others seem to use AlarmManger to start service or perform an action of that nature. I would be very grateful if someone could shed light on what a service provides (I've already read google's explanation but it did not clear up whether I need it or not).
Sending intent from UI
if (row.get(7) == 1) {
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
alarmIntent.putExtra("id", (long) row.get(0));
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long longValue = (long) row.get(0);
int intValue = (int) longValue;
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, intValue, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (row.get(8) == 1) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, (long) row.get(6), (long) row.get(9), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, (long) row.get(6), pendingIntent);
}
}
AlarmReceiver class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
long id = intent.getLongExtra("id", 0);
Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_action_search)
PendingIntent pi = PendingIntent.getActivity(context, (int)id, new Intent(), 0);
NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify((int)id, builder.build());
}
}
Try to use service like this :
public class UpdateService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
}
When onStartCommand returns START_STICKY, system restarts service if it's killed.
Use this link
I have an arraylist of objects, a member of which is a date/time.
The arraylist and object is used to populate the UI listview.
I would like to send a push notification when the time from the object/listview is approaching system/mobile time (whether its 5, 10 mins or modifiable, doesn't matter).
So i'm familiarizing myself with the Notification Builder, but i'm unsure where to put the logic and how the app will monitor the time and notify when its close.
Any ideas, suggestions on the right path much appreciated
You can trigger an alarm at a scheduled time and then use an IntentService to capture it once alarm goes off.
In the main activity (lets assume the name is MainActivity, you can create an alarm like this.
AlarmManager mgr = (AlarmManager) MainActivity.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(MainActivity, NotifService.class);
PendingIntent pi = PendingIntent.getService(MainActivity, 0, intent, 0);
mgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + PERIOD, pi);
where the PERIOD defines after how much milliseconds you want the alarm to go off.
To configure the AlarmManager differently, you can read more about it.
NotifService is what captures the alarm when it goes off. Create a class called NotifService it extends IntentService
public class NotifService extends IntentService {
public NotifService() {
super("My service");
}
#Override
protected void onHandleIntent(Intent intent) {
//write your code for sending Notification
Intent intent = new Intent();
intent.setAction("com.xxx.yyy.youractivitytobecalled");
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 1, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder (getApplicationContext());
builder.setContentTitle("Your Application Title");
builder.setContentText("Notification Content");
builder.setContentIntent(pendingIntent);
builder.setTicker("Your content");
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setOngoing(false);
builder.setPriority(0);
Notification notification = builder.build();
NotificationManager notificationManger = (NotificationManager) getSystemService (Context.NOTIFICATION_SERVICE);
notificationManger.notify(1, notification);
}
}
Register NotifService in your AndroidManifest.xml
<application
fill content here />
<service android:name=".NotifService" >
</service>
</application>
Just for future reference, I created a class that extends BroardcastReceiver and used that to handle the alarms from AlarmManager - its all there in the docs but its kinda confusing how everything sits together at first.
I am developing an android app which shows a notification every 12 hour if the time is saved in the database. So everytime a data is entered or edited in the database ,I cancel the current alarmmanager and start a fresh new one so that I dont miss one. Also on reboot I have called the alarmmanager. On the broadcast receiver, the database is checked for entry and if found a notification is set and the app is opened automatically.
So when I test the app by changing the date manually,the app works as expected.Also on reboot the app works.But if I keep the app idle for nearly 14 hours,the notification is not set ,but if I open the app and suspend it the notification is set after that.
This is how I call the alarmmanager.
Intent alarmintent = new Intent(context, package.Alarm_Manager.class);
alarmintent.putExtra("note","Notify");
sender = PendingIntent.getBroadcast(context , 0 , alarmintent , PendingIntent.FLAG_CANCEL_CURRENT | Intent.FILL_IN_DATA);
alarm_manger = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarm_manger.cancel(sender);
Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
alarmintent = new Intent(context, package.Alarm_Manager.class);
alarmintent.putExtra("note","Notification");
sender = PendingIntent.getBroadcast(context , 0 , alarmintent , PendingIntent.FLAG_CANCEL_CURRENT | Intent.FILL_IN_DATA);
alarm_manger = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm_manger.setRepeating(AlarmManager.RTC_WAKEUP, now, AlarmManager.INTERVAL_HALF_DAY, sender);
This is the broadcast receiver
#Override
public void onReceive(Context context, Intent intent)
{
NotificationManager manger = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Calendar cal = Calendar.getInstance();
date = (int)(cal.getTimeInMillis()/1000);
Notification notification = new Notification(R.drawable.vlcsnap_396460 , "Notify" , System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, "App", "Notify" , contentIntent);
notification.flags = Notification.FLAG_INSISTENT;
manger.notify( 0 , notification);
}
You don't need to call alarm_manager.cancel(sender); if you set the PendingIntent.FLAG_CANCEL_CURRENT.
Your call to
alarm_manger.setRepeating(AlarmManager.RTC_WAKEUP, now, AlarmManager.INTERVAL_HALF_DAY, sender);
will trigger the alarm right away, since the now is already passed when you set the alarm.
I suggest you use
now + DateUtils.HOUR_IN_MILLIS / 2
for the triggerAtMillis parameter
Did you tried to schedule it for smaller interval? Does it get triggered ?
After having seen your Alarm_Manager code, I think it is illegal to do this in your BroadcastReceiver object directly. Quote:
If this BroadcastReceiver was launched through a tag, then the object is no longer alive after returning from this function.
I believe there is no other way than to create a Service which is informed by your BroadcastReceiver, and make sure that the Service calls setLatestEventInfo() with itself (this) as the Context.
The reason why your asynchronous Broadcast fails while it works when your app is running is probably that the Context provided to the BroadcastReceiver lives only for the duration of the call to the BroadcastReceiver when your app does not run. So the Notification service, which only runs after your BroadcastReceiver has died along with the temporary context, is missing a valid context.
When your app runs, the Broadcast probably comes with your Activity or Application object as Context, and this is still vaild when the Notification manager runs.
Hope this helps.
Update: An `IntentService`` will do. You don't want a full time Service for that.
Update 2: Some snippets.
<service android:name=".MyIntentService" android:label="#string/my_intent_service_name" />
public final class MyIntentService extends IntentService {
public MyIntentService() {
super("service name");
// set any properties you need
}
#Override
public void onCreate() {
super.onCreate();
// do init, e.g. get reference to notification service
}
#Override
protected void onHandleIntent(Intent intent) {
// handle the intent
// ...especially:
notification.setLatestEventInfo(this, "App", "Notify" , contentIntent);
// ...
}
}
public final class MyAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MyIntentService.class));
}
}
Is there any way in Android to detect when a user swipes a notification to the left and deletes it? I'm using an alarmmanager to set a repeating alert and I need my repeating alert to stop when the notification is cancelled by the user. Here's my code:
Setting the repeating alert:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), repeatFrequency, displayIntent);
My notification code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get the notification ID.
int notifID = getIntent().getExtras().getInt("Reminder_Primary_Key");
//Get the name of the reminder.
String reminderName = getIntent().getExtras().getString("Reminder_Name");
//PendingIntent stores the Activity that should be launched when the user taps the notification.
Intent i = new Intent(this, ViewLocalRemindersDetail.class);
i.putExtra("NotifID", notifID);
i.putExtra("notification_tap", true);
//Add FLAG_ACTIVITY_NEW_TASK to stop the intent from being launched when the notification is triggered.
PendingIntent displayIntent = PendingIntent.getActivity(this, notifID, i, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.flag_red_large, reminderName, System.currentTimeMillis());
CharSequence from = "Here's your reminder:";
CharSequence message = reminderName;
notif.setLatestEventInfo(this, from, message, displayIntent);
//Pause for 100ms, vibrate for 250ms, pause for 100ms, and vibrate for 500ms.
notif.defaults |= Notification.DEFAULT_SOUND;
notif.vibrate = new long[] { 100, 250, 100, 500 };
nm.notify(notifID, notif);
//Destroy the activity/notification.
finish();
}
I know I need to call alarmManager.cancel(displayIntent) in order to cancel my repeating alarm. However, I don't understand where to put this code. I need to cancel the repeating alert ONLY when the user has tapped on the notification or dismissed it. Thanks for your help!
I believe that Notification.deleteIntent is what you are looking for. The doc says:
The intent to execute when the notification is explicitly dismissed by the user, either with the "Clear All" button or by swiping it away individually. This probably shouldn't be launching an activity since several of those will be sent at the same time.
To all those future people out there -- you can register a broadcast receiver to listen for notification delete inents.
Create a new broadcast receiver:
public class NotificationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null || !action.equals(Config.NotificationDeleteAction)) {
return;
}
// Do some sweet stuff
int x = 1;
}
}
Register the broadcast receiver within your application class:
"If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically)."
Android Documentation.
registerReceiver(
new NotificationBroadcastReceiver(),
new IntentFilter(Config.NotificationDeleteAction)
);
You probably noticed the static variable Config.NotificationDeleteAction. This is a unique string identifier for your notification. It typically follows the following {namespace}{actionName} convention:
you.application.namespace.NOTIFICATION_DELETE
Set the delete intent on your notification builder:
notificationBuilder
...
.setDeleteIntent(createDeleteIntent())
...
Where, createDeleteIntent is the following method:
private PendingIntent createDeleteIntent() {
Intent intent = new Intent();
intent.setAction(Config.NotificationDeleteAction);
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
Your registered broadcast receiver should receive the intent when your notification is dismissed.
You can also use an Activity PendingIntent, which may be simpler to implement if you have an Activity that can handle the dismissal, because you don't have to create and configure a broadcast receiver.
public static final String DELETE_TAG = "DELETE_TAG";
private PendingIntent createDeleteIntent(Context context) {
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra(DELETE_TAG, true);
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
MyActivity would receive the intent in its onCreate(), and in this example, could look for the DELETE_TAG extra to recognize it.