5

I want to show the notifications in the specified time. Like I have a start time from when I want to see the notifications and the end time till when I want to see the notifications i.e the list of strings which should be displayed in a given time slot.

Also the list can be of any number specified by the user.

How can I decide the time of showing the notifications dynamically? Or how can I divide the time slot and strings uniformly?

For more clarifications here is the screen which shows the start time, end time and the count of strings to shown in notifications:

enter image description here

Please help. Thank you...

EDIT :

I am trying the given solution.

 List<String> times = new ArrayList<>();
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
            Date start = dateFormat.parse(startTime);
            Date end = dateFormat.parse(endTime);
            long minutes = ((end.getTime() - start.getTime()) / 1000 / 60) /
                    howMany;
            for (int i = 0; i < howMany; i++) {

                Calendar calobj = Calendar.getInstance();
                calobj.setTime(start);
                calobj.add(Calendar.MINUTE, (int) (i * minutes));
                String time = dateFormat.format(calobj.getTime());
                times.add(time);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d("timesList", times.toString());
        return times;
    }

    public static void showNotification(
            List<String> timeList, Context context,
            String quote
    ) {

        Intent notifyIntent = new Intent(context, MyNewIntentReceiver.class);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
                notifyIntent, PendingIntent.FLAG_ONE_SHOT
        );

        notifyIntent.putExtra("title", context.getString(R.string.app_name));

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

        for (String time : timeList) {
            final int random = new Random().nextInt();
            notifyIntent.putExtra("notify_id", random);

            notifyIntent.putExtra(
                    "quote",
                    quote
            );
            Date date;
            SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
            try {
              date = dateFormat.parse(time);
                System.out.println(date);

            alarmManager
                    .setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                            date.getTime(),
                            date.getTime(),
                            pendingIntent
                    );

            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        Log.d("notificationIntentSet", "Utils, pending intent set");
    }

In my Receiver building the notification.

  public class MyNewIntentReceiver extends BroadcastReceiver {

    public MyNewIntentReceiver() {
    }


    @Override
    public void onReceive(Context context, Intent intent) {

        PowerManager powerManager = (PowerManager) context.getSystemService(
                Context.POWER_SERVICE);
        PowerManager.WakeLock wakeLock =
                powerManager.newWakeLock(
                        PowerManager.PARTIAL_WAKE_LOCK,
                        "dailyfaith:wakelog"
                );
        wakeLock.acquire();

        // get id, titleText and bigText from intent
        int NOTIFY_ID = intent.getIntExtra("notify_id", 0);
        String titleText = intent.getStringExtra("title");
        String bigText = intent.getStringExtra("quote");

        // Create intent.
        Intent notificationIntent = new Intent(context, MainActivity.class);

        // use NOTIFY_ID as requestCode
        PendingIntent contentIntent = PendingIntent.getActivity(context,
                NOTIFY_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT
        );

        // get res.
        Resources res = context.getResources();

        // build notification.
        Notification.Builder builder = new Notification.Builder(context)
                .setContentIntent(contentIntent)
                .setSmallIcon(R.drawable.ic_daily_faith_icon)
                .setAutoCancel(true)
                .setContentTitle(titleText)
                .setSound(RingtoneManager
                        .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setContentText(bigText);

        Log.d("notificationBuild", "Notification Builder set");

    /*    // check vibration.
        if (mPrefs.getBoolean("vibration", true)) {
            builder.setVibrate(new long[]{0, 50});
        }*/

   /*     // create default title if empty.
        if (titleText.equals("")) {
            builder.setContentTitle(
                    context.getString(R.string.app_name));
        }*/

        // show notification. check for delay.
        builder.setWhen(System.currentTimeMillis());
        Log.d("notificationSetWhen", "Notification set when triggered");

        Notification notification = new Notification.BigTextStyle(builder)
                .bigText(bigText).build();

        NotificationManager notificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFY_ID, notification);

        wakeLock.release();
    }
}

