How would I set multiple notification trigger times from one Activity? - java

I have a menu case that allows me to set a notification trigger based on the "term" start date. This takes user input where they select the start date for a term and creates a notification alert based on their choice:
case R.id.notify:
String startDateFromScreen = editTextStartDate.getText().toString();
String endDateFromScreen = editTextEndDate.getText().toString();
Date startDate = null;
Date endDate = null;
try {
startDate = sdf.parse(startDateFromScreen);
endDate = sdf.parse(endDateFromScreen);
} catch (ParseException e) {
e.printStackTrace();
}
Intent intent = new Intent(AddEditTermActivity.this,
MyReceiver.class);
Long triggerStartDate = startDate.getTime();
Long triggerEndDate = endDate.getTime();
intent.putExtra("start", editTextTermTitle.getText().toString() + " starts today!");
intent.putExtra("end", editTextTermTitle.getText().toString() + " ends today!");
PendingIntent startSender = PendingIntent.getBroadcast(AddEditTermActivity.this, MainActivity.termStartAlertNum++, intent, 0);
PendingIntent endSender = PendingIntent.getBroadcast(AddEditTermActivity.this, MainActivity.termEndAlertNum++, intent, 0);
AlarmManager startAlerm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
startAlerm.set(AlarmManager.RTC_WAKEUP, triggerStartDate, startSender);
return true;
I also want to be able to create a separate notification based on their selected end time, as you can see from some of the code in that section. This intent is sent to a receiver class:
public class MyReceiver extends BroadcastReceiver {
String startChannelID = "test";
static int notificationID;
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, intent.getStringExtra("start"), Toast.LENGTH_LONG).show();
createNotificationChannel(context, startChannelID);
Notification start = new NotificationCompat.Builder(context, startChannelID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentText(intent.getStringExtra("start"))
.setContentTitle("Starting").build();
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(notificationID++, start);
}
private void createNotificationChannel(Context context, String CHANNEL_ID) {
CharSequence name = context.getResources().getString(R.string.channel_name);
String description = context.getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
But when creating a separate notification/notification manager, it only shows the last notification line in the code. How can I make it so that both notifications are set on the respective dates? Time does not matter in this example.

Related

How to call a method from dbhelper in broadcastReceiver

I want to excute a method in my dbhelper immediately my alarm service run, the if that code runs successfully I want to display a notification based on the result of the method execution. I want this to run even if my app is idle or in the background
this is my broadcastReceiver
public class ExpiryBroadcast extends BroadcastReceiver {
//db helper
private DbHelper dbHelper;
private final String CHANNEL_ID = "expiring_items";
private final int NOTIFICATION_ID = 200;
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
dbHelper.updateExpiryRow();
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_item_expiring)
.setContentTitle("ProExm Product Expiry")
.setContentText("Some products will soon expire, check now...")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
}
}
this is my alarmmanager
public void startAlertAtParticularTime() {
// alarm first vibrate at 14 hrs and 40 min and repeat itself at ONE_HOUR interval
intent = new Intent(this, ExpiryBroadcast.class);
pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 280192, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 17);
calendar.set(Calendar.MINUTE, 02);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
Toast.makeText(this, "Alarm will vibrate at time specified",
Toast.LENGTH_SHORT).show();
}
I have this code in my dbhelper class which I want to run before notification even if my application is asleep or in the background
public void updateExpiryRow(){
int daysToExpiry = 0;
String selectQuery = "SELECT * FROM " + Constants.ITEMS_TABLE;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
//looping through all records and add to list
if(cursor.moveToFirst()){
do{
ModelItems modelItems = new ModelItems(
""+cursor.getInt(cursor.getColumnIndex(Constants.C_ID)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_ITEM_NAME)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_ITEM_IMAGE)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_ITEM_PRICE)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_ITEM_MANUFACTURER)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_DESC)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_EXPIRY_DATE)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_MANUFACTURE_DATE)),
Integer.parseInt(""+cursor.getInt(cursor.getColumnIndex(Constants.C_DAYS_TO_EXPIRY)))-1,
""+cursor.getString(cursor.getColumnIndex(Constants.C_ADDED_TIMESTAMP)),
""+cursor.getString(cursor.getColumnIndex(Constants.C_UPDATED_TIMESTAMP))
);
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("dd-MM-yyyy");
try {
Date date = formatter.parse(modelItems.getItemExp());
LocalDate now = LocalDate.now();
String text = now.format(formatter2);
Date dateNow = formatter.parse(text);
long diffInMillies = Math.abs(date.getTime() - dateNow.getTime());
long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
daysToExpiry = (int) (long) diff;
} catch (ParseException e) {
e.printStackTrace();
}
ContentValues values = new ContentValues();
// id will be inserted automatically as we set AUTOINCREMENT in query
//insert data
String timestamp = ""+System.currentTimeMillis();
values.put(Constants.C_ID, modelItems.getId());
values.put(Constants.C_ITEM_NAME, modelItems.getItemName());
values.put(Constants.C_ITEM_IMAGE, modelItems.getItemImage());
values.put(Constants.C_ITEM_PRICE, modelItems.getItemPrice());
values.put(Constants.C_ITEM_MANUFACTURER, modelItems.getItemManufacturer());
values.put(Constants.C_DESC, modelItems.getItemDesc());
values.put(Constants.C_EXPIRY_DATE, modelItems.getItemExp());
values.put(Constants.C_MANUFACTURE_DATE, modelItems.getItemMfd());
values.put(Constants.C_DAYS_TO_EXPIRY, daysToExpiry);
values.put(Constants.C_ADDED_TIMESTAMP, modelItems.getAddedTime());
values.put(Constants.C_UPDATED_TIMESTAMP, timestamp);
//insert row, it will return record id of saved record
db.update(Constants.ITEMS_TABLE, values, Constants.C_ID +" = ?", new String[] {modelItems.getId()});
//add record to list
}while (cursor.moveToNext());
}
//close db connection
db.close();
}
First of all you have to initialize the dbHelper
dbHelper = new DbHelper();
Then just call your method.
And this broadcast receiver will work if your app is idle or even closed
Try to use a foreground service and start it from your broadcast receiver, it will work even if the app is killed, and in your service, you can instantiate your DbHelper and execute what you want, after finishing tasks just stop it.

