Pending intent with different intent but same ID - android

I have two pending Intent to use with Alarm Manager one is:
Intent i = new Intent(context, TriggerAlarm.class);
PendingIntent pi =PendingIntent.getBroadcast(context,0,i,PendingIntent.FLAG_CANCEL_CURRENT);
and the other is:
Intent i = new Intent(context, TriggerNotification.class);
PendingIntent pi = PendingIntent.getBroadcast(context,0, i,PendingIntent.FLAG_CANCEL_CURRENT);
I use these two in different methods in my application
my question is:
Are these pendingIntents differnt from each other?? because the intents are different but the Ids are same
If I set alarm manager for each of these pending intent do both of them trigger or one replace another?

So the easy way is test it directly by yourself.
I have tested it on my computer and here is what i got:
Are these pendingIntents different from each other?? because the intents are different but the Ids are same
-Yes they are different each other although the Ids are same
If I set alarm manager for each of these pending intent do both of them trigger or one replace another?
-Both of them will be triggered
Here are my code for test, you can copy and try it by yourself
Copy this method to your activity, and call it
private void setAlarmManager() {
Log.v("AlarmManager", "Configuring AlarmManager...");
Intent startIntent1 = new Intent(context, AlarmReceiverFirst.class);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, startIntent1, PendingIntent.FLAG_CANCEL_CURRENT);
Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 20);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Log.v("AlarmManager", "Starting AlarmManager for >= KITKAT version");
alarm.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent1);
alarm.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent2);
} else {
Log.v("AlarmManager", "Starting AlarmManager for < KITKAT version");
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent1);
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent2);
}
Log.v("AlarmManager", "AlarmManager has been started");
}
Create your first receiver class
public class AlarmReceiverFirst extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v(this.getClass().getSimpleName(), "first alarm receiver is called");
}
}
Create your second receiver class
public class AlarmReceiverSecond extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v(this.getClass().getSimpleName(), "second alarm receiver is called");
}
}
Register those receivers to your manifest
<receiver android:name=".AlarmReceiverFirst" />
<receiver android:name=".AlarmReceiverSecond" />
Not to be confused, what you called Id here is called request code. It is used for cancelling the pending intent.

Intents are just the action PendingIntent is bound to execute once it triggers. But this triggering criteria are entirely depending on PendingIntent itself and RequestCode is playing here a pretty good role to uniquely identify, manage and trigger PendingIntent.
Therefore, no matter what the Intent is, if the requestCode is repeated then the latter PendingIntent will trigger. If you need to trigger multiple PendingIntents, the requestCode must be different from each other.

You can have same name of intents but with different ids like following,
Intent i = new Intent(context, TriggerAlarm.class);
PendingIntent pi =PendingIntent.getBroadcast(context,System.currentTimeMillis(),i,PendingIntent.FLAG_CANCEL_CURRENT);
And
Intent i = new Intent(context, TriggerNotification.class);
PendingIntent pi = PendingIntent.getBroadcast(context,System.currentTimeMillis(), i,PendingIntent.FLAG_CANCEL_CURRENT);
This way both the intents would be distinguished differently from each other and will get triggered.You can have any unique id instead of System.currentTimeMillis()

Related

Android testing Robolectric NullPointerException creating PendingIntent

