Home » Android » android – I schedule a local Notification at specific time, using switch but its not triggering at set time

android – I schedule a local Notification at specific time, using switch but its not triggering at set time

Posted by: admin May 14, 2020 Leave a comment

Questions:

I’m using a switch which, when turned on will trigger alarm and start the notifications.

Initially It worked fine and triggered the alarm at set time. After changing time manually, it started working weird notification is triggering instantly when the switch is turned on but not at the specified set time.

Here is the code for the switch:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    aSwitch = (Switch) findViewById(R.id.switch1);
    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    Boolean switchState = prefs.getBoolean("locked", false);

    if(switchState) {
        aSwitch.setChecked(true);
    } else {
        aSwitch.setChecked(false);
    }

    aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if(isChecked) {
                prefs.edit().putBoolean("locked", true).apply();
                NotificationEventReceiver.setupAlarm(getApplicationContext());
                aSwitch.setChecked(true);
            } else {
                prefs.edit().putBoolean("locked", false).apply();
                NotificationEventReceiver.cancelAlarm(getApplicationContext());
                aSwitch.setChecked(false);
            }
        }
    });
  }

 @Override
 protected void onNewIntent(Intent intent) {
     super.onNewIntent(intent);
     setIntent(intent);
 }

When the switch is turned on it will trigger notifications using
WakefullBroadcast receiver.

Here is the code for receiver class:

public class NotificationEventReceiver extends WakefulBroadcastReceiver {

    private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE";
    private static final String ACTION_DELETE_NOTIFICATION = "ACTION_DELETE_NOTIFICATION";


    public static void setupAlarm(Context context) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, 07);
        calendar.set(Calendar.MINUTE, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent alarmIntent = getStartPendingIntent(context);
        alarmManager.setExact(AlarmManager.RTC_WAKEUP,
            calendar.getTimeInMillis(),
            alarmIntent);
}

    public static void cancelAlarm(Context context) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent alarmIntent = getStartPendingIntent(context);
        if(alarmManager!= null) {
            alarmManager.cancel(alarmIntent);
        }
    }

    private static PendingIntent getStartPendingIntent(Context context) {
        Intent intent = new Intent(context, NotificationEventReceiver.class);
        intent.setAction(ACTION_START_NOTIFICATION_SERVICE);
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public static PendingIntent getDeleteIntent(Context context) {
        Intent intent = new Intent(context, NotificationEventReceiver.class);
        intent.setAction(ACTION_DELETE_NOTIFICATION);
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Intent serviceIntent = null;
        if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) {
            Log.i(getClass().getSimpleName(), "onReceive from alarm, starting notification service");
            serviceIntent = NotificationIntentService.createIntentStartNotificationService(context);
        } else if (ACTION_DELETE_NOTIFICATION.equals(action)) {
            Log.i(getClass().getSimpleName(), "onReceive delete notification action, starting notification service to handle delete");
            serviceIntent = NotificationIntentService.createIntentDeleteNotification(context);
        }

        if (serviceIntent != null) {
            // Start the service, keeping the device awake while it is launching.
            startWakefulService(context, serviceIntent);
        }
    }
}

And I used the service to trigger the notification.

Here is code for background service:

public class NotificationIntentService extends IntentService {

    private static final int NOTIFICATION_ID = 1;
    private static final String ACTION_START = "ACTION_START";
    private static final String ACTION_DELETE = "ACTION_DELETE";

    public NotificationIntentService() {
        super(NotificationIntentService.class.getSimpleName());
    }

    public static Intent createIntentStartNotificationService(Context context) {
        Intent intent = new Intent(context, NotificationIntentService.class);
        intent.setAction(ACTION_START);
        return intent;
    }

    public static Intent createIntentDeleteNotification(Context context) {
        Intent intent = new Intent(context, NotificationIntentService.class);
        intent.setAction(ACTION_DELETE);
        return intent;
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(getClass().getSimpleName(), "onHandleIntent, started handling a notification event");
        try {
            String action = intent.getAction();
            if (ACTION_START.equals(action)) {
                processStartNotification();
            }
        } finally {
            WakefulBroadcastReceiver.completeWakefulIntent(intent);
        }
    }