How to prevent notifications being overwritten each time a new notification is created?

I am trying to send a notification at a specific time after registering an item on a database (6 hours or 12 hours). The notification works fine when I only register one item, however if I register 2 items in a close period of time the first notification is overwritten by the second.
I know that I have to add ID's to the pending intents and maybe an id to the actual notification however I am not very familiar with the alarmManager class and I do not know where I should be adding the IDs.
How do I make these two notifications independent of one another?
NotificationHelper Class:
public static class NotificationHelper extends ContextWrapper {
public static final String channel1ID = "channel1ID";
public static final String channel1Name = "USER1";
private NotificationManager mManager;
public NotificationHelper(Context base) {
super(base);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannels();
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void createChannels() {
NotificationChannel channel1 = new NotificationChannel(channel1ID, channel1Name, NotificationManager.IMPORTANCE_HIGH);
channel1.enableLights(true);
channel1.enableVibration(true);
channel1.shouldVibrate();
channel1.setShowBadge(true);
channel1.setLightColor(R.color.colorPrimary);
channel1.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setUsage(USAGE_NOTIFICATION)
.build();
channel1.setSound(uri, audioAttributes);
getManager().createNotificationChannel(channel1);
}
public NotificationManager getManager() {
if (mManager == null) {
mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return mManager;
}
public NotificationCompat.Builder getChannel1Notification() {
return new NotificationCompat.Builder(getApplicationContext(), channel1ID)
.setContentTitle("Dressing")
.setContentText("Please scan the dressing on your: " + (et_DressingPos.getText().toString().trim()))
.setSmallIcon(R.drawable.ic_cnoticiation_scan);
}
}
AlarmReceiver Class:
#Override
public void onReceive(Context context, Intent intent) {
Camera2Register.NotificationHelper notificationHelper = new Camera2Register.NotificationHelper(context);
NotificationCompat.Builder nb = notificationHelper.getChannel1Notification();
Intent intent2 = new Intent(context, Camera2.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent2, 0);
nb.setContentIntent(pendingIntent);
notificationHelper.getManager().notify(1, nb.build());
}
}
startAlarmScan and startALarmChange Methods:
private void startAlarmScan() {
int requestCode = ("someString" + System.currentTimeMillis()).hashCode();
Long time = System.currentTimeMillis();
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("randomRequestCode", requestCode);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent, 0);
long milliseconds = 5000;
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, (time + milliseconds), pendingIntent);
//}
}
private void startAlarmChange() {
int requestCode = ("someString" + System.currentTimeMillis()).hashCode();
Long time = System.currentTimeMillis();
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("randomRequestCode", requestCode);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent, 0);
long milliseconds = 30000;
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, (time + milliseconds), pendingIntent2);
//}
}
I have set the time delay for the two different notifications to 5 and 30 seconds. If register and class the two startAlarmScan and startAlarmChange methods within 30 seconds of each other. the first scheduled notification will be overwritten by the second.
I am beginning to think the problem may lie in the structuring of my notification system, is a Receiver class necessary? There is no mention of it in the notification documentation on Android.
You are using a constant value "1" for your notification id here: notificationHelper.getManager().notify(1, nb.build());
from the docs: Here "If a notification with the same id has already been posted by your application and has not yet been canceled, it will be replaced by the updated information"
Change this 1 to a unique number for each notification and you should see them all come through.
Edit
You also do the same thing on the line:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent2, 0);
That request code "1" is used to compare pending intents using filterEquals(Intent intent) This question talks about it.

