What's the best way to implement snooze functionality in an Android notification. (i.e. I notify user of X [for arguments sake lets use the example of a text message], and he doesn't want to be bothered by it for now, yet at the same time he wants to make sure he doesn't forget. So he does want it to play the noise again, but at e.g. 5 minutes from now)
I saw the way the android alarm clock does it, but to me it seems messy (and usually not good) to popup a floating intent while the user might be doing something important.
On the other hand, it doesn't seem possible to put buttons inside the notification area. Or am I wrong?
What would you suggest?
Add a snooze button:
Button snooze = (Button) findViewById(R.id.snooze);
snooze.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
mMediaPlayer.stop();
finish();
return true;
}
});
Then before where you call the alarm, update the time
Intent intent = new Intent(this, this.getClass());
PendingIntent pendingIntent =
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long currentTimeMillis = System.currentTimeMillis();
long nextUpdateTimeMillis = currentTimeMillis + 5 * DateUtils.MINUTE_IN_MILLIS;
Time nextUpdateTime = new Time();
nextUpdateTime.set(nextUpdateTimeMillis);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, nextUpdateTimeMillis, pendingIntent);
Call the alarm now.
A simple strategy may be as follows:
The notification text can be "1 new message. Click here to notify again in 5 mins".
If the user clears the notifications, nothing happens and notification is cleared.
If the user clicks on the notification, then clear the notification and set up a timer and post a new notification after 5 min.
Alternatively, clicking the notification can bring an activity to the foreground that will set up a timer if there's no other input from the user (e.g., clicking on a "dismiss" button).
Another, opposite approach, would be to set up a timer when the notification is sent, and after the snooze time, remove it and add a new one, with the corresponding noise and probably a text added saying how much time passed since the original notification. That can be done recursively until the user clears the notification or clicks on it.
The best strategy will depend on what the application does and what is the level of customization the user is able to do. I would not implement any snozze behavior that cannot be easily prevented by the user (can be very annoying if not).
I've done this exactly same way how i created first alarm-notification
private void startAlarm(Calendar calendar) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Config.NOTIFICATION_REQUEST_CODE, intent, 0);
//Repeat every 24 hours
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24*60*60*1000, pendingIntent);
}
So for snoozing notification or alarm i just created another alarm but that's not repeating alarm. that will trigger for only once
private void snoozeAlarm() {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Config.NOTIFICATION_REQUEST_CODE, intent, 0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
Calendar.getInstance().getTimeInMillis() + 5 * 60000, //...start alarm again after 5 minutes
pendingIntent);
finish();
System.exit(0); //...exit the activity which displayed
}
if anyone need to take a look at AlertReceiver.class
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent = new Intent();
intent.setClass(context, DisplayedOnScreen.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
NotificationHelper notificationHelper = new NotificationHelper(context);
NotificationCompat.Builder notificationBuilder = notificationHelper.getNotification();
notificationHelper.getManager().notify(1, notificationBuilder.build());
}
}
Related
I have an Alarm Manager that runs periodically , but I want to have a specific set of time that it will be running. For Example , lets say that we have a periodic Alarm Manager that is registered with a broadcast receiver and an Action is being performed every 30 minutes. The thing is that I want the Alarm Manager to be active for a specific time lets say 3 hours, so the Alarm manager should goes off 3 hours / 30 minutes or 6 times.
Code to start the define the Alarm Manager:
TimerPeriodic = (AlarmManager)getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(),AlarmReceiver.class);
intent.putExtra(Constants.ALARM_ID, Constants.TIMER_PERIODIC_ID);
TimerPeriodicPendingIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
Fire Alarm Manager:
long start = TimeUnit.MINUTES.toMillis(StartMinutes);
TimerPeriodic.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + start, start, TimerPeriodicPendingIntent);
Also the alarm Manager should be active if the Application is killed.
Thank you for any help!
It can be acheived by using Sqlite Db. where you store the Alaram ID,count,and repeation (How many time you want to repeat).
when Alarm is trigger (AlarmReceiver.onReceive()) increment the count check with the condition with repeation. if it exceed just cancel it. Hope It will help :)
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(
context.ALARM_SERVICE);
Intent myIntent = new Intent(context, AlarmReceiver.class);
cancelAlarm(reminder.getId(),myIntent,alarmManager);
}
private void cancelAlarm(int notiId,Intent myIntent,AlarmManager alarmManager) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notiId, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(pendingIntent);
}
the app i'm doing have to schedule an notifications if the user choose to
every time the user close the app the must must check and make the notification based on the user choice
the problem is if the user choose to have notification every time he close the app my code will put new notification for the same the thing so when the notification is fired there will be many notification instead of just one
i need to know if i can check if there is scheduled notification just like the one that i'm trying to make to avoid duplication and have one notification only
here is my code:
private void createScheduledNotification(long dateop,int days,String vaa,String naa)
{
Calendar calendars = Calendar.getInstance();
calendars.setTimeInMillis(dateop);
if(days<30){
calendars.add(Calendar.HOUR_OF_DAY, days *24);
}
else{
calendars.add(Calendar.MONTH, days/30);
}
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(getBaseContext().ALARM_SERVICE);
int id = (int) System.currentTimeMillis();
Intent intent = new Intent(this, TimeReceiver.class);
intent.putExtra("username", naa);
intent.putExtra("vaccine", vaa);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendars.getTimeInMillis(), pendingIntent);
}
First off,this site is great and everyone is so helpfull. This is my first post so forgive me if i have ommited anything.
I create an alarm like so:
private void startLocation() {
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyWeatherUpdateService.class);
PendingIntent service = PendingIntent.getService(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
alarm.setRepeating(AlarmManager.RTC, SystemClock.elapsedRealtime() + (60 * 1000),
Long.parseLong(prefs.getString("listpref", "60000")), service);
}
In this method which is called inside a fragment, context is from getApplication (), listpref is a string update interval in milliseconds.
I cancel it by:
public void endLocation() {
Intent i = new Intent(context, MyWeatherUpdateService.class);
PendingIntent service = PendingIntent.getService(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
alarm.cancel(service);
}
Ensuring that the intent/pending intent is the same.
Now i have 2 issues:
1) the alarm fires almost imediately after creation, even though i tell it to start after 1min.
2) when i call cancel, the alarm fires once more before the alarm is cancelled.
With question 1) why does the alarm fire so soon? And with 2) is this working as intended or should the alarm cancel immediately like i want it to.
If i have not supplied enough info, ill add more code if required.
Thanks in advance.
the alarm fires almost imediately after creation, even though i tell it to start after 1min
That is because you are using RTC with an elapsedRealtime() starting time. Those need to match. The simplest solution is to switch to ELAPSED_REALTIME.
when i call cancel, the alarm fires once more before the alarm is cancelled.
Try replacing PendingIntent.FLAG_CANCEL_CURRENT with 0, at least in the PendingIntent for your cancel() call.
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().
I would like to display an alert dialog when the alarm goes off. Here is where i am so far. Im not sure if im doing it right.
#Override
void doTaskWork(Intent intent){
String taskId = intent.getStringExtra(TaskHelper._id);
NotificationManager mgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(this, TaskDetails.class);
notificationIntent.putExtra(TaskHelper._id, taskId);
PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Notification note = new Notification(R.drawable.stat_sys_warning, );
}
}
Alarm:
You can schedule a pending intent that drives what you want when the alarm fires. The process is:
Determine how often you want the alarm to fire. You can fire at an exact time, a specific time from now (in 10 seconds..), or a specific repeat at an interval (every x seconds/minutes/etc.). You can also set a specific time to start the repeat process. The interval isn't variable. Then you have to do one shots and set another alarm for the next time. You can also set flags that determine the time format (millis, RTC, ...). Finally, you can have the alarm firing wake up the device or let it sleep and get scheduled the next time the phone is awake.
Now, as to what is scheduled. A pending intent is scheduled. The pending intent wakes up a broadcast receiver. Here's some clips of code I use to fire a timer at 1 minute past midnight daily. (It updates a widget that has to update daily.)
Intent intent = new Intent(context, DaysReceiver.class);
PendingIntent receiverIntent = PendingIntent.getBroadcast(context,
DaysConstants.UPDATE_ALARM,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Schedule the alarm!
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(receiverIntent);
if (cancelAlarm) {
MyLog.d(TAG, "setAlarm cancel");
return;
}
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
JodaTime jtime = new JodaTime();
am.set(AlarmManager.RTC_WAKEUP, jtime.afterMidnight(), receiverIntent);
//am.setRepeating(AlarmManager.RTC_WAKEUP, jtime.nowPlusMillis(30 * 1000),
// 30 * 1000, receiverIntent);
MyLog.d(TAG, "setAlarm set");
}
The JodaTime class does date and time calculations. the afterMidnight() bit above returns 1 minute after midnight tonight. The routine can be used to just cancel an outstanding alarm.
The receiver is just a normal broadcast receiver and you can do anything in it that you can do in any other broadcast receiver. (Don't forget to put the usual stuff in the manifest. Permissions, and such like.
Here's the receiver I'm using less the imports. It's pretty straight forward. It grabs all the widgets that are on home screens and updates them. The update routine is a static function in the widget provider. It's a class because it is driven from two places. The widget config and the widget provider. The timer is rescheduled every 24 hours. The alarm won't live through a boot, but the provider's on update is driven at reboot. (All that's happening is the new day calculations are performed and the widget display is updated.) You could drop my code and put in a startActivity.
Ooops. Almost forgot. Use PendingIntent.FLAG_UPDATE_CURRENT so you don't have multiple intents stacked up accidentally...
public class DaysReceiver extends BroadcastReceiver {
static String TAG = "DaysReceiver";
#Override
public void onReceive(Context context, Intent intent) {
MyLog.d(TAG, "onReceive");
updateWidgets(context);
}
private void updateWidgets(Context context) {
MyLog.d(TAG, "updateWidgets");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName componentName = new ComponentName(context, DaysProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
final int N = appWidgetIds.length;
if (N < 1) {
MyLog.d(TAG, "No widgets");
return;
}
for (int i = 0; i < N; i++) {
MyLog.d(TAG, "Update widget " + Integer.toString(appWidgetIds[i]));
DaysProvider.updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
}
}
}
Hope I haven't rambled to much, but I'm in a rush to get back to some other business. I don't have the time to really edit the post. Hope this helped...
Do you really need a notification? Why not fire off an activity that can do the alarm notification and disappear. You can sound an alarm, vibrate the phone, whatever. Even do a notification if you still want to...
Intent intent = new Intent(context.MyAlarmResponse);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("REASONFORALARM", "What ever you want");
context.startActivity(intent);
In the manifest, use the following theme to look like a dialog:
<activity android:name=".MyAlarmResponse"
android:theme="#android:style/Theme.Dialog">
</activity>
It doesn't have to look like a dialog. You can do a full court press with a full screen display, animation, vibrate, and sound. The user than hits your cancel key and it all goes away.