How to show daily offline notifications in Android 10?

Issue

I want to send offline notifications to users daily.Tried many things like: Alarm manager,Work manager but no luck.The notifications are not triggered or they just trigger at later.

Any way to get the job done?

Alarm function:

public void StartAlarm()
{
    Calendar calendar  Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY,23);
    calendar.set(Calendar.MINUTE,59);
    calendar.set(Calendar.SECOND,0);


    AlarmManager alarmManager  (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);


    Intent alarmIntent  new Intent(getApplicationContext(), AlarmReceiver.class);
    //alarmIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

    Log.d("LOG", String.valueOf(calendar.getTimeInMillis()));

    PendingIntent pendingIntent  PendingIntent.getBroadcast(getApplicationContext(), 156, alarmIntent, 0);

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else {
            alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }

Work manager code:

 public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
    super(context, workerParams);
}


@NonNull
@Override
public Result doWork() {


    StartAlarm();


    Log.d("In worker","yes");


    return Result.success();
}

Work manager driver:

public void StartPeriodicWorker()
{

    final PeriodicWorkRequest periodicWorkRequest  new
            PeriodicWorkRequest.Builder(MyWorker.class,24,TimeUnit.HOURS)
            .addTag("Birthday")
            .build();

    WorkManager.getInstance(getApplicationContext()).enqueueUniquePeriodicWork("Birthday Notifier", ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);

}

Alarm Receiver:

  public class AlarmReceiver extends BroadcastReceiver {

private DatabaseReference myRef;
private ArrayList<String> allPeoples;

private int numberOfPeoples;

private Context ctx;

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

    Toast.makeText(context,"In alarm receiver",Toast.LENGTH_LONG).show();

    ctx  context;
    initPeoples();

}

public String getCurrentDate() {
    Calendar calendar  Calendar.getInstance();
    SimpleDateFormat mdformat  new SimpleDateFormat("d MMMM");
    String strDate  mdformat.format(calendar.getTime());
    return strDate;
}


private  void initPeoples() {

    FirebaseDatabase database  FirebaseDatabase.getInstance();
    myRef  database.getReference("Users");
    myRef.keepSynced(true);

    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            allPeoples   new ArrayList<>();
            for(DataSnapshot snapshot : dataSnapshot.getChildren()){
                if(snapshot.getKey().equals("Teacher") || snapshot.getKey().equals("Staff")){
                    for(DataSnapshot faculty : snapshot.child("peoples").getChildren()){
                        String birthday  (String) faculty.child("DOB").getValue();

                        if(birthday.equals(getCurrentDate())) {
                            String member  birthday;
                            allPeoples.add(member);
                        }
                    }
                }else{
                    for(DataSnapshot student : snapshot.child("peoples").getChildren()){
                        String birthday  (String) student.child("DOB").getValue();

                        if(birthday.equals(getCurrentDate())) {
                            String member  birthday;
                            allPeoples.add(member);
                        }
                    }
                }
            }

            numberOfPeoples  allPeoples.size();

            ShowNotification();

        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });

}

public void ShowNotification()
{
    String CHANNEL_ID  "Channel_1453";
    String CHANNEL_NAME  "Birthday Notification";

    NotificationManagerCompat manager  NotificationManagerCompat.from(ctx);

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
        NotificationChannel channel  new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
                NotificationManager.IMPORTANCE_HIGH);
        manager.createNotificationChannel(channel);
    }

    Notification notification  new NotificationCompat.Builder(ctx, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_stat_notify)
            .setContentTitle("Birthday Reminder")
            .setColor(Color.GREEN)
            .setContentText("Click to see who has birthday today!")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)
            .setCategory(NotificationCompat.CATEGORY_MESSAGE)
            .setContentIntent(PendingIntent.getActivity(ctx, 0, new Intent(ctx, Birthday.class), PendingIntent.FLAG_UPDATE_CURRENT))
            .build();

    manager.notify(454, notification);
}

}

Solution

I can see one possible issue, and it’s possible to do this without the workmanager (assuming the device has a healthy connection at the time the notification runs).

Instead of doing your network in the receiver itself, I suggest starting a service (foreground service if above Android 8.0), and doing your work there. This is because android’s time limit for a receiver is much lower than a service/foreground service. So to me, it sounds plausible that your receiver is killed before the network request completes, and so no notification is shown.

You can show the notification in the service, and also schedule the next alarm since setExactAndAllowWhileIdle isn’t a repetitive alarm on it’s own. So in your receiver, something like:

@Override
public void onReceive(Context context, Intent intent) {
        Intent service  new Intent(context, BirthdayNotifyService.class);
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            context.startForegroundService(service);
        } else {
            context.startService(service);
        }
}

Then a possible service class:

public class BirthdayNotifyService extends IntentService {

    public BirthdayNotifyService() {
        super("BirthdayNotifyService");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            //Build a simple notification to show if a foreground service is neccesary
            Notification noti  notiBuilder.build();
            startForeground(1, noti);
        }

        //Do your network request work here. After completed, show your birthday notification and stop the foreground service.
    }
}

To stop the service, right AFTER you display your notification for birthdays, use the following:

stopForeground(true);
stopSelf();

UPDATE: I used this method on my phone (Xiaomi Redmi Note 8 plus), it worked a few times but then stopped working. It works perfectly fine on stock android, but not on all devices. Therefore I would still say this is not a reliable solution to send notification on specific times.

Answered By – Amin

Leave a Comment