Reputation: 697
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
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
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
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
Reputation: 183
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
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
:
extend your Service
from JobIntentService
instead of IntentService
and use onHandleWork
method instead of onHandleIntent
.
add android:permission="android.permission.BIND_JOB_SERVICE"
to your Service
in AndroidManifest.xml
.
Upvotes: 16
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