Android AlarmManager.cancel() not actually cancelling alarm/PendingIntent - java

Trying to cancel an AlarmManager alarm, isn't quite working.
I create a PendingIntent like so:
static PendingIntent makePendingIntent(int id, Bundle bundle)
{
Intent intent = new Intent(mContext.getApplicationContext(), mfLocalNotificationManager.class);
if(bundle != null)
{
intent.putExtra(BUNDLE_ID, bundle);
}
return PendingIntent.getBroadcast(mContext.getApplicationContext(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Called from SendLocalNotification:
public static int SendLocalNotification(String title, String text, String tickerText,
int timeSent, int timeOffset, String sound)
{
AlarmManager alarmMgr =
(AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Bundle notificationData = new Bundle();
notificationData.putString("title", title);
notificationData.putString("text", text);
notificationData.putString("tickerText", tickerText);
/*snip, bundle stuff*/
int noteID = title.hashCode();
notificationData.putInt("noteID", noteID);
PendingIntent pendingIntent = makePendingIntent(noteID, notificationData);
if( pendingIntent == null )
{
//This should probably be flagged as an error or an assertion.
Log.d("[MF_LOG]", "Java intent is null");
return -1;
}
//This isn't my timing code, don't hate me for it
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, timeOffset);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
pendingIntent);
return noteID;
}
And attempt to cancel it like so (passing the id we previously got back from SendLocalNotification):
public static void CancelNotification(int id)
{
String ns = Context.NOTIFICATION_SERVICE;
AlarmManager alarmMgr =
(AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = makePendingIntent(id, null);
//This doesn't work...
pendingIntent.cancel(); //<- added based on SO post, doesn't help
alarmMgr.cancel(pendingIntent);
}
Nothing seems to work, and I've followed as much of the advice on other posts as I can find (making sure the ID is the same, ensuring the PendingIntent is recreated exactly the same) and it still seems to crash. As a side note, trying to check if a notification exists using the flag PendingIntent.FLAG_NO_CREATE also doesn't work, creating a new object instead of returning null.
The device I'm testing this on is a Nexus 7 and I'm building against API 9.

You need to recreate your intent and CANCEL it like this:
AlarmManager alarm = (AlarmManager) context.getSystemService(ALARM_SERVICE);
PendingIntent peding = PendingIntent.getActivity(context, code, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
alarm.cancel(peding);

Related

Do I still need database in setting multiple alarms or reminders?

So I'm developing this Android application which has many features, and one of them is the workout reminder. We used firebase database in setting up login authentication, and the user's information.
Now for the last feature, I made a workout reminder which consists of Task Name and Time which also has a notification and. It only sets one alarm and I assume that if I applied and displayed it in a Recycler View, it will set multiple alarms. Unfortunately, it doesn't. When the reminder is displayed in the Recycler View, and when I restart the application, the reminder is gone.
I just want to humbly ask if I need to store it in a database and then retrieve it?
Thank you in advance!
Here is my code below:
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationHelper notificationHelper = new NotificationHelper(context);
NotificationCompat.Builder nb = notificationHelper.getChannel1Notification(reminderAddFragment.getTitle(), reminderAddFragment.getMessage());
notificationHelper.getManager().notify(1, nb.build());
}
}
private void startAlarm(Calendar cal) {
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1, intent, 0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
Solved it by setting different requestCode everytime I set an alarm.
private void startAlarm(Calendar cal) {
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlertReceiver.class);
final int id = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), id, intent, PendingIntent.FLAG_MUTABLE);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
Yes, you need to persist the state of alarms set by your app and display the same to the user. Once set we cannot retrieve the alarms set by the system at the app level. All we can do is dump them using adb shell using:
adb shell dumpsys alarm > alarms_dump.txt

Show alert instead of scheduled notification if the app is currently opened

I have an app that schedules a bunch of notifications (user has to answer questionnaires) locally using AlarmManager. The notification should show at certain points in the future.
I schedule the notifications like this:
private void scheduleNotification(Notification notification, int delay, int scheduleId, int notificationId) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(NotificationPublisher.INTENT, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, scheduleId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, delay);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
The intent is received by a BroadcastReceiver that calls notify on the notification attached to the intent.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String INTENT = "notification";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT)) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Notification notification = intent.getParcelableExtra(INTENT);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
}
This works fine so far. The problem that I'm facing is that I only want to show the notification if the app is currently not open/shown. If it's open I want to show an AlertDialog instead.
I know that it might be a better idea to put only the plain content of the notification into the intent and only build it when it should be displayed and I want to refactor that later on.
My main problem is, how do I determine in the onReceive of my broadcast receiver if the app is currently showing to decide if a notification or an alert should be displayed?
Or is there an entirely different approach that might work better (for example using WorkManager)?
I think you can handle it on your BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if (isForeground(context))
// AlertDialog
else
// Notification
}
public boolean isForeground(Context mContext) {
ActivityManager activityManager = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).getTaskInfo().topActivity;
return topActivity.getPackageName().equals(mContext.getPackageName());
}
return true;
}

Alarm successfully sets for future time, but not for Calendar date

