I am trying to get start time and stop time from user using Time Picker in one class and then passing this time to the broadcast class.
But when I am checking whether the values of the start time and stop time is reached in the Broadcast Receiver class by using a toast message, I am not able to get the required start time or stop time that is passed.
CODE [Main Class]:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.setting);
initialize();
alarmIntent = new Intent(Settings.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(Settings.this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmRepeat();
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Calendar c = Calendar.getInstance();
switch(v.getId()){
case R.id.startTime :
// Process to get Current Time
startHour = c.get(Calendar.HOUR_OF_DAY);
startMinute = c.get(Calendar.MINUTE);
// Launch Time Picker Dialog
TimePickerDialog tpd1 = new TimePickerDialog(this,
new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay,
int minute) {
// Display Selected time in textbox
eStart.setText(hourOfDay + ":" + minute);
startHour = hourOfDay;
startMinute = minute;
alarmIntent.putExtra("startHour", startHour);
alarmIntent.putExtra("startMinute", startMinute);//passing these variables to Broadcast class
}
}, startHour, startMinute, false);
tpd1.show();
public void alarmRepeat(){
Calendar cal = Calendar.getInstance();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000, pendingIntent);
}
Broadcast Class :
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
startHour = intent.getIntExtra("startHour", 0);
stopHour = intent.getIntExtra("StopHour", 0);
Toast.makeText(context, startHour + ":" + startMinute, Toast.LENGTH_LONG).show();
Program explanation: I have passed startHour and startMinute from the onTimeSet method in the main class to broadcast class.
In the Broadcast Class I am storing this startHour and StopMinute in the variables as defined above.
The problem here is that you are creating the alarm in onCreate and then updating your information in onClick. I'm pretty sure your pendingIntent declaration needs to be after you've supplied the information to alarmIntent.
Edit: I would recreate pendingIntent immediately after updating alarmIntent and then call alarmRepeat() again. Personally, I would put the assignment of pendingIntent inside the alarm method and pass alarmIntent in as a parameter, but that's a stylistic choice.
As long as the pending intents are the same (not including extras added to the intent inside it) alarmmanager will override any existing alarm with the new alarm
Related
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'm trying to test launching alarm with AlarmManager and accepting it with BroadcastReceiver. I've found this sources, and do everything like there. But it works so-so and fires from time to time (like 1 successful test from 20 attempts):
#Test public void testOnReceive_defaultAlarm_accepted() throws Exception {
final SharedPreferences sharedPrefs = mQuestions.getAppComponent().getSharedPrefs();
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis() + TIME_DELAY_SNOOZE); // time for alarm
sharedPrefs.edit()
.putString(mQuestions.getString(R.string.pref_notification_time_key),
TimePreference.timeToString(calendar.get(Calendar.HOUR), calendar.get(Calendar.MINUTE)))
.apply(); // set test prefs to alarm
QuestionNotificationUtils.launchDefaultAlarm(mQuestions, sharedPrefs); // launch alarm
Thread.sleep(TIME_DELAY_SNOOZE + TIME_DELAY); // wait for alarm to be fired
assertNotNull(mQuestionNotificationReceiver.mRealmWrapper); // check if injected, and HERE IT FAILS
verify(mQuestionNotificationReceiver.mRealmWrapper, times(1)).getQuestions(); // check if fired with Mockito
}
Launch default alarm is wrapper around this func:
private static void launchAlarm(Context ctx, SharedPreferences prefs, int id) {
final AlarmManager alarmMgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
final PendingIntent alarmIntent =
PendingIntent.getBroadcast(ctx, id, QuestionNotificationReceiver.getIntent(ctx, id),
PendingIntent.FLAG_UPDATE_CURRENT);
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
final String time = prefs.getString(ctx.getString(R.string.pref_notification_time_key),
ctx.getString(R.string.questions_preference_fragment_default_notification_time));
calendar.set(Calendar.HOUR_OF_DAY, TimePreference.parseHour(time));
calendar.set(Calendar.MINUTE, TimePreference.parseMinute(time));
alarmMgr.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY,
alarmIntent);
}
Parts of the broadcast receiver:
#Inject RealmWrapper mRealmWrapper;
#Override public void onReceive(Context context, Intent intent) {
((Questions) context.getApplicationContext()).getQuestionNotificationReceiverComponent()
.inject(this);
onPostInjectReceive(context, intent);
}
Also here is #Before method:
#Before public void setUp() throws Exception {
mQuestionNotificationReceiver = new QuestionNotificationReceiver();
mQuestions.registerReceiver(mQuestionNotificationReceiver,
new IntentFilter(QuestionNotificationReceiver.getAction(mQuestions)));
}
Sometimes it works, it shows, that code is almost right, but it's very very flaky. If I start to use custom RetryRule to retry test if it's failed, test becomes very long, since Thread.sleep() takes about 10 seconds. How to manage this situation?
Use either Calendar.HOUR or Calendar.HOUR_OF_DAY, not both
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
I am trying to get an android notification to show up at noon every day. The notification seems to show up once whenever the device is started, then somewhat sporadically afterwards.
Here is my service:
public class myService extends Service {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v(TAG, "on onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LoginActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("App name")
.setContentText("Notification")
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify("main", 1, mBuilder.build());
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and Receiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast Received");
handleMessage(context, intent);
}
private void handleMessage(Context context, Intent intent)
{
PendingIntent contentIntent = PendingIntent.getService(context, 0, new Intent(context, myService.class), 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(contentIntent);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 12);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24*60*60*1000 , contentIntent);
}
}
Any pointers are appreciated. Thank you.
I attempted to set up my own notification / alarm class. The only way I found to manage it was to extend the Android calendar.
If you would like to try it this way see this link for a start:
http://developer.android.com/guide/topics/providers/calendar-provider.html
I have an example of this approach however i am at work, I can provide my code later if you need it!
What may be happening is that the system kills your Service to free up memory and since the superclass's onStartCommand() returns START_STICKY, recreates it later, causing your notification to sporadically appear.
Really, if the Service's purpose is just to make a Notification consider moving that portion of code some sort of BroadcastReceiver or stop the Service after the Notification is created.
Sorry if answered before, but i looked everywhere but didn't get the proper solution
I am using AlarmManager to automatically fire a notification at 9am everyday, but when i try to run it on emulator it executes immediately, and every half hour (31-32min to be precise) after that instead of only once at 9am everyday.
Any ideas why? help appreciated.
code is as below:
public class Home extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bsheet);
notificationAlert(savedInstanceState);
}
private void notificationAlert(Bundle savedInstanceState) {
AlarmManager manager;
PendingIntent pendingIntent;
Intent intent=new Intent(Home.this, Notify.class);
manager=(AlarmManager)getSystemService(ALARM_SERVICE);
pendingIntent=PendingIntent.getService(Home.this,
0, intent, 0);
GregorianCalendar gcal = new GregorianCalendar();
gcal.set(Calendar.HOUR_OF_DAY, 9);
gcal.set(Calendar.MINUTE, 0);
gcal.set(Calendar.SECOND, 0);
gcal.set(Calendar.MILLISECOND, 0);
long initTime = gcal.getTimeInMillis();
manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime,
24*60*60*1000, pendingIntent);
}
}
cheers,
EDIT: my intention is that, once the app is installed, it fires this alarm at 9am. i have put the alarm in the onCreate, so im not sure if the alarm is only being created everytime i start the app and something weird is happening when i hide the app... again insight would be appreciated!
manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime, 24*60*60*1000, pendingIntent);
Alarm manager will fire immidiatly if initTime < System.currentTimeMillis()
from docs:
If the time occurs in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.
According to the code you've provided, gcal.getTimeInMillis() will return millisecods corresponding to Today 9.00. So if you'll try to run your code after this time, initTime will be less then current system time which triggers immidiate run of AlarmManager.
To fix this, for example, you can add one day to your calendar before passing its gcal.getTimeInMillis() if it is already in past so it will point to Tomorrow 9.00 to let it run tomorrows morning
Update1
Tried code like this and it worked as expected for me - fired service every 10 seconds:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initManager();
}
private void initManager() {
AlarmManager manager;
PendingIntent pendingIntent;
Intent intent = new Intent(this, NotifyService.class);
manager=(AlarmManager)getSystemService(ALARM_SERVICE);
pendingIntent=PendingIntent.getService(this, 0, intent, 0);
long initTime = System.currentTimeMillis() + 5000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, initTime,
10*1000, pendingIntent);
}
However you can use another option: there is AlarmManager.set() method
You can fire it like this
long runTime = /* your calendar time + 24 hours in millis*/
manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);
so it will fire your service at runTime. And then in the service invoke the same method with recalculated runTime for another day so it could look something like that:
public MainActivity extends Activity{
protected onCreate(Bundle bundle){
....
initManager();
}
private initManager(){
...
long runTime = /* time of your first alarm/notification/whatever you develope */
Intent intent = new Intent(this, NotifyService.class);
pendingIntent=PendingIntent.getService(this, 0, intent, 0);
manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);
}
}
And the service:
public NotifyService extends Service{
...
public int onStartCommand(...){
...
/* do stuff */
Intent intent = new Intent(getApplicationContext(), NotifyService.class);
pendingIntent=PendingIntent.getService(this, 0, intent, 0);
long runTime = /* recalculate it according to the next time of firing this service*/
manager.set(AlarmManager.RTC_WAKEUP, runTime, pendingIntent);
}
}
So your service will register an intent in AlarmManager itself everytime the service fires.
try this :
Calendar currentTime = Calendar.getInstance();
Calendar alarmTime = Calendar.getInstance();
currentTime.set(Calendar.HOUR_OF_DAY, 9;
currentTime.set(Calendar.MINUTE, 0);
currentTime.set(Calendar.SECOND, 0);
currentTime.set(Calendar.MILLISECOND, 0);
if (alarmTime.compareTo(currentTime) <= 0) {
// check for time
alarmTime.add(Calendar.DATE, 1);
}
Intent intent = new Intent(getBaseContext(), Receiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getBaseContext(), 1, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);