Displaying multiple notifications at user-defined times - android

I've been programming in Android for over a year but have never used notifications before, which I need for one of my apps.
In the app, there are events that can be set at different times. Obviously, the user can choose to change these times or add/remove events.
I plan to use notifications to notify the user 5 minutes before their event starts.
I've read through the Android developer docs for Building a Notification and Services (which I am also new to). I have decided to use Services because I figured that the notification would need to be shown even when the app not running. To help me, I have been referring to one particular SO answer as guidance.
I begun by experimenting a little with the notification builder classes in my NotificationService class like so:
public class NotificationService extends IntentService {
private static final int NOTIFICATION_ID = 1;
public NotificationService() {
super(NotificationService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
showNotification();
}
private void showNotification() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle("Test notification")
.setSmallIcon(R.drawable.ic_event_black_24dp)
.setContentText("Test description")
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID, builder.build());
}
}
I also use the following to start this Service in the splash screen of my app:
Intent serviceIntent = new Intent(this, NotificationService.class);
startService(serviceIntent);
To display notifications at specific times, I've read about AlarmManager, mainly through SO questions like this one. I also know that to display multiple notifications, I would need different notification ids (like my constant NOTIFICATION_ID).
However, what I am unsure of is dynamically updating the times that notifications would be shown each time an event is added, removed, or its times changed.
Could someone provide me some guidance on how I could achieve this?

You implement notification part. For notify user at Specific time you should set AlarmManager. I paste whole code you need then explain each part:
public class AlarmReceiver extends WakefulBroadcastReceiver {
AlarmManager mAlarmManager;
PendingIntent mPendingIntent;
#Override
public void onReceive(Context context, Intent intent) {
int mReceivedID = Integer.parseInt(intent.getStringExtra(AddReminderActivity.EXTRA_REMINDER_ID));
// Get notification title from Reminder Database
ReminderDatabase rb = new ReminderDatabase(context);
ApiReminderModel reminder = rb.getReminder(mReceivedID);
String mTitle = reminder.getName();
// Create intent to open ReminderEditActivity on notification click
// handling when you click on Notification what should happen
Intent editIntent = YourActivity.createActivity(context, reminder.getChannelId(), reminder.getStartTime());
PendingIntent mClick = PendingIntent.getActivity(context, mReceivedID, editIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Create Notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_logo))
.setSmallIcon(R.drawable.ic_logo)
.setContentTitle(context.getResources().getString(R.string.app_name))
.setTicker(mTitle)
.setContentText(mTitle)
.setContentIntent(mClick)
.setSound(ringtoneUri)
.setAutoCancel(true)
.setOnlyAlertOnce(true);
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.notify(mReceivedID, mBuilder.build());
}
public void setAlarm(Context context, Calendar calendar, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Put Reminder ID in Intent Extra
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(AddReminderActivity.EXTRA_REMINDER_ID, Integer.toString(ID));
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Calculate notification time
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using notification time
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + diffTime, mPendingIntent);
// Restart alarm if device is rebooted
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
public void cancelAlarm(Context context, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Cancel Alarm using Reminder ID
mPendingIntent = PendingIntent.getBroadcast(context, ID, new Intent(context, AlarmReceiver.class), 0);
mAlarmManager.cancel(mPendingIntent);
// Disable alarm
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
As you see we have setAlarm which notify users at specific time. I also pass calendar instance which is initiated before ( assign a time which user should be notify).
Calendar mCalendar = Calendar.getInstance();
mCalendar.add(Calendar.DAY_OF_YEAR, 7);// assume you want send notification 7 days later
new AlarmReceiver().setAlarm(getApplicationContext(), mCalendar, id);
We have another method cancelAlarm. If you want to delete a Alaram just pass unique ID of Alarm (Which already used for creation of Alarm).
Also don't forget to add this Service to your AndroidManifest.xml:
<receiver android:name=".service.AlarmReceiver" />
There is only on thing remain When you reboot your device you should set AlarmsManager again so you need a BootRecivier service.

Related

Android AlarmManager only sending last scheduled notification

I am creating a research app that should prompt the user 4 times a day to enter their mood - by sending a notification, which when clicked launches the correct Activity. I am able to schedule these notifications using AlarmManager, however only the last scheduled notification ever shows. So although I schedule them for 9AM, 2PM, 5PM, and 8PM, it only ever sends a notification at 8PM.
How can I get all of the scheduled notifications to show?
Here is my code for setting (one of) the alarms (from a notification manager class). Note that al alarms are set using the same instance of AlarmManager:
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, 9);
cal.set(Calendar.MINUTE, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), createPendingIntent(9, this));
Here is the createPendingIntent method (in the same notification manager class):
public static PendingIntent createPendingIntent(int hour, Context c){
Intent notificationIntent = new Intent(c, AlarmBroadcastReceiver.class);
notificationIntent.putExtra("time", hour);
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0 , notificationIntent , PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
Here is the BroadcastReceiver for the alarm:
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationSender.createNotification(context);
}
}
And finally the createNotification method:
public static void createNotification(Context c){
Log.e("notif?", "creating");
Intent intent = new Intent(c, UpdateMoodActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
int notificationId = new Random().nextInt();
PendingIntent pendingIntent = PendingIntent.getActivity(c, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(c, "com.lizfltn.phdapp.notifChannelID")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("SoftMood")
.setContentText("Please record your mood")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(c);
notificationManager.notify(notificationId, builder.build());
}
Yes I know this isn't the best-practice way of doing things, or even the neatest, but unfortunately I need to get code working ahead of writing good code :P
I've tried various configurations of setting the alarm, e.g. using elapsed realtime instead of RTC, only setting the alarm, setting the exact alarm, etc, but there might be something fundamental I'm not understanding about how those work.
Any help appreciated!
Can you try with same id in pending intent and notify.?
Notification id in createNotification() method is random id.
int notificationId = new Random().nextInt();
and id used in createPendingIntent method is 0.
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0 , notificationIntent , PendingIntent.FLAG_UPDATE_CURRENT);
Can you try with using same value for second parameter of getBroadcast?

Want to write a code to only send notification at certain time, but somehow the alarmManager is not working and it shows some errors

Not sending notification at selected time, when I ran my code, directly showed notification
and showed error as well
Here is the error message: E/NotificationManager: notifyAsUser: tag=null, id=12345, user=UserHandle{0}
I thought the error message was due to Build.VERSION.SDK_INT, but after adding that, the error message is still there.
Place all of these under onCreate:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 13);
calendar.set(Calendar.MINUTE,9)
;
Intent intent = new Intent ();
intent.setAction("com.example.Broadcast");
PendingIntent contentIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// PendingIntent alarmIntent = PendingIntent.getBroadcast(this,0, intent,0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, contentIntent);
and here is the extend.
public class wakeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
setNotification(context);
}
protected void setNotification(Context context){
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class), 0);
String ChannelId = "12345";
int uniID = 12345;
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,ChannelId )
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("Hi")
.setAutoCancel(true)
.setWhen(System.currentTimeMillis())
.setContentText("Please Rate.");
builder.setContentIntent(contentIntent);
//
// Send notification to your device
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId("com.myApp");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"com.myApp",
"My App",
NotificationManager.IMPORTANCE_DEFAULT
);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
manager.notify(uniID, builder.build());
}
}
Can someone please help me with this?
You are very confused.
In your code you call NotificationManager.notify(). This will show the Notification immediately.
You do:
Intent intent = new Intent(this, MainActivity.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this,0, intent,0);
This won't work. You have created a PendingIntent which will be sent via broadcast using an Intent that is for an Activity! What do you want to happen? Do you want an Activity to be launched or do you want a BroadcastReceiver to be triggered?
I think what you want to do is as follows:
Create an Intent for a BroadcastReceiver, wrap that in a PendingIntent using getBroadcast() and pass that to the AlarmManager so that the broadcast Intent will be set at some future time.
Create a class that extends BroadcastReceiver. In onReceive() create the Notification and call NotificationManager.notify() to post the Notification. In the Notification you can set a PendingIntent that opens your Activity so that if the user clicks on the Notification your Activity will be launched. To do this, call PendingIntent.getActivity() and pass an Intent that contains MainActivity.class.