I have this app where i want to set a notification on a specific date the user defines. I saw lots of code and relative answers here on SO but for some reason nothing works so far.
In this test project i have 2 methods. One that sets an alarm to ring 5 seconds on future and one that assigns the desired date.
Problem:
If i set the alarm to a second delay it works fine. The notification is shown within 5 seconds after the alarm assignment. But if i use the method that passes a Calendar date, it does nothing. Not triggers no notification
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void setAlarmOnClick(View view){
// this method call works fine
setAlarm(getNotification("Date test"), 3000);
// this one doesn't
// setAlarm(getNotification("Date test"), getDate());
}
// Here nothing happens when the date comes
private void setAlarm(Notification notification, Calendar cal) {
Intent notificationIntent = new Intent(this, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),pendingIntent );
Toast.makeText(this, "Alarm worked.", Toast.LENGTH_LONG).show();
}
// This alarm get successfully trigger here showing the notification
private void setAlarm(Notification notification, int delay) {
Intent notificationIntent = new Intent(this, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, delay, pendingIntent );
Toast.makeText(this, "Alarm worked.", Toast.LENGTH_LONG).show();
}
private Calendar getDate(){
Calendar cal=Calendar.getInstance();
cal.set(Calendar.MONTH,8);
cal.set(Calendar.YEAR,2017);
cal.set(Calendar.DAY_OF_MONTH,29);
cal.set(Calendar.HOUR_OF_DAY,11);
cal.set(Calendar.MINUTE,47);
return cal;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private Notification getNotification(String content) {
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("Scheduled Notification");
builder.setContentText(content);
builder.setSmallIcon(R.mipmap.ic_launcher);
return builder.build();
}
}
NotificationPublisher.java
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String NOTIFICATION = "notification";
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
NotificationManager notofManager = (NotificationManager)context. getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
notofManager.notify(id, notification);
}
}
I would really appreciate anykind of help!
P.S.
How can i be sure that an alarm was successfully set on a date. Even if a code works and a date is set a week form now. How can i test that it will trigger then? Obviously we can't wait a week to see that. Changing the device date is working? Thank you
Calendar month goes from 0-11 instead of 1-12 as u assumed.
So something like:
cal.set(Calendar.Month, 7 );
would set your calendar month to August.

Save variable with alarm manager event

I'm building a study planner application for Android, i have the AlarmManager set up and working to trigger a notification when the time elapses, which works fine.
When setting the alarm, the alarm details are saved into an SQLite database, when the alarm is set off, i need to recall the alarm information, is there some form of variable i can save into the database and link to the specific alarm so that i can use it in an SQLite query to find the correct entry.
UPDATE Code below:
Long nIdLong = System.currentTimeMillis();
String nId = nIdLong.toString();
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("nID", nId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent , 0);
AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
AlarmReciever:
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{
Toast.makeText(context, notificationId, Toast.LENGTH_LONG).show();
}catch(Exception e){
e.printStackTrace();
}
}
Thanks in advance
You're sending a String through the intent, it needs a Long, this code should work.
Long nIdLong = System.currentTimeMillis();
String nId = nIdLong.toString();
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("nID", nIdLong);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent , 0);
AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
While setting the alarm, first retrieve the id which will be created while inserting alarm details to SQLite via
long uniqueId = db.insert(your query);
And put that in the intent for PendindIntent for AlarmManager
Intent alarmIntent = new Intent(this, AlarmEventReceiver.class);
alarmIntent.putExtra("dbId", uniqueId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent , 0);
Inside the onReceive() of AlarmEventReceiver, you can get the id & retrieve the data from DB.
#Override
public void onReceive(Context context, Intent intent) {
long dbId = intent.getLongExtra("dbId", 0);
}

Multiple notification on same intent

I am writing an application and in this application I need to set multiple notification with same intent just like open my application whenever user tap on any notification.
All the notification comes on different time and date without having any data but the problem is, if I set two notification for 03:27 PM and 03:28 PM then the first notification (03:27 PM) is canceled (Overwritten by second) and second is working correctly.
I am currently using this code for achieving this goal:
this method is used to set notification from Activity:
public static void setNotificationOnDateTime(Context context, long fireTime)
{
int requestID = (int) System.currentTimeMillis();
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, NotificationReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, requestID, i, 0);
am.set(AlarmManager.RTC_WAKEUP, fireTime, pi);
}
and my NotificationReceiver class look like this:
NotificationManager nm;
#Override
public void onReceive(Context context, Intent intent) {
Log.w("TAG", "Notification fired...");
nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent;
Bundle bundle = intent.getExtras().getBundle("NotificationBundle");
if(bundle == null)
{
contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, SplashScreen.class), 0);
}
else
{
contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MenuScreen.class)
.putExtra("NotificationBundle", bundle), 0);
}
Notification notif = new Notification(R.drawable.ic_launcher,
"Crazy About Android...", System.currentTimeMillis());
notif.setLatestEventInfo(context, "Me", "Message test", contentIntent);
notif.flags |= Notification.FLAG_AUTO_CANCEL;
nm.notify(1, notif);
}
I alerady spend a lot time on googling and found some solutions but they didn't work for me here is the link of some of them:
android pending intent notification problem
Multiple notifications to the same activity
If any one knows how to do this please help me.
Quote:
Post a notification to be shown in the status bar. 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.
But you're always using 1 for the id parameter. Use a unique ID when you post several notifications.
Update If that doesn't help, you can still create Intents which do not compare as being equal, while having an equal effect.
this may be helpful
notif.flags |= Notification.FLAG_ONGOING_EVENT;
the notification will never close...
Try to set as below :
contentIntent=PendingIntent.getActivity(p_context, i, new Intent(context, MenuScreen.class),PendingIntent.FLAG_CANCEL_CURRENT);
It might help you.

Categories

Resources