I am developing an Android application for counseling services. Client can view their scheduled appointment in app. For example,
Next appointment: Dec 31 2016 10:00AM
Now I need to do that user will receive 2 notifications – reminders about appointment. One on 7 days before and another on 3 days before. I save this date (Dec 31 2016 10:00AM) as a String
so I can extract year, month, etc.
I found that I need to write some kind of service which will send these notifications. This is what I tried (is not completed):
public class NotificationService extends Service {
@Override
public void onCreate() {
Intent resultIntent=new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
Notification nBuilder = new Notification.Builder(this)
.setContentTitle("Don't miss! ")
.setTicker("Notification!")
.setContentIntent(pIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setSmallIcon(R.drawable.my_logo)
.setContentText("7 days left till your appointment...")
//.setWhen(System.currentTimeMillis())
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nBuilder.flags |=Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1,nBuilder);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
And method that I don't know from where to call:
public void reminder() {
Intent intent = new Intent(getActivity(), MainActivity.class);
AlarmManager manager =(AlarmManager) getActivity().getSystemService(Activity.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(getActivity().getApplicationContext(),
0,intent, 0);
Calendar cal=Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 8);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
manager.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),24*60*60*1000,pendingIntent);
}
For testing purposes I have set hour/minute/second manually but obviously I will need to extract it from date String
.
You need to write an IntentService
first. Here's an example, you can write code for showing the notification in processNotification
function.
public class NotificationIntentService extends IntentService {
private static final String ACTION_START = "ACTION_START";
public NotificationIntentService() {
super(NotificationIntentService.class.getSimpleName());
}
public static Intent createIntentStartNotificationService(Context context) {
Intent intent = new Intent(context, NotificationIntentService.class);
intent.setAction(ACTION_START);
return intent;
}
@Override
protected void onHandleIntent(Intent intent) {
try {
String action = intent.getAction();
if (ACTION_START.equals(action))
processNotification();
} finally {
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
}
private void processNotification() {
Intent resultIntent=new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
Notification nBuilder = new Notification.Builder(this)
.setContentTitle("Don't miss! ")
.setTicker("Notification!")
.setContentIntent(pIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setSmallIcon(R.drawable.my_logo)
.setContentText("7 days left till your appointment...")
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nBuilder.flags |=Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1, nBuilder);
}
}
And then create a NotificationEventReceiver
public class NotificationEventReceiver extends WakefulBroadcastReceiver {
private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE";
public static void setupAlarm(Context context, long interval) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent alarmIntent = getStartPendingIntent(context);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), interval, alarmIntent);
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Intent serviceIntent = null;
if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) {
serviceIntent = NotificationIntentService.createIntentStartNotificationService(context);
}
if (serviceIntent != null) {
startWakefulService(context, serviceIntent);
}
}
private static PendingIntent getStartPendingIntent(Context context) {
Intent intent = new Intent(context, NotificationEventReceiver.class);
intent.setAction(ACTION_START_NOTIFICATION_SERVICE);
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
And the NotificationServiceStarterReceiver
public final class NotificationServiceStarterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
long interval = getIntent().getLongExtra("alarm_interval", 0);
NotificationEventReceiver.setupAlarm(context, interval);
}
}
Add these in your AndroidManifest.xml
inside <application>
tag
<service
android:name="YourPackage.NotificationIntentService"
android:enabled="true"
android:exported="false" />
<receiver android:name="YourPackage.BroadcastReceiver.NotificationEventReceiver" />
<receiver android:name="YourPackage.BroadcastReceiver.NotificationServiceStarterReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
Now from your Activity
you may call the setupAlarm()
inside onCreate
function.
NotificationEventReceiver.setupAlarm(getApplicationContext(), interval);
You need to add WAKE_LOCK
permission in your manifest.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Here you see you can pass the interval
of the next notification to be shown. Use the interval
wisely. You might consider saving the current statuses of the appointment in the database and then trigger the alarm when necessary by passing proper interval of next alarm. That's the idea.
Update
So in your case, you don't want to show the notification when user is logged out. So in this case, you might consider keeping a SharedPreference
to store the login status. You might call the processNotification
function based on the value stored.
So the pseudo code may look like this.
if(pref.getBoolean("login_status", false)) {
// If the login status is true, process the notification
processNotification();
} else {
// Do nothing
}