Ad

Notifications Are Being Sent Out On The Wrong Time (Java, Android Studio)

In my app the user can choose a time and a date when a notification will be sent out on. However, the notifcations are not being sent out on the right time. If I choose a notification to be sent out on the same day, it will be sent out on a random time during the next day. and If I choose a notification to be sent out on a day in the future, it will be sent out on a random time during that day. So in summary, it seems to be ignoring the time and sending out notifications based on the date but it can't even get the date right when I choose a notification for the current day.

The code worked fine when the the user only had the ability to choose the time. It broke after I added the ability to choose a date for the notification.

MeeldetuletusActivity.java

public class MeeldetuletusActivity extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener {
    String timeText;
    TextView textTime;
    Button nupp_vali, nupp_katkesta, nupp_kuupaev, nupp_alarm;
    Calendar c;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_meeldetuletus);

        nupp_vali = findViewById(R.id.button2);
        nupp_katkesta = findViewById(R.id.nupp_katkesta);
        nupp_kuupaev = findViewById(R.id.button);
        nupp_alarm = findViewById(R.id.button3);

        nupp_alarm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startAlarm(c);


            }
        });

        nupp_vali.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DialogFragment timePicker = new TimePickerFragment();
                timePicker.show(getSupportFragmentManager(), "time picker");

            }
        });

        nupp_kuupaev.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DialogFragment kuupaevaValija = new KuupaevaFragment();
                kuupaevaValija.show(getSupportFragmentManager(), "date picker");
            }
        });

        nupp_katkesta.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                katkestaAlarm();
                Toast.makeText(MeeldetuletusActivity.this, "Meeldetuletus unustatud", Toast.LENGTH_SHORT).show();

            }
        });




    }


    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, 0);
    }


    public void onDateSet (DatePicker view, int aasta, int kuu, int paev) {
        c = Calendar.getInstance();
        c.set(Calendar.YEAR, aasta);
        c.set(Calendar.MONTH, kuu);
        c.set(Calendar.DAY_OF_MONTH, paev);
    }



    private void startAlarm(Calendar c) {
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, NotificationPublisher.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0);
        if (c.before(Calendar.getInstance())) {
            c.add(Calendar.DATE, 1);
        }
        Objects.requireNonNull(alarmManager).setExact(AlarmManager.RTC_WAKEUP,
                c.getTimeInMillis(), pendingIntent);
    }

    private void katkestaAlarm() {
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent myIntent = new Intent(getApplicationContext(), NotificationPublisher.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                getApplicationContext(), 1, myIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        alarmManager.cancel(pendingIntent);
    }
}

KuupaevaFragment.java

public class KuupaevaFragment extends DialogFragment {
    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Calendar c = Calendar.getInstance();
        int aasta = c.get(Calendar.YEAR);
        int kuu = c.get(Calendar.MONTH);
        int paev = c.get(Calendar.DAY_OF_MONTH);
        return new DatePickerDialog(getActivity(), (DatePickerDialog.OnDateSetListener) getActivity(),
                aasta, kuu, paev);


    }


}

TimePickerFragment.java

public class TimePickerFragment extends DialogFragment {
    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        return new TimePickerDialog(getActivity(), (TimePickerDialog.OnTimeSetListener) getActivity(),
                hour, minute, DateFormat.is24HourFormat(getActivity()));


    }


}

NotificationPublisher.java

public class NotificationPublisher extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationHelper notificationHelper = new NotificationHelper(context);
        NotificationCompat.Builder nb = notificationHelper.getChannelNotification();
        notificationHelper.getManager().notify(1, nb.build());
        Notification notification = nb.build();
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notification.defaults |= Notification.DEFAULT_SOUND;
    }
}

NotificationHelper.java

class NotificationHelper extends ContextWrapper {
    public static final String channelID = "channelID";
    public static final String channelName = "Channel Name";
    private NotificationManager notificationManager;
    public NotificationHelper(Context base) {
        super(base);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createChannel();
        }
    }
    @TargetApi(Build.VERSION_CODES.O)
    private void createChannel() {
        NotificationChannel channel = new NotificationChannel(channelID, channelName,
                NotificationManager.IMPORTANCE_HIGH);
        getManager().createNotificationChannel(channel);
    }
    public NotificationManager getManager() {
        if (notificationManager == null) {
            notificationManager = (NotificationManager)
                    getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return notificationManager;
    }
    public NotificationCompat.Builder getChannelNotification() {
        return new NotificationCompat.Builder(getApplicationContext(), channelID)
                .setContentTitle("Meeldetuletus")
                .setContentText("Teie valitud aeg on käes")
                .setSmallIcon(R.drawable.ic_baseline_notifications_active_24);
    }
}
Ad

Answer

This is most likely happenning because in Your onTimeSet and onDateSet callback methods You are initializing the c variable - the one that is supposed to represent the date on which the alarm should be fired and thus whenever You are setting a new date or time the c variable loses the previously set data:

@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
    c = Calendar.getInstance(); // This code is causing the trouble
    c.set(Calendar.HOUR_OF_DAY, hourOfDay);
    c.set(Calendar.MINUTE, minute);
    c.set(Calendar.SECOND, 0);
}

public void onDateSet (DatePicker view, int aasta, int kuu, int paev) {
    c = Calendar.getInstance(); // This code is also causing the trouble
    c.set(Calendar.YEAR, aasta);
    c.set(Calendar.MONTH, kuu);
    c.set(Calendar.DAY_OF_MONTH, paev);
}

Now, the straightforward solution would be to initialize the c in Your onCreate lifecycle method once:

Calendar c;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_meeldetuletus);

        c = Calendar.getInstance() // Initialize 'c' here!

        ...
}

And remove the redundant initialization in the callback methods:

@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
    c.set(Calendar.HOUR_OF_DAY, hourOfDay);
    c.set(Calendar.MINUTE, minute);
    c.set(Calendar.SECOND, 0);
}

public void onDateSet (DatePicker view, int aasta, int kuu, int paev) {
    c.set(Calendar.YEAR, aasta);
    c.set(Calendar.MONTH, kuu);
    c.set(Calendar.DAY_OF_MONTH, paev);
}

Now, whenever Your startAlarm(c) method will be called it will use the data that was set from both onDateSet and onTimeSet or from only one of them - basically, the changes made in those methods won't be overriden by redundantly reinitializing the c variable from those methods themselves.

Ad
source: stackoverflow.com
Ad