I'm trying to create a test of a method that clear some data in the database, cancel one existing AlarmManager (clearing the same PendingIntent) and deleting a file in the storage etc.
The test consist basically in three steps:
- Launch a method that create the alarms managers and put data into the database
- Launch the method that clear everything
- All the check
The test is failing when Robolectric try to create the pending intent with a NullPointerException.
#Test
public void testClearExpiredVideoDownloadedContent() {
mDatabase.post_action().addVideo(mVideoSample, StaticDbConfig.TableNames.DOWNLOADED_CONTENT);
//Run the method to create the timer for downloaded content into the database
int numberAlarmCreated = SuperBase.setUpContextExpireAlarm(mContext);
assertEquals("Alarm has not been created", 1, numberAlarmCreated);
//Run method to clear the expired content
mDatabase.delete_action().clearExpiredVideoContent(mContext, mVideoSample);
//ALL THE CHECKS
}
Method setUpContextExpireAlarm is crashing when i use the pending intent:
Intent intent = new Intent(context, ExpiredContentReceiver.class);
intent.putExtra(ExpiredContentReceiver.EXTRA_VIDEO_INFO, video);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
SimpleDateFormat format = new SimpleDateFormat(StaticAppConfig.MatDateFormat);
Date d = format.parse(video.getExpiryDate());
alarmMgr.setRepeating( //CRASHING HERE BECAUSE alarmIntent is null
AlarmManager.RTC_WAKEUP,
d.getTime(),
AlarmManager.INTERVAL_DAY,
alarmIntent);
EDIT
This is the method that create the alarm manager and pending intent:
public static int setUpContextExpireAlarm(Context context){
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
ArrayList<VideosV0> videosV0s = new DatabaseHandler(context, null).get_action().getNotExpiredDownloadedContent();
for(VideosV0 video : videosV0s){
try {
Intent intent = new Intent(context, ExpiredContentReceiver.class);
intent.putExtra(ExpiredContentReceiver.EXTRA_VIDEO_INFO, video);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
SimpleDateFormat format = new SimpleDateFormat(StaticAppConfig.MatDateFormat);
Date d = format.parse(video.getExpiryDate());
alarmMgr.setRepeating(
AlarmManager.RTC_WAKEUP,
d.getTime(),
AlarmManager.INTERVAL_DAY,
alarmIntent);
Logging.i("Setting up the alarm for content ["+video.getTitle()+" ("+video.getId()+")], the alarm will be triggered on ["+video.getExpiryDate()+"("+d.getTime()+")] ");
} catch (ParseException e) {
e.printStackTrace();
}
}
return videosV0s.size();
}
This call:
PendingIntent alarmIntent = PendingIntent.getBroadcast(context,
video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
does not create a PendingIntent. If you specify PendingIntent.FLAG_NO_CREATE then no PendingIntent is created, it will only return one if there is already one there.
If you want to have multiple alarms, you need to make sure that the PendingIntent is unique. Remove the flag PendingIntent.FLAG_NO_CREATE and make sure to use either a unique ACTION on each Intent OR a unique requestCode in the call to PendingIntent.getBroadcast(). This will ensure that it creates a new one every time.

Alarm Manager and Pending Intent Cancel Not Working

I schedule Alarm from Activity like.
private AlarmManager mAlarmManager;
mAlarmManager = (AlarmManager) ACT_ActiveSession.getAppContext()
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, LocalNotification.class);
intent.putExtra("alertBody", "");
intent.putExtra(K.SESSIONID, "");
intent.putExtra("TIME", "");
intent.putExtra("BATCHNO","");
intent.putExtra("REQUEST_CODE", "");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
ACT_ActiveSession.getAppContext(), REQUEST_CODE, intent, 0);
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, finishTime,
pendingIntent);
// alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, finishTime,
// (1 * 1000), pendingIntent);
intent.putExtra("",""); only used for some task on BroadcastReceiver
And Cancel Alarm From Fragment
private AlarmManager mAlarmManager;
mAlarmManager = (AlarmManager) mActivity
.getSystemService(Context.ALARM_SERVICE);
Intent updateServiceIntent = new Intent(mActivity,
ACT_Home.class);
PendingIntent pendingUpdateIntent = PendingIntent.getBroadcast(
mActivity, REQUEST_CODE,
updateServiceIntent, 0);
pendingUpdateIntent.cancel();
// Cancel alarms
if (pendingUpdateIntent != null) {
mAlarmManager.cancel(pendingUpdateIntent);
Log.e("", "alaram canceled ");
} else {
Log.e("", "pendingUpdateIntent is null");
}
But Alarm Manager is not cancelled.
Here i change mActivity = MyActivity's static getApplicationContext(); and also change different Flags and different Context.
Also I refer many answer. But doesn't work any code. Link1 Link2 Link3
please give me solution as soon as possible.
and apologize for my bad English.
You create the alarm using this Intent:
Intent intent = new Intent(mContext, LocalNotification.class);
But you try to cancel it using this Intent:
Intent updateServiceIntent = new Intent(mActivity, ACT_Home.class);
These Intents do not match, so the cancel does nothing. If you want to cancel the alarm you need to use an Intent in the cancel call that matches the Intent you used to schedule the alarm.