    private void processDeleteNotification(Intent intent) {
        // Log something?
    }

    private void processStartNotification() {
        // Do something. For example, fetch fresh data from backend to create a rich notification?

        final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentTitle("Scheduled Notification")
                .setAutoCancel(true)
                .setColor(getResources().getColor(R.color.colorAccent))
                .setContentText("This notification has been triggered by Notification Service")
                .setSmallIcon(R.drawable.notification_icon);

        Intent mainIntent = new Intent(this, NotificationActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                NOTIFICATION_ID,
                mainIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pendingIntent);
        builder.setDeleteIntent(NotificationEventReceiver.getDeleteIntent(this));

        final NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(NOTIFICATION_ID, builder.build());
    }
}

Edit 1

Here is the log:

06-23 11:19:56.807 5630-5630/logi.com.notificationbyschedule I/String: On setupAlarm
06-23 11:19:56.807 5630-5630/logi.com.notificationbyschedule I/String: PendingIntent Started
06-23 11:19:56.809 5630-5630/logi.com.notificationbyschedule V/AAAAA-AlarmManager: logi.com.notificationbyschedule
06-23 11:19:56.810 978-4653/? I/AlarmManager/AlarmPowerSavingMode: the following package : logi.com.notificationbyschedule is trusted app
06-23 11:19:56.810 978-4653/? I/AlarmManager/AlarmPowerSavingMode: logi.com.notificationbyschedule not in the white list or system app, do not use exact interface.
06-23 11:19:56.810 978-4653/? I/AlarmManager/AlarmPowerSavingMode: logi.com.notificationbyschedule in whitelist or system app not forece batched
06-23 11:19:56.810 978-4653/? V/AlarmManager: set(PendingIntent{16198c6a: PendingIntentRecord{1ed2c203 logi.com.notificationbyschedule broadcastIntent}}) : type=0 triggerAtTime=1466645456807 win=-1 tElapsed=309263486 maxElapsed=309263486 interval=0 standalone=true intent=Intent { act=ACTION_START_NOTIFICATION_SERVICE cmp=logi.com.notificationbyschedule/.broadcast_receivers.NotificationEventReceiver }
06-23 11:19:56.813 978-4014/? I/AlarmManager/AlarmPowerSavingMode: logi.com.notificationbyschedule Wakeup System : 6 times
06-23 11:19:56.836 5630-5630/logi.com.notificationbyschedule I/NotificationEventReceiver: onReceive from alarm, starting notification service
06-23 11:19:56.836 5630-5630/logi.com.notificationbyschedule I/String: CreateIntentServiceStart
06-23 11:19:56.967 5630-11858/logi.com.notificationbyschedule D/NotificationIntentService: onHandleIntent, started handling a notification event
06-23 11:19:56.967 5630-11858/logi.com.notificationbyschedule I/String: ProcessStartNotification
06-23 11:19:56.974 5630-11858/logi.com.notificationbyschedule I/String: PendingIntent Deleted
06-23 11:23:58.820 5630-5630/logi.com.notificationbyschedule I/String: On CancelAlarm
06-23 11:23:58.820 5630-5630/logi.com.notificationbyschedule I/String: PendingIntent Started
06-23 11:23:58.823 5630-5630/logi.com.notificationbyschedule I/String: Inside alarmManager not null
How to&Answers:

Try changing the on trigger method to this:

private static long getTriggerAt(Date now) {
Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);

if (System.currentTimeMillis() > calendar.getTimeInMillis()){
calendar.setTimeInMillis(calendar.getTimeInMillis()+ 24*60*60*1000);// Okay, then tomorrow ...
}
return calendar.getTimeInMillis();
}

It will let u set alarm after 24 hur

Answer:

For anybody looking for a good solution to achieve the above, please also take a look at this page: https://developer.android.com/topic/performance/scheduling.html

Personally I’m a fan of the Firebase JobDispatcher solution which offers a robust solution that can even trigger scheduled events over a device reboot.