Handle click events on Notification bar that redirects users to the app, Lollipop

When users click the icon of my app on the Notification bar, users will be redirected to my app.
Can anyone provide sample code? How to subscribe to the click event, and the redirection.
Update
My application might be using some services that cause the display of icon on Notification bar.
My application is calling SetForeground, not getBroadcast().
Update 2
how can I redirect users to the last Activity rather than the hard-code activity? For example, the last Activity might be different when users navigate to different activity.
Notification click event in xamarin forms
It's a sample from my app, it works. I think you can do somthing similar.
public class AlarmReceiver extends BroadcastReceiver {
public final static String NOTIF_TEXT = AlarmSetActivity.class.getPackage() + ".NOTIF_TEXT";
private String notifText;
#Override
public void onReceive(Context context, Intent intent) {
notifText = intent.getExtras().getString(NOTIF_TEXT);
//().getExtras().getString(NOTE_BODY);
Toast.makeText(context, "Notification from " + R.string.app_name,
Toast.LENGTH_LONG).show();
buildNotification(context);
}
private void buildNotification(Context context) {
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "default_channel_id";
String channelDescription = "Default Channel";
Notification.Builder builder = new Notification.Builder(context);
Intent intent = new Intent(context, **EditorActivity.class**);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(context.getString(R.string.notificTitle)).setContentText(notifText)
.setContentInfo(context.getString(R.string.notificInfo)).setTicker(context.getString(R.string.notifTicker))
.setLights(0xFFFF0000, 500, 500)
//.setChannelId(id)
.setContentIntent(pendingIntent).setAutoCancel(true);
Notification notification = builder.build();
//notification.so
notificationManager.notify(2, notification);
}
}
And:
private void setAlarm(Calendar targetCal) {
mTimeTextView.setText(R.string.alarm_on);
mTimeTextView.append(String.valueOf(targetCal.getTime()));
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
intent.putExtra(AlarmReceiver.NOTIF_TEXT,notificationText);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getApplicationContext(), RQS_TIME, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, targetCal.getTimeInMillis(),
pendingIntent);
}