From Activity :

  @Override
    public void onTimeSet(
            TimePickerDialog view, int hourOfDay, int minute, int second
    ) {
        String hourString = hourOfDay < 10 ? "0" + hourOfDay : "" + hourOfDay;
        String minuteString = minute < 10 ? "0" + minute : ":" + minute;
        String time = hourString + minuteString;

        if (startTimeSelected) {
            startTime = time;
            textViewStartTime.setText(time);
        }
        else if (endTimeSelected) {
            endTime = time;
            textViewEndTime.setText(time);
        }

        String count = (String) textViewQuoteCount.getText();
        count.replace("X","");

        if(startTimeSelected && endTimeSelected)
        {
            Utils.setAlarmTimeList(startTime, endTime, Integer.parseInt(count));
            Utils.showNotification(timeList); // not sure how to send the list of strings - quotes
        }

        tpd = null;
    }

I am passing the time array to pending intent, but notification is not getting triggered. I thought for alarm I also need to give the current date so I again formatted time for each notification.

But that also did not work. Any suggestions?

EDIT :

I have updated the answer by Erwin. I am getting the date also with the time now but still as I debug the receiver is also not getting called.

I have set the receiver in the manifest file :

<receiver
    android:name = ".MyNewIntentReceiver"
    android:enabled = "true"
    android:exported = "false" />

Log of timesList

  D/timesList: [Tue May 19 16:21:00 GMT+05:30 2020, Tue May 19 16:24:00 GMT+05:30 2020, Tue May 19 16:27:00 GMT+05:30 2020, Tue May 19 16:30:00 GMT+05:30 2020, Tue May 19 16:33:00 GMT+05:30 2020, Tue May 19 16:36:00 GMT+05:30 2020, Tue May 19 16:39:00 GMT+05:30 2020, Tue May 19 16:42:00 GMT+05:30 2020, Tue May 19 16:45:00 GMT+05:30 2020, Tue May 19 16:48:00 GMT+05:30 2020]

What can be the issue:

I tried to give current time to the pending intent as :

 alarmManager
                .setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                        System.currentTimeMillis(),
                        System.currentTimeMillis(),
                        pendingIntent
                );

Then I got the notification. But not getting when I am setting a date into that.

EDIT 2

   public static List<Date> setAlarmTimeList(String startTime, String endTime, int howMany) {
        List<Date> times = new ArrayList<>();
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
            Date start = dateFormat.parse(startTime);
            Date end = dateFormat.parse(endTime);
            long minutes = ((end.getTime() - start.getTime()) / 1000 / 60) /
                    (howMany - 1);
            Calendar calobj;
            for (int i = 0; i < howMany; i++) {

                calobj = Calendar.getInstance();
                calobj.set(Calendar.HOUR_OF_DAY, Integer.valueOf(dateFormat.format(start).split(":")[0]));
                calobj.set(Calendar.MINUTE, Integer.valueOf(dateFormat.format(start).split(":")[1]));
                calobj.add(Calendar.MINUTE, (int) (i * minutes));
                calobj.set(Calendar.SECOND, 0);
                times.add(calobj.getTime());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d("timesList", times.toString());
        return times;
    }


    public static void showNotification(
            List<Date> timeList, Context context,
            String quote
    ) {

        for (Date date : timeList) {
            Intent notifyIntent = new Intent(context, MyNewIntentReceiver.class);

            notifyIntent.putExtra("title", context.getString(R.string.app_name));

            final int random = new Random().nextInt();
            notifyIntent.putExtra("notify_id", random);

            notifyIntent.putExtra(
                    "quote",
                    quote
            );
            int randomInt = new Random().nextInt(1000);

            notifyIntent.putExtra("requestCode",randomInt);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                    randomInt,
                    notifyIntent, PendingIntent.FLAG_ONE_SHOT

            );

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


            Log.d("date",String.valueOf(date.getTime()));

         /*   long afterTwoMinutes = SystemClock.elapsedRealtime() + 60 * 1000;*/
            long afterTwoMinutes = System.currentTimeMillis();

            Log.d("aftertwoMinutes",String.valueOf(afterTwoMinutes));

            long datetimer = date.getTime();

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                alarmManager.setExactAndAllowWhileIdle
                        (AlarmManager.ELAPSED_REALTIME_WAKEUP,
                               date.getTime(), pendingIntent);
            else
                alarmManager.setExact
                        (AlarmManager.ELAPSED_REALTIME_WAKEUP,
                                date.getTime(), pendingIntent);
        }

        Log.d("notificationIntentSet", "Utils, pending intent set");
    }


public class MyNewIntentReceiver extends BroadcastReceiver {

    public MyNewIntentReceiver() {
    }


