I'm having some trouble with getting a daily notification appearing.
My application gets a time, a hour and minute that the user wishes to be reminded of something.
I then use AlarmManager to set up a alarm at this time repeating whilst using alarm receiver to create the notification.
I've been trying this for hours but can't figure out what I'm doing wrong.
I've looked at a bunch of other SO questions but none have helped me yet.
I've stored the user's hours and minute input into a date object get habitReminder.
My createNotifications() method:
private void createNotifications() {
Log.i("Reminder at",""+habitReminder.getHours()+":"+habitReminder.getMinutes());
//Create the alarms/notifications for the user
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
alarmIntent.putExtra("name", habitName);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Log.i("createNotifications", "Alarm manager is created.");
//Set the timing of the reminder
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, habitReminder.getHours());
calendar.set(Calendar.MINUTE, habitReminder.getMinutes());
calendar.set(Calendar.SECOND,0);
//Check to make sure time is after the current date.
if(calendar.before(now)){
calendar.add(Calendar.DATE, 1);
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.i("createNotifications", "Alarm has been set for " +habitReminder.getHours()+":"+habitReminder.getMinutes() +" daily.");
}
My alarm receiver class:
public class AlarmReceiver extends BroadcastReceiver {
private static int id =0;
#Override
public void onReceive(Context context, Intent intent) {
String name = intent.getStringExtra("name");
String title = name + " Reminder!";
String message = "Your reminder to keep up your habit!";
long when = System.currentTimeMillis();
Intent in = new Intent(context, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context,0,in,PendingIntent.FLAG_CANCEL_CURRENT);
NotificationManager nM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(context)
.setContentIntent(contentIntent)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.setWhen(when);
Notification notification = builder.build();
nM.notify(id,notification);
id++;
}
}
And my android manifest:
<receiver android:name="com.closedbracket.trackit.AlarmReceiver" android:enabled="true">
</receiver>
Any help would really be appreciated.
If you want a precise and reliable alarm, use setAlarmClock. It will drain more power from the battery but you are sure the alarm will ring precisely at the time set.
For more information, you can refer to Difference between setExact and setAlarmClock
I think you have the arguments to setRepeating wrong. 2nd argument is the time interval until first alarm fires (the jitter). 3rd is the interval, after the first occurrence at which subsequent alarms fire (the interval).
You are setting an alarm for AlarmManager.INTERVAL_DAY which has a value of 86400000. Your alarm will fire once a day.
Related
I followed a YouTube guide to get going on an alarm clock app. It seems to be working well, however when the alarm starts to play and I click the button to stop the alarm it does not stop the ringtone service. I've tried looking at other stack overflow questions but could not find a logical answer for myself. I know that my intents are not triggering the ringtone service in the receiver class to stop. Anyone have an idea how to stop the ring tone service from a mainactivityclass and send the trigger to the receiver class?
Mainactivity code to trigger alarm and play ringtone
public void setTimer(View v){
//Make alarmmanager
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Date currentTime = Calendar.getInstance().getTime();
Calendar cal_alarm = Calendar.getInstance();
Calendar cal_now = Calendar.getInstance();
cal_now.setTime(currentTime);
cal_alarm.setTime(currentTime);
cal_alarm.set(Calendar.HOUR_OF_DAY,mHour);
cal_alarm.set(Calendar.MINUTE,mMin);
cal_alarm.set(Calendar.SECOND,0);
if (cal_alarm.before(cal_now)){
cal_alarm.add(Calendar.DATE,1);
}
//Add alarm to ArrayList
Alarms.add(cal_alarm);
showAlarm();
Intent i = new Intent(MainActivity.this,MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 1, i, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP,cal_alarm.getTimeInMillis(), pendingIntent);
}
//Stop Alarm
public void cancelAlarm(View v){
Intent i = new Intent(getApplicationContext(), MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, i, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
alarmview.setText("Alarm cancelled");
}
Receiver class
public void onReceive(Context context, Intent intent) {
//Set vibration
Vibrator vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(3000);
//Make notification for alarm
Notification notification = new Notification.Builder(context).setContentTitle("WakeMeYup").setContentText("Wake up!").setSmallIcon(R.mipmap.ic_launcher).build();
//Pass notification to Android system
NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notification.flags|= Notification.FLAG_AUTO_CANCEL;
manager.notify(0, notification);
//Play ringtone
Uri notificati = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
Ringtone r = RingtoneManager.getRingtone(context, notificati);
r.play();
}
}
I ended up making a Ringtone class, which receives an int that decides whether it should play or stop the alarm. The onclick listeners put an extra message into the intent which is picked up by the ringtone class and reads them so it knows which bit of code to run.
Let me explain what I'm doing before I get into the problem.
Ultimately, I'm wanting to send different notifications on certain days of the week every week. I've been able to get it working with a single notification. The problem happens when I try to set up multiple notifications.
So in my MainController's OnCreate method I'm making a call to a function called setAlarm and passing variables:
setAlarm(this, 3, 14, 04, 1, 1);
where 'this' is the context, 3 is a day of the week, 14 is an hour, 04 is a minute, 1 is a second and the last 1 is what I call a notification ID. Here is the setAlarm function:
public void setAlarm(Context context2, int dayofweek, int hourofday, int dayminute, int daysecond, int notiID){
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
alarmIntent.putExtra("VALUE", notiID);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context2, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.DAY_OF_WEEK, dayofweek);
calendar.set(Calendar.HOUR_OF_DAY, hourofday);
calendar.set(Calendar.MINUTE, dayminute);
calendar.set(Calendar.SECOND, daysecond);
Date date = calendar.getTime();
//manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 0, pendingIntent);
manager.setExact(AlarmManager.RTC_WAKEUP, date.getTime(),pendingIntent);
}
What I'm doing in this function is setting up the alarm manager to trigger on a certain day of the week, at a certain time. I know once this is triggered it will call the AlarmReceiver class which I've set up. But I'm also passing an integer variable to the AlarmReceiver class through the alarmIntent intent I set up.
The alarm manager works, and triggers on the specified time. Here's the alarmReceiver class I've set up:
public class AlarmReceiver extends BroadcastReceiver {
private static AlarmReceiver instance = null;
#Override
public void onReceive(Context context, Intent intent) {
int value = intent.getIntExtra("VALUE", 0);
if (value == 1){
NotificationCompat.Builder noti = new NotificationCompat.Builder(context, "notify_001");
noti.setSmallIcon(R.drawable.clocknoon);
noti.setContentTitle("Bill Sez...");
noti.setContentText("First Notification Test!!!");
noti.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManager nm = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("notify_001", "Channel title", NotificationManager.IMPORTANCE_DEFAULT);
nm.createNotificationChannel(channel);
}
nm.notify(0, noti.build());
}
if (value == 2){
NotificationCompat.Builder noti = new NotificationCompat.Builder(context, "notify_002");
noti.setSmallIcon(R.drawable.clocknoon);
noti.setContentTitle("Bill Sez...");
noti.setContentText("This is the second notification test");
noti.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManager nm = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("notify_002", "Channel title", NotificationManager.IMPORTANCE_DEFAULT);
nm.createNotificationChannel(channel);
}
nm.notify(0, noti.build());
}
}
}
As you can see, I'm passing the int variable Value to the class, which works fine as long as I only call the setAlarm function one time. But I'm trying to get this working to set up multiple notifications. What I expect to happen is that I call the setAlarm function with the notification ID (notiID) and at the time specified, the alarm manager triggers and the extra variable value is passed to the alarmReceiver class along with the flow of execution. In the Alarm Receiver class I've got an if statement set up to test the variable 'value' to see if it's 1 or 2 and based on that, a notification will fire and appear on the phone.
What's happening is when I call setAlarm function twice, the first notification is never received. Even more strange, the second notification is received, but it's variable 'value' is 1, not 2 as I expect it to be.
for example:
So I call setAlarm and set the alarm to go off at 12:05:01 on Tuesday, and pass notiID of 1. Then I call setAlarm again and set the alarm to go off at 12:06:01 on Tuesday, and pass notiID of 2.
At 12:05:01, nothing happens. I should see the first notification, but I don't. At 12:06:01 I get a notification but instead of the second notification, I see the first one. Likewise if I put a breakpoint in the AlarmReceiver class and look at what 'value' is set to, it shows to be set to 1, not 2.
So I don't get what's happening. I'm hoping anyone experienced in making notifications with Android 8.0.0 and higher can help. Or even suggest a different way to send different notifications on different days.
Change the following line
PendingIntent pendingIntent = PendingIntent.getBroadcast(context2, 0, alarmIntent, 0);
to
PendingIntent pendingIntent = PendingIntent.getBroadcast(context2, notiID, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
I have this app where i want to set a notification on a specific date the user defines. I saw lots of code and relative answers here on SO but for some reason nothing works so far.
In this test project i have 2 methods. One that sets an alarm to ring 5 seconds on future and one that assigns the desired date.
Problem:
If i set the alarm to a second delay it works fine. The notification is shown within 5 seconds after the alarm assignment. But if i use the method that passes a Calendar date, it does nothing. Not triggers no notification
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void setAlarmOnClick(View view){
// this method call works fine
setAlarm(getNotification("Date test"), 3000);
// this one doesn't
// setAlarm(getNotification("Date test"), getDate());
}
// Here nothing happens when the date comes
private void setAlarm(Notification notification, Calendar cal) {
Intent notificationIntent = new Intent(this, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),pendingIntent );
Toast.makeText(this, "Alarm worked.", Toast.LENGTH_LONG).show();
}
// This alarm get successfully trigger here showing the notification
private void setAlarm(Notification notification, int delay) {
Intent notificationIntent = new Intent(this, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, delay, pendingIntent );
Toast.makeText(this, "Alarm worked.", Toast.LENGTH_LONG).show();
}
private Calendar getDate(){
Calendar cal=Calendar.getInstance();
cal.set(Calendar.MONTH,8);
cal.set(Calendar.YEAR,2017);
cal.set(Calendar.DAY_OF_MONTH,29);
cal.set(Calendar.HOUR_OF_DAY,11);
cal.set(Calendar.MINUTE,47);
return cal;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private Notification getNotification(String content) {
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("Scheduled Notification");
builder.setContentText(content);
builder.setSmallIcon(R.mipmap.ic_launcher);
return builder.build();
}
}
NotificationPublisher.java
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String NOTIFICATION = "notification";
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
NotificationManager notofManager = (NotificationManager)context. getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
notofManager.notify(id, notification);
}
}
I would really appreciate anykind of help!
P.S.
How can i be sure that an alarm was successfully set on a date. Even if a code works and a date is set a week form now. How can i test that it will trigger then? Obviously we can't wait a week to see that. Changing the device date is working? Thank you
Calendar month goes from 0-11 instead of 1-12 as u assumed.
So something like:
cal.set(Calendar.Month, 7 );
would set your calendar month to August.
I am trying to set a repeating alarm in android that eventually will go up at a user specified time. However the alarm goes off right away when once it is set, even when I make sure the alarm isn't set to go off until after the alarm has been set. For example, I have the code below set to have an alarm go off at 10:43 so I set the alarm at 10:41, but the alarm goes off right away. Any ideas? Thanks in advance.
public class Alarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For
Intent scheduledIntent = new Intent(context,ReminderMessage.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(scheduledIntent);
// example
wl.release();
}
public void SetAlarm(Context context) {
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Date dat = new Date();
Calendar cal_alarm = Calendar.getInstance();
Calendar cal_now = Calendar.getInstance();
cal_now.setTime(dat);
cal_alarm.setTime(dat);
cal_alarm.set(Calendar.HOUR_OF_DAY, 10);
cal_alarm.set(Calendar.MINUTE, 43);
cal_alarm.set(Calendar.SECOND, 0);
if(cal_alarm.before(cal_now)){
cal_alarm.add(Calendar.DATE, 1);
}
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), cal_alarm.getTimeInMillis() , pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context) {
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent
.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
I think your line:
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), cal_alarm.getTimeInMillis() , pi); // Millisec * Second * Minute
is triggering the alarm immediately, the second param is the scheduled time, and the third is the period. So if you wanted your alarm to go off at cal_alarm time, you want to use something like:
am.setRepeating(AlarmManager.RTC_WAKEUP, cal_alarm.getTimeInMillis(), 1000*60*5 , pi); // Millisec * Second * Minute
That should go off at the cal_alarm time, and repeat every 5 mins.
AlarmManager.SetRepeating API Doc
I need to trigger a block of code after 20 minutes from the AlarmManager being set.
Can someone show me sample code on how to use an AlarmManager in ِAndroid?
I have been playing around with some code for a few days and it just won't work.
"Some sample code" is not that easy when it comes to AlarmManager.
Here is a snippet showing the setup of AlarmManager:
AlarmManager mgr=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(context, OnAlarmReceiver.class);
PendingIntent pi=PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), PERIOD, pi);
In this example, I am using setRepeating(). If you want a one-shot alarm, you would just use set(). Be sure to give the time for the alarm to start in the same time base as you use in the initial parameter to set(). In my example above, I am using AlarmManager.ELAPSED_REALTIME_WAKEUP, so my time base is SystemClock.elapsedRealtime().
Here is a larger sample project showing this technique.
There are some good examples in the android sample code
.\android-sdk\samples\android-10\ApiDemos\src\com\example\android\apis\app
The ones to check out are:
AlarmController.java
OneShotAlarm.java
First of, you need a receiver, something that can listen to your alarm when it is triggered. Add the following to your AndroidManifest.xml file
<receiver android:name=".MyAlarmReceiver" />
Then, create the following class
public class MyAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm went off", Toast.LENGTH_SHORT).show();
}
}
Then, to trigger an alarm, use the following (for instance in your main activity):
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, 30);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent);
.
Or, better yet, make a class that handles it all and use it like this
Bundle bundle = new Bundle();
// add extras here..
MyAlarm alarm = new MyAlarm(this, bundle, 30);
this way, you have it all in one place (don't forget to edit the AndroidManifest.xml)
public class MyAlarm extends BroadcastReceiver {
private final String REMINDER_BUNDLE = "MyReminderBundle";
// this constructor is called by the alarm manager.
public MyAlarm(){ }
// you can use this constructor to create the alarm.
// Just pass in the main activity as the context,
// any extras you'd like to get later when triggered
// and the timeout
public MyAlarm(Context context, Bundle extras, int timeoutInSeconds){
AlarmManager alarmMgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyAlarm.class);
intent.putExtra(REMINDER_BUNDLE, extras);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, timeoutInSeconds);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
pendingIntent);
}
#Override
public void onReceive(Context context, Intent intent) {
// here you can get the extras you passed in when creating the alarm
//intent.getBundleExtra(REMINDER_BUNDLE));
Toast.makeText(context, "Alarm went off", Toast.LENGTH_SHORT).show();
}
}
What you need to do is first create the intent you need to schedule. Then obtain the pendingIntent of that intent. You can schedule activities, services and broadcasts. To schedule an activity e.g MyActivity:
Intent i = new Intent(getApplicationContext(), MyActivity.class);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),3333,i,
PendingIntent.FLAG_CANCEL_CURRENT);
Give this pendingIntent to alarmManager:
//getting current time and add 5 seconds in it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
Now MyActivity will be launched after 5 seconds of the application launch, no matter you stop your application or device went in sleep state (due to RTC_WAKEUP option).
You can read complete example code Scheduling activities, services and broadcasts #Android
I wanted to comment but <50 rep, so here goes. Friendly reminder that if you're running on 5.1 or above and you use an interval of less than a minute, this happens:
Suspiciously short interval 5000 millis; expanding to 60 seconds
See here.
Some sample code when you want to call a service from the Alarmmanager:
PendingIntent pi;
AlarmManager mgr;
mgr = (AlarmManager)ctx.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(DataCollectionActivity.this, HUJIDataCollectionService.class);
pi = PendingIntent.getService(DataCollectionActivity.this, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() , 1000, pi);
You dont have to ask userpermissions.
An AlarmManager is used to trigger some code at a specific time.
To start an Alarm Manager you need to first get the instance from the System. Then pass the PendingIntent which would get executed at a future time that you specify
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context, MyAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
int interval = 8000; //repeat interval
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
You need to be careful while using the Alarm Manager.
Normally, an alarm manager cannot repeat before a minute. Also in low power mode, the duration can increase to up to 15 minutes.