make alarms survive boot

I have created an app, that allows a user to input assignment deadlines and then a time to be notified that the assignment is due, this all works fine, however, I can't find a clear example of how to make the alarms survive a reboot.
The database stuff on the receiver is just to populate the notification with the specific assignments information. The alarms themselves are not saved in the database, the times and dates are set by user input and directly passed to alarm manager.
Alarm creation page:
Long nIdLong = System.currentTimeMillis();
String nId = nIdLong.toString();
final int _id = (int) System.currentTimeMillis();
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("nID", nIdLong);
// make sure the intent have id's
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, _id, alarmIntent , 0);
AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
This is my receiver:
public void onReceive(Context context, Intent intent)
{
long dbId = intent.getLongExtra("nID", 0);
String notificationId = Long.toString(dbId);
Log.i("App", "called receiver method");
try{
userDbHelper = new UserDbHelper(context.getApplicationContext());
sqLiteDatabase = userDbHelper.getReadableDatabase();
cursor = userDbHelper.getAssignmentNotification(notificationId, sqLiteDatabase);
if (cursor.moveToFirst()) {
do {
id = cursor.getString(0);
name = cursor.getString(1);
subject = cursor.getString(2);
date = cursor.getString(3);
time = cursor.getString(4);
} while (cursor.moveToNext());
}
NotificationGenerator.generateNotification(context, date, time, name, subject);
}catch(Exception e){
e.printStackTrace();
}
}
https://examples.javacodegeeks.com/android/core/activity/android-start-service-boot-example/
This example shows how to start services on boot, save the alarms into a database and have the on boot service run through all the saved alarms to have them recreated upon each boot.

Notification doesnt work

