I made an app which has a number picker ranging from 1 to 60 minutes, and I connected it to a repeated alarm manager. When I gave it a try, I noticed that it's not accurate sometimes, it either takes more minutes to work or less.
What could be the problem?
For the start button:
startB.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (startB.isChecked())
{
Calendar calSet = Calendar.getInstance();
calSet.set(Calendar.MINUTE, picker2.getValue());
calSet.set(Calendar.SECOND, 0);
calSet.set(Calendar.MILLISECOND, 0);
setAlarm(calSet);
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
editor.putBoolean("toggleButton", startB.isChecked());
editor.commit();
timerHasStarted = true;
}
else
{
Intent intent = new Intent(getBaseContext(), MainReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(), RQS_1, intent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
editor.putBoolean("toggleButton", startB.isChecked());
editor.commit();
timerHasStarted = false;
}
}
});
For the alarm:
private void setAlarm(Calendar targetCal ) {
// TODO Auto-generated method stub
Intent intent = new Intent(getBaseContext(), MainReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(), RQS_1, intent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
targetCal.getTimeInMillis(),
TimeUnit.MINUTES.toMillis(picker2.getValue()),
pendingIntent);
}
Receiver:
#Override
public void onReceive(Context context, Intent intent) {
MediaPlayer m=MediaPlayer.create(context, R.raw.sound);
m.start();
}
The Android OS is able to shift alarms in order to minimize wakeups and battery consumption (since API 19). Take a look here. I noticed delays up to a few seconds.
A pretty nice tutorial on alarms in general could be found here
Related
I am trying to develop an application in which the user can create more than 1 alarms for the same time ,say, 09:48. And for this time, each alarm has to create its own notification which leads the user to an activity when the notification is clicked. The other alarms which were scheduled at the same time must keep ringing until their notifications are clicked. Now, I am able to create alarms for different times and get their corresponding notifications which lead to an activity in which the user can dismiss or snooze the alarm. However, when I schedule more than one alarm for the same time, only 1 alarm is ringing and the other one gets lost. I share my code pieces at the below.
public void schedule(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, alarmId, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
alarmPendingIntent
);
In my broadcastReceiver class:
private void startAlarmService(Context context, Intent intent) {
Intent intentService = new Intent(context, AlarmService.class);
Log.println(Log.DEBUG, "DEBUG", "************Alarm Broadcast Receiver**********");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intentService);
} else {
context.startService(intentService);
}
}
In my AlarmService :
#Override
public void onCreate() {
super.onCreate();
mediaPlayer = MediaPlayer.create(this, R.raw.alarm);
mediaPlayer.setLooping(true);
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, RingActivity.class);
int requestCode = new Random().nextInt(Integer.MAX_VALUE);
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, notificationIntent, 0);
//String alarmTitle = String.format("%s Alarm", intent.getStringExtra(TITLE));
int notificationId = new Random().nextInt(Integer.MAX_VALUE);
Notification notification = new NotificationCompat.Builder(this, String.valueOf(notificationId))
.setContentTitle("PASS1")
.setContentText("PASS2")
.setSmallIcon(R.drawable.pill)
.setContentIntent(pendingIntent)
.build();
mediaPlayer.start();
long[] pattern = { 0, 100, 1000 };
vibrator.vibrate(pattern, 0);
startForeground(1, notification);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
vibrator.cancel();
}
in this code
startForeground(1, notification);
you are using 1 as the id.
If a notification with the same id has already been posted by your application and has not yet been canceled, it will be replaced by the updated information.
So the second alarm notification with the same id (because you are using a fixed value of 1) is replacing the old one
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 would like to create a custom notification service in my app.
I wouldn't use the google service (google cloud messaging).
Is there a way to create a daemon that check every X seconds a particular condition on my app db and show a notification?
Thank you,
edit
I call this method in MainActivity's oncreate(). I get the times from my db
private void restartNotify() {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.cancel(pendingIntent);
ArrayList<String> item = new ArrayList<String>();
item = GetLists.GetTimesListForNotification(this);
for (int i = 0; i < item.size(); ++i) {
String time = item.get(i);
int Position = time.indexOf(":");
int hour = Integer.parseInt(time.substring(0, Position));
int min = Integer.parseInt(time.substring(Position + 1));
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, min);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
am.set(AlarmManager.RTC, cal.getTimeInMillis(),
pendingIntent);
}
And this is my broadcast receiver
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager mManager;
mManager = (NotificationManager) context.getApplicationContext()
.getSystemService(
context.getApplicationContext().NOTIFICATION_SERVICE);
Intent intent1 = new Intent(context.getApplicationContext(),
MainActivity.class);
Notification notification = new Notification(R.drawable.ic_launcher,
"New message to read", System.currentTimeMillis());
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
context.getApplicationContext(), 0, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(context.getApplicationContext(),
"notification are work", "it's work",
pendingNotificationIntent);
mManager.notify(0, notification);
}
}
You can use AlarmManager + BroadcastReceiver like so:
private void setRecurringAlarm(Context context) {
Intent downloader = new Intent(this, MyStartServiceReceiver.class);
downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, downloader, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 6000, 10000, pendingIntent);
}
BroadcastReceiver class:
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//do the stuff...
}
}
And don't forget to register receiver in your manifest:
<receiver android:name=".MyStartServiceReceiver"
android:enabled="true"/>
You have to use Alarm Manager to schedule code for execution every specific period. take a look here:
http://developer.android.com/training/scheduling/alarms.html
Date dat = new Date();
Calendar cal_alarm = Calendar.getInstance();
Calendar cal_now = Calendar.getInstance();
cal_alarm.setTime(dat);
cal_alarm.set(Calendar.HOUR_OF_DAY, hrs);// set the alarm time
cal_alarm.set(Calendar.MINUTE, min);
cal_alarm.set(Calendar.SECOND, 0);
cal_alarm.set(Calendar.MILLISECOND, 0);
if (cal_alarm.before(cal_now)) {// if its in the past increment
cal_alarm.add(Calendar.DATE, 1);
}
Intent intent = new Intent(ctx, AlarmReceiver.class);
// intent.putExtra("Reminder to Take Photo", "Pixitch!");
PendingIntent sender = PendingIntent.getBroadcast(ctx, 0010000,
intent, 0);
// Get the AlarmManager service
long tmemills = cal_alarm.getTimeInMillis()
- cal_now.getTimeInMillis();
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, tmemills,
AlarmManager.INTERVAL_DAY, sender);
Alarm Receiver Class
public class AlarmReceiver extends BroadcastReceiver {
private static final int MY_NOTIFICATION_ID = 1;
private NotificationManager notificationManager;
private Notification myNotification;
// Context ctx = this;
#SuppressWarnings("deprecation")
#Override
public void onReceive(Context context, Intent intent) {
try {
NotificationManager mNM;
mNM = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(
R.drawable.ic_launcher, "Pixitch Notification !",
System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, AlarmManage.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(context, "Pixitch Notification!",
"Reminder For TakePhoto", contentIntent);
mNM.notify(0, notification);
} catch (Exception e) {
Toast.makeText(
context,
"There was an error somewhere, but we still received an alarm",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
the value of tmemills is 278,088
the tmemills is around 4.5 minutes but
the alarm Manager is Running immediately
I am not able to find where the problem is because I am beginner for Android. please help me
Try this:
am.setRepeating(AlarmManager.RTC_WAKEUP, tmemills + System.currentTimeMillis(),
AlarmManager.INTERVAL_DAY, sender);
Get rid of tmemills. Use cal_alarm.getTimeInMillis() as the second parameter to your set() call on AlarmManager, as that is the number of milliseconds since the Unix epoch at which you want the event to occur.
I've found many similar questions to this, but they're too complicated (too much code), at least I think.
Can this thing be done in a few code of lines? I want to fire an activity in 10 (let's say) minutes, that's it. Thank you.
To Set Alarm for 10 Minutes(let's say) Use this code
AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, ShortTimeEntryReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),10*60*1000, pendingIntent);
To Start Activity
public class ShortTimeEntryReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
// Your activity name
Intent newIntent = new Intent(context, ReminderPopupMessage.class);
newIntent.putExtra("alarm_message", message);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
In your Manifest File Add the following
<receiver android:name=".ShortTimeEntryReceiver"
android:enabled="true"
android:process=":remote">
</receiver>
This function I use sets or cancels an alarm depending on the "Set" parameter
public static void SetAlarm(Context c, long AlarmTime, int ItemID, String Message, Boolean Set) {
Intent intent = new Intent(c, AlarmReceiver.class);
intent.putExtra("Message", Message);
intent.putExtra("ItemID", ItemID);
PendingIntent sender = PendingIntent.getBroadcast(c, 8192 + ItemID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Clear the seconds to 0 for neatness
Calendar ca = Calendar.getInstance();
ca.setTimeInMillis(AlarmTime);
ca.set(Calendar.SECOND, 0);
AlarmTime = ca.getTimeInMillis();
// Get the AlarmManager service
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
if (Set) {
am.set(AlarmManager.RTC_WAKEUP, AlarmTime, sender);
} else {
am.cancel(sender);
}
}
You would then need a Broadcast Receiver to handle the alarm and do whatever it is you want to do.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String Message = bundle.getString("Message");
int ItemID = bundle.getInt("ItemID");
// Do what you want to do, start an activity etc
} catch (Exception e) {
e.printStackTrace();
}
}
}