admin 7798
admin 7798

Reputation: 697

How To give notifications on android on specific time?

I want to give notification to my app on a specific time. Say everyday i have to give notification on 7 AM even if the app is closed.

How can i do this? Any tutorial? Please mention the link.

Upvotes: 48

Views: 98003

Answers (6)

4xMafole
4xMafole

Reputation: 477

Here is my solution, tested on android 10 but compatible with all the previous versions of android.

MainActivity.class

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    ....
    reminderNotification();

}

public void reminderNotification()
{
    NotificationUtils _notificationUtils = new NotificationUtils(this);
    long _currentTime = System.currentTimeMillis();
    long tenSeconds = 1000 * 10;
    long _triggerReminder = _currentTime + tenSeconds; //triggers a reminder after 10 seconds.
    _notificationUtils.setReminder(_triggerReminder);
}

NotificationUtils.class

public class NotificationUtils extends ContextWrapper
{

    private NotificationManager _notificationManager;
    private Context _context;

    public NotificationUtils(Context base)
    {
        super(base);
        _context = base;
        createChannel();
    }

    public NotificationCompat.Builder setNotification(String title, String body)
    {
        return new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.noti_icon)
                .setContentTitle(title)
                .setContentText(body)
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);
    }

    private void createChannel()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, TIMELINE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
            getManager().createNotificationChannel(channel);
        }
    }

    public NotificationManager getManager()
    {
        if(_notificationManager == null)
        {
            _notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }

        return _notificationManager;
    }

    public void setReminder(long timeInMillis)
    {
        Intent _intent = new Intent(_context, ReminderBroadcast.class);
        PendingIntent _pendingIntent = PendingIntent.getBroadcast(_context, 0, _intent, 0);

        AlarmManager _alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

        _alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, _pendingIntent);
    }

}

ReminderBroadcast.class

public class ReminderBroadcast extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        NotificationUtils _notificationUtils = new NotificationUtils(context);
        NotificationCompat.Builder _builder = _notificationUtils.setNotification("Testing", "Testing notification system");
        _notificationUtils.getManager().notify(101, _builder.build());
    }
}

AndroidManifest.xml

<application>
    ...
    <receiver android:name=".custom.ReminderBroadcast"/>
</application>

NB: CHANNEL_ID and TIMELINE_CHANNEL_NAME, have been created on another class.

For example,

CHANNEL_ID = "notification channel";

TIMELINE_CHANNEL_NAME = "Timeline notification";

If there are any misconceptions about my code and bugs, don't hesitate to comment. I will reply as soon as possible.

Upvotes: 6

Shia G
Shia G

Reputation: 1464

First you need to use a BroadcastReceiver, and because a broadcast receiver can only run for a short time, it's a better practice to use an intent service, here you have an example how to do it.

When handling a broadcast, the application is given a fixed set of time (currently 10 seconds) in which to do its work. If it doesn't complete in that time, the application is considered to be misbehaving, and its process immediately tossed into the background state to be killed for memory if needed.

(from the android developer blog)

This is the broadcast receiver class:

    public class MyReceiver extends BroadcastReceiver {
        public MyReceiver() {
        }

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

            Intent intent1 = new Intent(context, MyNewIntentService.class);
            context.startService(intent1);
        }
    }

Register it in the manifest:

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

This is the intent service class:

    public class MyNewIntentService extends IntentService {
        private static final int NOTIFICATION_ID = 3;

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

        @Override
        protected void onHandleIntent(Intent intent) {
            Notification.Builder builder = new Notification.Builder(this);
                builder.setContentTitle("My Title");
                builder.setContentText("This is the Body");
                builder.setSmallIcon(R.drawable.whatever);
            Intent notifyIntent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            //to be able to launch your activity from the notification 
            builder.setContentIntent(pendingIntent);
            Notification notificationCompat = builder.build();
            NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
            managerCompat.notify(NOTIFICATION_ID, notificationCompat);
        }
    }

Register it in the manifest:

    <service
        android: name=".MyNewIntentService"
        android: exported="false" >
    </service>

