Unable to cancel the alarm from AlarmManager - java

I have an AlarmManager that notifies me every 10 seconds. Everything works just fine but for some reason I can't cancel the alarm. Here's my code.
public class AlarmNotifReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
//things
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
}
as expected I call this CancelAlarm() method from my other classes but for some reason it does not cancel and keep notifying me like nothing happened.
Note: SetAlarm() also works just fine.
Thanks in advance.

Alarm should be created and cancelled on Same Pending intent.In your case you are creating Pending Intent Twice.
Your code should look like below.
public class AlarmNotifReceiver extends BroadcastReceiver {
PendingIntent pi;
AlarmManager am;
Intent i;
#Override
public void onReceive(Context context, Intent intent) {
pi = PendingIntent.getBroadcast(context, 0, i, 0);
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
i = new Intent(context, AlarmNotifReceiver.class);
//things
}
public void SetAlarm(Context context) {
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10 * 1000, pi);
}
public void CancelAlarm(Context context) {
am.cancel(pi);
}
}

Try to cancel Pendingintent--
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT).cancel();
Hope this helps

Try this.
Android: Get all PendingIntents set with AlarmManager
To cancel all alarm, first you have to find all the pending intent for that and cancel alarm using that.

Try like this
public class AlarmNotifReceiver extends BroadcastReceiver {
AlarmManager am = null;
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
//things
}
public void SetAlarm(Context context)
{
am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
am.cancel(pi);
}
}

Your problem is that you're creating a NEW intent instead of cancelling the existing one. Function SetAlarm should place the intent into a "global" variable and the CancelAlarm function should just call
am.cancel(global_pi);
The above worked for me in a service, but:
If this is impossible (since that's a Receiver), try setting a new alarm with the (new) intent first.

Related

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;
}

How to create a custom notification in android

I would like to create a custom notification service in my app.
I wouldn't use the google service (google cloud messaging).
Is there a way to create a daemon that check every X seconds a particular condition on my app db and show a notification?
Thank you,
edit
I call this method in MainActivity's oncreate(). I get the times from my db
private void restartNotify() {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.cancel(pendingIntent);
ArrayList<String> item = new ArrayList<String>();
item = GetLists.GetTimesListForNotification(this);
for (int i = 0; i < item.size(); ++i) {
String time = item.get(i);
int Position = time.indexOf(":");
int hour = Integer.parseInt(time.substring(0, Position));
int min = Integer.parseInt(time.substring(Position + 1));
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, min);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
am.set(AlarmManager.RTC, cal.getTimeInMillis(),
pendingIntent);
}
And this is my broadcast receiver
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager mManager;
mManager = (NotificationManager) context.getApplicationContext()
.getSystemService(
context.getApplicationContext().NOTIFICATION_SERVICE);
Intent intent1 = new Intent(context.getApplicationContext(),
MainActivity.class);
Notification notification = new Notification(R.drawable.ic_launcher,
"New message to read", System.currentTimeMillis());
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
context.getApplicationContext(), 0, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(context.getApplicationContext(),
"notification are work", "it's work",
pendingNotificationIntent);
mManager.notify(0, notification);
}
}
You can use AlarmManager + BroadcastReceiver like so:
private void setRecurringAlarm(Context context) {
Intent downloader = new Intent(this, MyStartServiceReceiver.class);
downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, downloader, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 6000, 10000, pendingIntent);
}
BroadcastReceiver class:
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//do the stuff...
}
}
And don't forget to register receiver in your manifest:
<receiver android:name=".MyStartServiceReceiver"
android:enabled="true"/>
You have to use Alarm Manager to schedule code for execution every specific period. take a look here:
http://developer.android.com/training/scheduling/alarms.html

Android daily notification shows up multiple times at the wrong time

I am trying to get an android notification to show up at noon every day. The notification seems to show up once whenever the device is started, then somewhat sporadically afterwards.
Here is my service:
public class myService extends Service {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v(TAG, "on onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LoginActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("App name")
.setContentText("Notification")
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify("main", 1, mBuilder.build());
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and Receiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "LocationLoggerServiceManager";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast Received");
handleMessage(context, intent);
}
private void handleMessage(Context context, Intent intent)
{
PendingIntent contentIntent = PendingIntent.getService(context, 0, new Intent(context, myService.class), 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(contentIntent);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 12);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 24*60*60*1000 , contentIntent);
}
}
Any pointers are appreciated. Thank you.
I attempted to set up my own notification / alarm class. The only way I found to manage it was to extend the Android calendar.
If you would like to try it this way see this link for a start:
http://developer.android.com/guide/topics/providers/calendar-provider.html
I have an example of this approach however i am at work, I can provide my code later if you need it!
What may be happening is that the system kills your Service to free up memory and since the superclass's onStartCommand() returns START_STICKY, recreates it later, causing your notification to sporadically appear.
Really, if the Service's purpose is just to make a Notification consider moving that portion of code some sort of BroadcastReceiver or stop the Service after the Notification is created.

Simple AlarmManager example for firing an activity in 10 minutes

I've found many similar questions to this, but they're too complicated (too much code), at least I think.
Can this thing be done in a few code of lines? I want to fire an activity in 10 (let's say) minutes, that's it. Thank you.
To Set Alarm for 10 Minutes(let's say) Use this code
AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, ShortTimeEntryReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),10*60*1000, pendingIntent);
To Start Activity
public class ShortTimeEntryReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
// Your activity name
Intent newIntent = new Intent(context, ReminderPopupMessage.class);
newIntent.putExtra("alarm_message", message);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
In your Manifest File Add the following
<receiver android:name=".ShortTimeEntryReceiver"
android:enabled="true"
android:process=":remote">
</receiver>
This function I use sets or cancels an alarm depending on the "Set" parameter
public static void SetAlarm(Context c, long AlarmTime, int ItemID, String Message, Boolean Set) {
Intent intent = new Intent(c, AlarmReceiver.class);
intent.putExtra("Message", Message);
intent.putExtra("ItemID", ItemID);
PendingIntent sender = PendingIntent.getBroadcast(c, 8192 + ItemID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Clear the seconds to 0 for neatness
Calendar ca = Calendar.getInstance();
ca.setTimeInMillis(AlarmTime);
ca.set(Calendar.SECOND, 0);
AlarmTime = ca.getTimeInMillis();
// Get the AlarmManager service
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
if (Set) {
am.set(AlarmManager.RTC_WAKEUP, AlarmTime, sender);
} else {
am.cancel(sender);
}
}
You would then need a Broadcast Receiver to handle the alarm and do whatever it is you want to do.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String Message = bundle.getString("Message");
int ItemID = bundle.getInt("ItemID");
// Do what you want to do, start an activity etc
} catch (Exception e) {
e.printStackTrace();
}
}
}

how would create an alarm manager with reciever to put phone on silent at certain time?

I have been trying this for a while and i cannot figure out the best way to do it and i do not really understand what teh broadcast reciever does. what i would like is for the alarm to be fired and maybe an activity to put the phone on silent.
thanks in advance
Use the AlarmManager's setRepeating method to run your task periodically. To change the ringer you can use the AudioManger's setRingerMode method.
This is working code. It wakes CPU every 10 minutes and shows notification.
Add to Manifest.xml:
...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver android:process=":remote" android:name="Alarm"></receiver>
...
Code:
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}

Categories

Resources