karthik kolanji
karthik kolanji

Reputation: 2104

Alarm Notification fires instantly. Android

I am working on a Reminder that sends notification on fixed time to the user.

The alarm is getting off instantly ...

I tried most of the suggestions over stackoverflow, but still having same issue

Please help me sort this problem out.

server data

user_reminder": [
                {
                    "id": "75",
                    "name": "Morning Snacks",
                    "time": "11:00:00",
                    "days": "1,2,3,4,5,6,7",
                    "user_id": "14"
                },
                {
                    "id": "76",
                    "name": "Lunch",
                    "time": "13:00:00",
                    "days": "1,2,3,4,5,6,7",
                    "user_id": "14"
                },
               ......
            ]

My code

for (int i = 0; i < reminderList.size(); i++) 
{
     String time = reminderList.get(i).getTime(); // "time": "11:00:00"

    String strSpit[] = time.split(":");
    String strDays[] = reminderList.get(i).getDays().split(","); //"days": "1,2,3,4,5,6,7"

    Date date = new Date();
    Calendar calNow = Calendar.getInstance();
    calNow.setTime(date);

    Calendar calAlarm = Calendar.getInstance();
    calAlarm.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0]));
    calAlarm.set(Calendar.MINUTE, Integer.parseInt(strSpit[1]));

    for (int j = 0; j < strDays.length; j++) 
    {
        calAlarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j]));

        if (calAlarm.before(calNow)) 
        {
            //if its in the past increment
            calAlarm.add(Calendar.DATE, 1);
        }

        notifyIntent.putExtra(Constants.REMINDER_NAME, reminderList.get(i).getName());
        pendingIntent = PendingIntent.getBroadcast(this, 0, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, calAlarm.getTimeInMillis() , pendingIntent);

        }
    }
}

Get days : This solves the day numbering

public int getDayInt(String strDay) 
{
   int dayNumber = 0;

   if (strDay.equals("1")) 
   {
       dayNumber = Calendar.MONDAY;

   } ......

   return dayNumber;
}

screen shot

enter image description here

Upvotes: 8

Views: 2071

Answers (5)

Hussnain Azam
Hussnain Azam

Reputation: 358

Got hit by same issue and stumbled upon this question while finding the solution. When setting the alarm, You just need to place a check that your alarm date should not be before current date.

public static void setReminder(Context context,Class<?> cls,long milliseconds, int event_id,String eventName)
{
    Calendar calendar = Calendar.getInstance();

    Calendar notificationcalendar = Calendar.getInstance();

    notificationcalendar.setTimeInMillis(milliseconds);

    if(!notificationcalendar.before(calendar)) { // **just add this check**


        ComponentName receiver = new ComponentName(context, cls);
        PackageManager pm = context.getPackageManager();

        pm.setComponentEnabledSetting(receiver,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);


        Intent intent1 = new Intent(context, cls);
        intent1.putExtra("eventName", eventName);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, event_id, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, notificationcalendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
    }

}

Upvotes: 0

karthik kolanji
karthik kolanji

Reputation: 2104

Finally I found a way to do that by storing PendingIntent requestCode in database (used ROOM) , then cancelling all the alarm by retrieving all the requestCode from DB

AlarmIdPojo

@Entity
public class AlarmIdPojo {

    @PrimaryKey(autoGenerate = true)
    public int id;

    private int requestCode;

    public AlarmIdPojo() {
    }

    public int getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(int requestCode) {
        this.requestCode = requestCode;
    }
}

AlarmIdDAO

@Dao
public interface AlarmIdDAO {

    @Query("select * from AlarmIdPojo")
    List<AlarmIdPojo> getAllRequestCode();

    @Query("delete from AlarmIdPojo")
    public void deleteAllRequestCode();

    @Insert(onConflict = REPLACE)
    void addRequestCode(AlarmIdPojo pojo);
}

AppDatabase

@Database(entities = {AlarmIdPojo.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {

    public abstract AlarmIdDAO requestIdPojo();

    @Override
    protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
        return null;
    }

    @Override
    protected InvalidationTracker createInvalidationTracker() {
        return null;
    }
}

callReminder

private void callReminder() {


        //  java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        // because of this Exception , we are doing this in AsyncTask

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                List<AlarmIdPojo> idList = appDatabase.requestIdPojo().getAllRequestCode();

                Intent notifyIntent = new Intent(MainActivity.this, MyReceiver.class);
                AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                PendingIntent pendingIntent;

                for (int i = 0; i < idList.size(); i++) {


                    int requestId = idList.get(i).getRequestCode();

                    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, requestId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

                    // Cancel alarms
                    try {
                        alarmManager.cancel(pendingIntent);
                    } catch (Exception e) {
                        Log.e(TAG, "AlarmManager update was not canceled. " + e.toString());
                    }

                }

                appDatabase.requestIdPojo().deleteAllRequestCode();
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);

                // Once every request code is deleted , then once again call setReminderNotification() for fresh data.
                setReminderNotification();

            }
        }.execute();


    }

setReminderNotification