Then in your activity, set the alarm manager to start the broadcast receiver at a specific time and use AlarmManager's setRepeating method to repeat it. In the example below, it will repeat it every day:

    
     Intent notifyIntent = new Intent(this,MyReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast
                (context, NOTIFICATION_REMINDER_NIGHT, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,  System.currentTimeMillis(),
                1000 * 60 * 60 * 24, pendingIntent);

I hope this will help you.

Upvotes: 38

Amir sohail
Amir sohail

Reputation: 43

Use NotifyMe Android Library for simple notifications. Very easily set a delay or time when you want the notification to popup. Notification will popup through system reboots.

Download library with Jitpack.io Add this to your build.gradle file for your app.

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Add this to your dependencies in build.gradle for your project.

dependencies {
        implementation 'com.github.jakebonk:NotifyMe:1.0.1'
}

Example Create a NotifyMe Builder Object

NotifyMe.Builder notifyMe = new NotifyMe.Builder(getApplicationContext());

Then set the fields you want.

notifyMe.title(String title);
notifyMe.content(String content);
notifyMe.color(Int red,Int green,Int blue,Int alpha);//Color of notification header
notifyMe.led_color(Int red,Int green,Int blue,Int alpha);//Color of LED when 
notification pops up
notifyMe.time(Calendar time);//The time to popup notification
notifyMe.delay(Int delay);//Delay in ms
notifyMe.large_icon(Int resource);//Icon resource by ID
notifyMe.rrule("FREQ=MINUTELY;INTERVAL=5;COUNT=2")//RRULE for frequency of 
//notification
notifyMe.addAction(Intent intent,String text); //The action will call the intent when 
//pressed

After all the fields that you want are set just call build()!

notifyMe.build();

Upvotes: 1

Vaibhav Rai
Vaibhav Rai

Reputation: 183

  • Get the Alarm service from the system.
  • Make a pending intent, passing in the broadcast receiver class's name.
  • Make a calendar object and set the time of it too 8 am.
  • Check if the current time is past 8. If yes then add another day to it.
  • Call the set repeating method of AlarmManager class.

Sample code for the same:

alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);   
alarmIntent = new Intent(context of current file, AlarmReceiver1.class); 
AlarmReceiver1 = broadcast receiver

    pendingIntent = PendingIntent.getBroadcast(  Menu.this, 0, alarmIntent, 
PendingIntent.FLAG_UPDATE_CURRENT);
    alarmIntent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
    alarmManager.cancel(pendingIntent);

    Calendar alarmStartTime = Calendar.getInstance();
    Calendar now = Calendar.getInstance();
    alarmStartTime.set(Calendar.HOUR_OF_DAY, 8);
    alarmStartTime.set(Calendar.MINUTE, 00);
    alarmStartTime.set(Calendar.SECOND, 0);
    if (now.after(alarmStartTime)) {
        Log.d("Hey","Added a day");
        alarmStartTime.add(Calendar.DATE, 1);
    }

     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 
alarmStartTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
     Log.d("Alarm","Alarms set for everyday 8 am.");

Coming to the broadcast receiver class. You need to register your broadcast receiver in the manifest. This will cause you to receive clock events. Override the onReceive method of this broadcast receiver and make a notification there itself or make a seperate notification building service and build and display your notification there.

The manifest code snippet:

The broadcast receiver code snippet:

public class AlarmReceiver1 extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
  Intent service1 = new Intent(context, NotificationService1.class);
service1.setData((Uri.parse("custom://"+System.currentTimeMillis())));
          context.startService(service1);
}

Notification building service code snippet:

public class NotificationService1 extends IntentService{

private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1;
Notification notification;
@Override
protected void onHandleIntent(Intent intent) {
Context context = this.getApplicationContext();
       notificationManager = 
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, Activity to be opened after clicking on the 
notif);
        Bundle bundle = new Bundle(); 
        bundle.putString("test", "test");
        mIntent.putExtras(bundle);
        pendingIntent = PendingIntent.getActivity(context, 0, mIntent, 
PendingIntent.FLAG_UPDATE_CURRENT);     

        Resources res = this.getResources();
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        notification = new NotificationCompat.Builder(this)
                    .setContentIntent(pendingIntent)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
                    .setTicker("ticker value")
                    .setAutoCancel(true)
                    .setPriority(8)
                    .setSound(soundUri)
                    .setContentTitle("Notif title")
                    .setContentText("Text").build();
        notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
        notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
        notification.ledARGB = 0xFFFFA500;
        notification.ledOnMS = 800;
        notification.ledOffMS = 1000;
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICATION_ID, notification);
        Log.i("notif","Notifications sent.");

}

}

Upvotes: 2

Vasily Kabunov
Vasily Kabunov

Reputation: 6751

A solution from the accepted answer will not work properly on Android 8 Oreo (api level 26) and higher due to background service limits (https://developer.android.com/about/versions/oreo/background.html#services) and will cause an exception like this when the app is in background:

java.lang.IllegalStateException: Not allowed to start service Intent xxx: app is in background

One of the possible workarounds is using JobIntentService:

  1. extend your Service from JobIntentService instead of IntentService and use onHandleWork method instead of onHandleIntent.

  2. add android:permission="android.permission.BIND_JOB_SERVICE" to your Service in AndroidManifest.xml.

Upvotes: 16

SaNtoRiaN
SaNtoRiaN

Reputation: 2202

You can use AlarmManager to set alarm at specified time

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("firstTime", false)) {

    Intent alarmIntent = new Intent(this, AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);

    AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, 7);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 1);

    manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
            AlarmManager.INTERVAL_DAY, pendingIntent);

    SharedPreferences.Editor editor = prefs.edit();
    editor.putBoolean("firstTime", true);
    editor.apply();
}

I used SharedPreferences to check that's not the first time to run the app and if it is, you set that alarm otherwise do nothing instead of resetting the alarm each time you start your app.
Use a BroadcastReceiver to listen when the alarm happens

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // show toast
        Toast.makeText(context, "Alarm running", Toast.LENGTH_SHORT).show();
    }
}

Use another receiver to listen to device boots so that you can reset the alarm

public class DeviceBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            // on device boot compelete, reset the alarm
            Intent alarmIntent = new Intent(context, AlarmReceiver.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);

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

            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.set(Calendar.HOUR_OF_DAY, 7);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 1);

            manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                    AlarmManager.INTERVAL_DAY, pendingIntent);
        }
    }
}

add the permission to the manifest

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

then register your receivers

<receiver android:name=".DeviceBootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />

Upvotes: 17

Related Questions