Android Studio - Trouble setting off notifications with broadcast receiver

So my program is supposed to set off a notification a few hours after the application has been stopped (minutes are being used just now for testing). It does this, however the problem with it is that if the code is executed a second time before a notification has been pushed, then no notification is pushed at all.
Override
public void onStop() {
super.onStop();
Calendar calendar = Calendar.getInstance();
int alarmTime = (calendar.get(Calendar.MINUTE)) + 3;
calendar.set(Calendar.MINUTE,alarmTime);
Intent intent3 = new Intent(getApplicationContext(),timeReceiver.class);
PendingIntent pendingIntent3 = PendingIntent.getBroadcast(getApplicationContext(),100,intent3,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pendingIntent3);
}
#Override
protected void onRestart() {
super.onRestart();
//this.onCreate(null);
}
This is what my broadcast receiver class looks like...
public class timeReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager =(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent repeating_intent = new Intent(context, RepeatingActivity.class);
repeating_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context,100,repeating_intent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentIntent(pendingIntent);
builder.setSmallIcon(android.R.drawable.arrow_up_float);
builder.setContentTitle("Timer Notification");
builder.setContentText("blaaah blaaah blah");
builder.setAutoCancel(true);
notificationManager.notify(100,builder.build());
}
}
My expectation is that the alarm would reset and trigger 3 minutes after the last execution of the onStop() method, but this does not happen. I don't really understand why it doesn't, if anyone could give me insight/ a possible solution I would be grateful. Also the SDK version is 24.
You can schedule your notification with NotificationCompat.Builder#setWhen(long), no need for alarm manager.
int notification1Id = 56748;
Calendar calendar = Calendar.getInstance();
int alarmTime = (calendar.get(Calendar.MINUTE)) + 2;
calendar.set(Calendar.MINUTE,alarmTime);
long timeMs = calendar.getTimeInMillis();
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notifications
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelID);
builder.setContentIntent(pendingIntent);
builder.setSmallIcon(android.R.drawable.arrow_up_float);
builder.setContentTitle("It's been a while...");
builder.setContentText("Remember to keep track of your calories using the calorie counter");
builder.setAutoCancel(true);
builder.setWhen(timeMs);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notification1Id, builder.build());

Android notifications not displaying

I have written a code that is supposed to display notifications. I am choosing hour and minute from TimePicker component (notifications popping up every day at given time), then create an intent for Notification receiver. The database is updated with proper info and everything is being set with the AlarmManager. The request code ("code" variable) is unique for each notification. I am pasting code snippets below:
SettingActivity class:
findViewById(R.id.buttonNotification).setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
int hour, minute, id;
Calendar calendar = Calendar.getInstance();
PendingIntent pendingIntent;
calendar.set(Calendar.HOUR_OF_DAY,timePicker.getCurrentHour());
calendar.set(Calendar.MINUTE, timePicker.getCurrentMinute());
Intent intent = new Intent(getApplicationContext(),Notifcation_receiver.class);
hour = timePicker.getCurrentHour();
minute = timePicker.getCurrentMinute();
if(extra!=null){
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),extra.getInt("Code"),intent,PendingIntent.FLAG_UPDATE_CURRENT);
intent.putExtra("Code",extra.getInt("Code"));
db.updateNotification(hour,minute,extra.getInt("ID"));
}
else{
int code= Notification.getID();
intent.putExtra("Code",code);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),code,intent,PendingIntent.FLAG_UPDATE_CURRENT);
db.insertNotification(hour,minute);
}
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pendingIntent);
startActivity(new Intent(SettingActivity.this, NotificationActivity.class));
}
});
}
Notification receiver class:
public class Notifcation_receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int code = intent.getIntExtra("Code",0);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent repeating_intent = new Intent(context,MainActivity.class);
repeating_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context,code,repeating_intent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentIntent(pendingIntent)
.setSmallIcon(android.R.drawable.arrow_up_float)
.setContentTitle("title")
.setContentText("text")
.setAutoCancel(false);
notificationManager.notify(code,builder.build());
}
}
I can't seem to find the problem, causing the lack of planned notifications. Thank You for any help.
The problem was, as Mehmed mentioned, no channel set for the NotificationService.
Logcat log:
"E/NotificationService: No Channel found for pkg=com.example.kuba.quizapp, channelId=null"
It worked on API 22, but for 25 and higher the notification must be build with extra channel info.

Categories

Resources