    @Override
    public void onReceive(Context context, Intent intent) {

        int NOTIFY_ID = intent.getIntExtra("notify_id", 0);
        String titleText = intent.getStringExtra("title");
        String bigText = intent.getStringExtra("quote");
        int requestCode = intent.getIntExtra("requestCode",0);
        sendNotification(context,bigText,NOTIFY_ID,requestCode);
    }

    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library

    }

    public static void sendNotification(Context mcontext, String messageBody,
            int notify_id,int requestCode) {
        Intent intent = new Intent(mcontext, HomeScreenActivity.class);
        PendingIntent pendingIntent = PendingIntent
                .getActivity(mcontext, requestCode /* Request code */, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );
        NotificationManager notificationManager = (NotificationManager) mcontext
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Uri defaultSoundUri = RingtoneManager
                .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel notificationChannel = new NotificationChannel
                    (
                            mcontext.getString(R.string.default_notification_channel_id),
                            "Rewards Notifications",
                            NotificationManager.IMPORTANCE_HIGH
                    );

            // Configure the notification channel.
            notificationChannel.setDescription("Channel description");
            notificationChannel.enableLights(true);
            notificationManager.createNotificationChannel(notificationChannel);
        }

        NotificationCompat.Builder notificationBuilder = new NotificationCompat
                .Builder(mcontext, mcontext.getString(R.string.default_notification_channel_id))
                .setContentTitle(mcontext.getString(R.string.app_name))
                .setSmallIcon(R.drawable.ic_daily_faith_icon)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);


        notificationManager.notify(notify_id /* ID of notification */,
                notificationBuilder.build());
    }
}

Not working for date.getTime(), System.currentTimeInMilliseconds() working for SystemClock