private void setReminderNotification() {

        Intent notifyIntent = new Intent(this, MyReceiver.class);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent;


        // Taking existing offline reminder data from sharePreference
        Type type = new TypeToken<List<UserReminderPojo>>() {
        }.getType();
        List<UserReminderPojo> reminderList = new Gson().fromJson(sharedPrefUtils.getString(sharedPrefUtils.DEFAULT_REMINDERS), type);


        for (int i = 0; i < reminderList.size(); i++) {

            String time = reminderList.get(i).getTime();

            String strSpit[] = time.split(":");

            String strDays[] = reminderList.get(i).getDays().split(",");


            Calendar todayWithTime = Calendar.getInstance();
            todayWithTime.set(Calendar.SECOND, 0);
            todayWithTime.set(Calendar.MILLISECOND, 0);


            for (int j = 0; j < strDays.length; j++) {

                Calendar alarm = Calendar.getInstance();
                alarm.set(Calendar.SECOND, 0);
                alarm.set(Calendar.MILLISECOND, 0);

                alarm.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0]));
                alarm.set(Calendar.MINUTE, Integer.parseInt(strSpit[1]));
                alarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j]));


                int randomPendingIntentId = generateRandomId();
                notifyIntent.putExtra(Constants.REMINDER_NAME, reminderList.get(i).getName());
                notifyIntent.putExtra(Constants.ID, randomPendingIntentId); // passing it , so that we can cancel this PendingIntent with this Id, once notification is shown.This is done to prevent past time alarm firing
                notifyIntent.putExtra(Constants.REMINDER_DAY, viewFunctions.getDayInt(strDays[j]));
                pendingIntent = PendingIntent.getBroadcast(this, randomPendingIntentId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

                if (alarm.before(todayWithTime)) {
                    alarm.add(Calendar.DATE, 7);
                }

                alarmManager.set(AlarmManager.RTC_WAKEUP, alarm.getTimeInMillis(), pendingIntent);

                insertToDB(randomPendingIntentId);

            }
        }

    }

insertToDB

// Saving to DB. keeping track  of PendingIntent unique id.
    private void insertToDB(int randomPendingIntentId) {
        alarmIdPojo = new AlarmIdPojo();
        alarmIdPojo.setRequestCode(randomPendingIntentId);

        //  java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        // because of this Exception , we are doing this in AsyncTask

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                appDatabase.requestIdPojo().addRequestCode(alarmIdPojo);
                return null;
            }
        }.execute();

    }

Upvotes: -1

Wael Abo-Aishah
Wael Abo-Aishah

Reputation: 942

I have the same issue before, please check the following details:

Not working code sample:

Intent notificationIntent = new Intent("~~~.BaseActivity");
        notificationIntent.putExtra("type", 2);
        notificationIntent.putExtra("appName", "testApp");
        notificationIntent.putExtra("messageEN", "Good evening");
        notificationIntent.putExtra("notificaitonID", 4);


        PendingIntent broadcast = PendingIntent.getBroadcast(context, 4,
                notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 18);
        calendar.set(Calendar.MINUTE, 10);
        calendar.set(Calendar.SECOND, 0);
        // this is to show it at the 6:10 

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);



        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                    calendar.getTimeInMillis(),
                    AlarmManager.INTERVAL_DAY,
                    broadcast);

Working Code:

    Intent notificationIntent = new Intent("~~~.BaseActivity");
    notificationIntent.putExtra("type", 2);
    notificationIntent.putExtra("appName", "testApp");
    notificationIntent.putExtra("messageEN", "Good evening");
    notificationIntent.putExtra("notificaitonID", 4);


    PendingIntent broadcast = PendingIntent.getBroadcast(context, 4,
            notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 18);
    calendar.set(Calendar.MINUTE, 10);
    calendar.set(Calendar.SECOND, 0);
    // this is to show it at the 6:10 

    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);


    Calendar nowCalendar = Calendar.getInstance();

    if (calendar.after(nowCalendar)) {
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY,
                broadcast);

    } else {
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY,
                broadcast);
    }

it's done only when you about to set the repeating, you need to check if it's passed or not, and if it's passed just add the wanted time for repeating

Upvotes: 0

Nick Cardoso
Nick Cardoso

Reputation: 21773

The main problem appears to be with this line:

calAlarm.set(Calendar.DAY_OF_WEEK, viewFunctions.getDayInt(strDays[j]));

What you need to realise is this is just setting the Day of the week which will be displayed in output - It is not changing the underlying date to match, which I think is what you are expecting.

Try using the following code to alter your dates to set an alarm for each day selected:

String strSpit[] = time.split(":");
String strDays[] = reminderList.get(i).getDays().split(","); //"days": "1,2,3,4,5,6,7"

Calendar todayWithTime = Calendar.getInstance(); //setting current time is redundant
todayWithTime.set(Calendar.HOUR_OF_DAY, Integer.parseInt(strSpit[0]));
todayWithTime.set(Calendar.MINUTE, Integer.parseInt(strSpit[1]));

Calendar alarm;
int today = todayWithTime.get(Calendar.DAY_OF_WEEK);
int offset, target;

for (int j = 0; j < strDays.length; j++) {

    alarm = (Calendar) todayWithTime.clone(); //now you have todays date, but correct time
    target = strDays[j];
    //saturday is biggest day of week
    offset  = (Calendar.SATURDAY - today + target) % 7; //work out how many days in the future the next occurance of this day is
    alarm.add(Calendar.DATE, offset);

    ... // the rest stays the same

}

Upvotes: 1

Newtron Labs
Newtron Labs

Reputation: 819

Problem

You alarm is going off instantly because Android will fire off any alarms that are scheduled in the past.

Some of your alarms are getting scheduled in the past because the following code is not working as you expect. Sample code from your question:

if (calAlarm.before(calNow)) 
{
   //if [it's] in the past increment
   calAlarm.add(Calendar.DATE, 1);
}

In the above code you are only adding one day to your alarm if the alarm is in the past. So let's say you are running this code on Friday and you read an alarm for Monday. Your code will add one day to the date making it Tuesday, schedule that alarm. The alarm is in the past because Tuesday is still before Friday, so Android will fire off that alarm shortly after being scheduled.

Update

It is unclear from your question what you wish to do with the reminders that are in the past. One possible solution is to schedule them 1 week into the future.

if(calAlarm.before(calNow)) 
{
   // If it's in the past increment by one week.
   calAlarm.add(Calendar.DATE, 7);
}

Upvotes: 1

Related Questions