I've created a notification and it's just doesnt show up.
My code in the main activity: `boolean alarm = (PendingIntent.getBroadcast(this, 0, new Intent("ALARM"), PendingIntent.FLAG_NO_CREATE) == null);
if(alarm){
Intent itAlarm = new Intent("ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,itAlarm,0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 3);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
AlarmManager alarme = (AlarmManager) getSystemService(ALARM_SERVICE);
alarme.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),60000, pendingIntent);
}
my code in the Broadcast Reciver:
public class BroadcastManager extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
String yourDate = "04/05/2016";
String yourHour = "13:07:00";
Date d = new Date();
DateFormat date = new SimpleDateFormat("dd/MM/yyyy");
DateFormat hour = new SimpleDateFormat("HH:mm:ss");
if (date.equals(yourDate) && hour.equals(yourHour)){
Intent it = new Intent(context, MainActivity.class);
createNotification(context, it, "new mensage", "body!", "this is a mensage");
}
}catch (Exception e){
Log.i("date","error == "+e.getMessage());
}
}
public void createNotification(Context context, Intent intent, CharSequence ticker, CharSequence title, CharSequence descricao){
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent p = PendingIntent.getActivity(context, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setTicker(ticker);
builder.setContentTitle(title);
builder.setContentText(descricao);
builder.setSmallIcon(R.drawable.web_hi_res_512);
builder.setContentIntent(p);
Notification n = builder.build();
//create the notification
n.vibrate = new long[]{150, 300, 150, 400};
n.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(R.drawable.web_hi_res_512, n);
//create a vibration
try{
Uri som = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone toque = RingtoneManager.getRingtone(context, som);
toque.play();
}
catch(Exception e){}
}
}
Above code will start alarm service on every 3 seconds and repeat on every 1 minute. If you want to generate notification on specific time then, You have to add,
calendar.add(Calendar.HOUR, 13);
calendar.add(Calendar.MINUTES, 07);
calendar.add(Calendar.SECONDS, 00);
and remove this line,
calendar.add(Calendar.SECOND, 3);
I hope it may work for you.

How to implement multiple timed notifications in Android

I have this final feature for the app that I am creating. The app that I have made is a calendar that saves events and notifies the user when the time arrives. The problem that I encounter is that when I create multiple notifications (or multiple events), it only notifies the very latest that was created. I tried to make different IDs for the notifications but to no success. Here the codes that I modified. It was from a tutorial that I've seen.
AlarmTask.java
public class AlarmTask implements Runnable{
// The date selected for the alarm
private final Calendar date;
// The android system alarm manager
private final AlarmManager am;
// Your context to retrieve the alarm manager from
private final Context context;
private final long alarmID;
public AlarmTask(Context context, Calendar date, long id) {
this.context = context;
this.am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
this.date = date;
this.alarmID = id;
}
#Override
public void run() {
// Request to start are service when the alarm date is upon us
// We don't start an activity as we just want to pop up a notification into the system bar not a full activity
Intent intent = new Intent(context, NotifyService.class);
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
intent.putExtra("alarmID", alarmID);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC, date.getTimeInMillis(), pendingIntent);
}
}
NotifyService.java
public class NotifyService extends Service {
/**
* Class for clients to access
*/
public class ServiceBinder extends Binder {
NotifyService getService() {
return NotifyService.this;
}
}
// Unique id to identify the notification.
private static final int NOTIFICATION = 143;
// Name of an intent extra we can use to identify if this service was started to create a notification
public static final String INTENT_NOTIFY = "com.gpplsmje.mac.calendar.utils.INTENT_NOTIFY";
// The system notification manager
private NotificationManager mNM;
#Override
public void onCreate() {
Log.i("NotifyService", "onCreate()");
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// If this service was started by out AlarmTask intent then we want to show our notification
if(intent.getBooleanExtra(INTENT_NOTIFY, false)){
showNotification(intent.getLongExtra("alarmID", 0));
}
// We don't care if this service is stopped as we have already delivered our notification
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// This is the object that receives interactions from clients
private final IBinder mBinder = new ServiceBinder();
/**
* Creates a notification and shows it in the OS drag-down status bar
*/
#SuppressWarnings("deprecation")
private void showNotification(long alarmID) {
SaveEvent event = new SaveEvent(this);
event.open();
Log.d("Notification: ID", alarmID + "");
// This is the 'title' of the notification
CharSequence title = event.getEventName(alarmID);
// This is the icon to use on the notification
int icon = R.drawable.icon_reminder;
// This is the scrolling text of the notification
CharSequence text = event.getEventDesc(alarmID);
// What time to show on the notification
long time = System.currentTimeMillis();
event.close();
Intent backToEventDetail = new Intent(this, CalendarEventDetail.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, backToEventDetail, 0);
Notification notify = new Notification.Builder(this)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(icon)
.setContentIntent(contentIntent).getNotification();
notify.defaults = Notification.DEFAULT_SOUND;
notify.flags = Notification.FLAG_AUTO_CANCEL;
// Send the notification to the system.
mNM.notify(Integer.parseInt(String.valueOf(alarmID)), notify);
// Stop the service when we are finished
stopSelf();
}
}
From what I understand with the code, the AlarmTask.java receives the alarm date and sets the it to notify on that date. The ID that I passed is the ID of the event that I saved in the phone's database. But I couldn't get it to add multiple notifications. It only receives the latest that I saved. I would want it to get all the events and set notification for each of those events. Can somebody help me with it?
Create pending intent like this
PendingIntent contentIntent = PendingIntent.getActivity(this, (int)(Math.random() * 100), backToEventDetail, PendingIntent.FLAG_UPDATE_CURRENT);
Create Pending intent with below code
PendingIntent contentIntent = PendingIntent.getActivity(this, Integer.parseInt(String.valueOf(alarmID)), backToEventDetail, Intent.FLAG_ACTIVITY_NEW_TASK );

Categories