Stop alarmManager from other activity

I am trying to stop the alarmManager in the MainActivity from the onBackPressed() method in the Map activity. I have tried the code below but the alarmManager is not being stoped and still firing. How can I fix it?
Code in the MainActivity:
Intent intent = new Intent(MainActivity.this, GetLLRD.class);
intent.putExtra("json_data", json);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 20 * 1000, pendingIntent);
startService(intent);
Code in the Map Activity:
#Override
public void onBackPressed() {
Intent intent = new Intent(Map.this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
}
u problem is u use two different classes for intent to create and stop alarm:
Intent intent = new Intent(context,
GetLLRD.class);
Intent intent = new Intent(context,
MainActivity.class);
/** as in source code - new intent constructor */
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
if u want to check if u got the same pending intent as before you can try to use:
Intent.filterEquals(oherIntent);
to cancel alarm you have two options use flag or use the same intent on alarm:
PendingIntent.FLAG_CANCEL_CURRENT
& i advice to make pending intent as final - example:
/**
* create pending intent
*/
final PendingIntent pIntent(Intent alarmIntent) {
// Create a PendingIntent to be triggered when the alarm goes off
return PendingIntent.getBroadcast(getApplicationContext(), AlarmReceiver.REQUEST_CODE,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* cancel alarm
*/
public void cancelAlarm(Intent alarmIntent, Context context) {
try {
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
/** use flag cancel here */
PendingIntent pIntent = PendingIntent.getService(context, AlarmReceiver.REQUEST_CODE, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
/** cancel alarm */
alarm.cancel(pIntent);
} catch (Exception e) {
// handle exception here
}
}
why to make pending intent final ?
because to cancel alarm u need:
Create pending intent with the same id and appropriate intent FLAG.
(to get reference to current pending intent)
PendingIntent.getBroadcast(context, REQUEST_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Cancel that pending intent.
PendingIntent.cancel();
Cancel the alarm using alarm manager.
AlarmManager.cancel(PendingIntent);
A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.
if you are using activity, use
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
12345, intent,0);

Android set Exact Repeating Alarms WorkAround

I am trying to set repeating alarms in an exact fashion by manually setting an alarm to the next day the moment I receive it in a broadcast. However, I might be missing something and somehow its not working.
The Logic:
When I select the time from a time chooser, I set an exact alarm to the time given and start a pending intent which calls MyBroadCastReceiver.java (extends BroadcastReceiver) when its time. I then forward the intent with another pending intent to AlarmFireActivity. (AlarmFireActivity also has snooze which simply sets a pendingIntent to itself to fire after 5 mins.)
The MyBroadCastReceiver component hence only receives the actual alarms (not snoozes). And its functions are :
a) Get the non-repeating pending intent cancel it, then create another pending intent from the intent and then set it with the milliseconds set to the next day at the same time.
b) Start the AlarmFireActivity and show the alarm.
In AddAlarmActivity
Intent intent = new Intent(context, MyBroadcastReceiver.class);
intent.putExtra(DBHelper.COLUMN_ID,alarm.getId());
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, reminder.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, reminder.getHourOfDay());
calendar.set(Calendar.MINUTE, reminder.getMinuteOfHour());
calendar.set(Calendar.SECOND,0);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
pendingIntent);
BLog("Pending intent added at " + new SimpleDateFormat(utilFunctions.timeFormat).format(calendar.getTime()));
}
Snippet MyBroadCastReceiver.java TaskOne
Logic
Get the intent which MyBroadCastReceiver receives. Reuse the same intent in a new PendingIntent set to the next day at the same time.
Code
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
PendingIntent p1 = PendingIntent.getBroadcast(context, alarmCurrent.getReminderId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
if(p1!=null){
alarmManager.cancel(p1);
}
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, alarmCurrent.getReminderId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//for test
calendar.add(Calendar.MINUTE,1);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
pendingIntent1);
}
MyBroadCastReceiver.java TaskTwo
Logic
If the time when the alarm was set was after the time the alarm is due, do not forward the pending intent to the AlarmFireActivity.
Else forward it to the AlarmFireActivity which shows the screen to dismiss/snooze the alarm.
Code
Calendar timeSet = alarmCurrent.getAlarmReminderSetTime();
Calendar alarmTime = Calendar.getInstance();
if(timeSet!=null && alarmTime.getTimeInMillis() > timeSet.getTimeInMillis()){
Intent intent1 = new Intent(context, AlarmFireActivity.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra(DBHelper.COLUMN_ID,id);
String ext = extras.getString(DBHelper.TASK_TITLE);
if(ext!=null){
intent1.putExtra(DBHelper.TASK_TITLE,ext);
}
context.startActivity(intent1);
}else{
}
The BroadCastReceiver is doing the second task just fine. However, not the task one. Its not repeating/ resetting a new pending intent. I am guessing I must have messed up the intent/pendingIntent somewhere. I dont know which. Please help/
The solution is restart the phone. I have seen somewhere that there is a bug in a one of the os' 4.3 or so. A pending intent with a request id of 0 might fail at times. And once I restarted the phone it worked. However, there is a more standard solution which is :
Replacing
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, reminder.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
with
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, A_NUMBER_GREATER_THAN_ZERO + reminder.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
so that you are avoiding a pending intent with 0 at all times. Thanks all!

Starting up Service with AlarmManager , which already might be running

I need to run a service in time interval, for example every 2 minutes. I register it with AlarmManager, it works fine when the service stops itself before that 2 minutes is up, but there is a great chance it will take more than 2 minutes, in this case I'll need the service to be terminated and start up a new one, how can I do this?
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), Sender.class);
PendingIntent pi = PendingIntent.getService(getApplicationContext(), 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),1000 * 30, pi);
Instead of starting service by AlarmManager use broadcast. Set AlarmManager to send some broadcast intent. Create your own BroadcastReceiver that will receive that intent and in onReceive method restart(stop and start) service.
//Start AlarmManager sending broadcast
Intent intent = new Intent(context, MyBroadcastReceiver.class); // explicit
peningIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 30 * 1000, pendingIntent);
.
//BroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(SynchronizationService.class.getName());
context.stopService(serviceIntent);
context.startService(serviceIntent);
}
}
.
//Register receiver in AndroidManifest.xml in Application tag
<receiver
android:name="com.example.MyBroadcastReceiver" >
</receiver>
You should write a login in onStartCommand itself.
Check if service is running or not using variable.
If its running call stopSelf method on service,then again call startservice for same service.
start a alarm manager services u have to use this code
Intent intent = new Intent(activity.this,Sender.class);
pendingIntent = PendingIntent.getBroadcast(activity.this.getApplicationContext(),1, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),1000 * 30, pendingIntent);
for stop this broadcast receiver use this code
Intent intent = new Intent(activity.this,Sender.class);
pendingIntent = PendingIntent.getBroadcast(activity.this.getApplicationContext(), 1,intent, 0);
pendingIntent.cancel() ;

Categories

Resources