Sid
  • 2,792
  • 9
  • 55
  • 111
  • end time - start time / how many. like that? – Erwin May 07 '20 at 17:10
  • may be.. no idea how to do this. Looking for some suggestions. @Erwin – Sid May 08 '20 at 09:15
  • that should work. what's the issue? – Erwin May 08 '20 at 11:17
  • I have not tried. as your suggestion how to devide time by the number? can you please help me with code if possible. – Sid May 08 '20 at 11:58
  • what do you mean by strings? the words/sentence like "What you do today... - Ralph Marston" ? so you want to divide the strings base on input also? i.e. there's 10 strings in the list and user specify 5 for "how many", so there's only the first until fifth strings to display? – Erwin May 09 '20 at 06:56
  • No. I am having motivation quotes i.e sentences. These are in list. and these i want to show when the notification is set. – Sid May 09 '20 at 07:27
  • check my answer – Erwin May 09 '20 at 09:26
  • So, do you want to show the different quotes in different notifications? – Sonu Sourav May 15 '20 at 13:50
  • yes @SONUSOURAV – Sid May 15 '20 at 13:51
  • consider using the `android-job` library for scheduling of these "show notification" tasks. – Shark May 18 '20 at 15:09
  • how can it be done? @Shark – Sid May 18 '20 at 15:11
  • android job scheduling is a very touchy matter, and the guys writing the [android-job](https://github.com/evernote/android-job) library tried to make a "one to rule them all" library for job scheduling across all platform versions. Then the WorkManager came out, kinda tries to do the same thing this library has done, but as usual - not quite. – Shark May 18 '20 at 15:32
  • Are you suggesting me to use the same or not? @Shark – Sid May 18 '20 at 17:07

1 Answers1

3

try this,

    public static List<Date> setAlarmTimeList(String startTime, String endTime, int howMany) {
    List<Date> times = new ArrayList<>();
    try {
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
        Date start = dateFormat.parse(startTime);
        Date end = dateFormat.parse(endTime);
        long minutes = ((end.getTime() - start.getTime()) / 1000 / 60) /
                (howMany - 1);
        Calendar calobj;
        for (int i = 0; i < howMany; i++) {

            calobj = Calendar.getInstance();
            calobj.set(Calendar.HOUR_OF_DAY, Integer.valueOf(dateFormat.format(start).split(":")[0]));
            calobj.set(Calendar.MINUTE, Integer.valueOf(dateFormat.format(start).split(":")[1]));
            calobj.add(Calendar.MINUTE, (int) (i * minutes));
            calobj.set(Calendar.SECOND, 0);
            times.add(calobj.getTime());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    Log.d("timesList", times.toString());
    return times;
}

get start time and end time in millis and then divide it to how many times.

for alarm manager,

public static void showNotification(List<Date> timeList, Context context, String quote) {

        Intent notifyIntent = new Intent(context, MyNewIntentReceiver.class);

        notifyIntent.putExtra("title", context.getString(R.string.app_name));

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

        for (Date time : timeList) {
            final int random = new Random().nextInt();
            notifyIntent.putExtra("notify_id", random);

            notifyIntent.putExtra(
                    "quote",
                    quote
            );

            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, random,
                    notifyIntent, PendingIntent.FLAG_ONE_SHOT
            );

            alarmManager
                    .setInexactRepeating(AlarmManager.RTC_WAKEUP,
                            time.getTime(),
                            AlarmManager.INTERVAL_DAY,
                            pendingIntent
                    );
        }

        Log.d("notificationIntentSet", "Utils, pending intent set");
    }
Erwin
  • 460
  • 2
  • 6
  • Thank you.. and how to push notification on this time? – Sid May 09 '20 at 09:47
  • on android i think u can use service https://developer.android.com/guide/components/services – Erwin May 09 '20 at 10:34
  • will this be issue? "Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted. " from https://developer.android.com/reference/android/app/AlarmManager. Is alarm manager the same with android alarm/time app? if u add an alarm will it show in the alarm/time app ui? – Erwin May 09 '20 at 11:44
  • why don't you put myGlobalArray in Util class? so showNotification can directly access it – Erwin May 15 '20 at 17:44
  • I dont have problem of giving the access. How the time array list and my global array list will work simultenously? – Sid May 16 '20 at 06:36
  • If you want to show different quote every time, I think the best way is to store the quotes (sqlite, textfiles, etc) and randomize them everytime you generate new quote (so I think the best way is when you build the notification). Also it is better flagging the quotes that had ever shown, or may be set an input which give options if the quotes should always fresh or can be shown more than once – Erwin May 16 '20 at 07:51
  • Hi I am now just to test notification have set single quote for each notification and have passed the time array and generated notification for each time. But the notification is not getting triggered. Can u please check the same? – Sid May 18 '20 at 15:03
  • I have updated my answer, I put the current date to the list and return as list of dates. I think your issue is because the date is not set – Erwin May 19 '20 at 08:26
  • Hi I have updated the code with your answer still the notification is not triggered please check the edit. @Erwin – Sid May 19 '20 at 10:56
  • Please check edit as i tried with default current time it worked. @Erwin – Sid May 19 '20 at 13:18
  • Hi can you please check the issue? not getting notification when I set date in alarm manager. @Erwin – Sid May 20 '20 at 17:24
  • try [this](https://stackoverflow.com/questions/8469705/how-to-set-multiple-alarms-using-alarm-manager-in-android), I have update my answer too – Erwin May 20 '20 at 20:45
  • Just be careful with that AlarmManager. As I remember if the user restart the device or the device goes to deep sleep the AlarmManager will not be executed at the time set. – f.trajkovski May 20 '20 at 21:53
  • I have given different id's for each broadcast. It doesnt work still. @Erwin – Sid May 21 '20 at 06:43
  • updated code in edit2 please check. No error on stacktrace. getting this W/AppOps: Noting op not finished: uid 10098 pkg com.google.android.gms code 79 time=1590059016866 duration= everytime. but not sure is it related to this @Erwin – Sid May 21 '20 at 11:59
  • I've updated my answer using setInexactRepeating like your 1st attempt and it is working using API 19. If u use [ELAPSED_REALTIME_WAKEUP](https://developer.android.com/reference/android/app/AlarmManager#ELAPSED_REALTIME_WAKEUP) it will calculate the time since boot – Erwin May 21 '20 at 13:40
  • I really don't remember what options it had, but I know I had to display a certain pop up in a given time and I used some similar option to that AlarmManager (I really can't remember it), but I discovered that after restarting the phone this wasn't working. In the end I was writing the value in SharedPreferences and was checking on startup of the application if I need to set the timer again. If the time was in the past I was just displaying the notification immediately. – f.trajkovski May 24 '20 at 10:06
  • hi, I want to triegger alarm everyday now for that I used alarmManager.setInexactRepeating (AlarmManager.RTC_WAKEUP, date.getTime(),AlarmManager.INTERVAL_DAY, pendingIntent); but it is not working. Please help @Erwin – Sid May 25 '20 at 09:44