Intent.putExtras not consistent - android

I have a weird situation with AlarmManager. I am scheduling an event with AlarmManager and passing in a string using intent.putExtra. The string is either silent or vibrate and when the receiver fires the phone should either turn of the ringer or set the phone to vibrate. The log statement correctly outputs the expected value each time.
Intent intent;
if (eventType.equals("start")) {
intent = new Intent(context, SReceiver.class);
} else {
intent = new Intent(context, EReceiver.class);
}
intent.setAction(eventType+Long.toString(newId));
Log.v("EditQT",ringerModeType.toUpperCase());
intent.putExtra("ringerModeType", ringerModeType.toUpperCase());
PendingIntent appIntent = PendingIntent.getBroadcast(context, 0,
intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService (Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
appIntent);
The receiver that fires when the alarm executes also has a log statement and I can see the first time around that the statement outputs the expected string either SILENT or VIBRATE but for each subsequent execution the output shows the original value on the receiver end. The alarm executes and then I change the value for putExtra to opposite string and the receiver still displays the previous value event though the call from the code above shows that the new value was passed in. The value for setAction is the same each time.
audioManager = (AudioManager) context.getSystemService(Activity.AUDIO_SERVICE);
Log.v("Start",intent.getExtras().get("ringerModeType").toString());
if (intent.getExtras().get("ringerModeType").equals("SILENTMODE")) {
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
} else {
audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
}
Any thoughts?

Your very question was asked six hours ago.
If you will have multiple PendingIntents at the same time with different extras, you will need to vary something else in the Intents, like the action string or the Uri, as described in the linked-to issue above.
If you will only have one PendingIntent at a time, but your extra may vary, just use FLAG_UPDATE_CURRENT in your call to getBroadcast().

Multiple PendingIntents:
Intent notificationIntent = new Intent(this, Oconf.class);
notificationIntent.setData(Uri.parse("text"));
Then, onNewIntent(Intent intent):
String text = intent.getData().toString();

Related

Create alarms in Android

i used below code to create alarm.
public static void RegisterForAlarmEvent(Context ct, long intervel)
{
Intent intent = new Intent(ct, AlarmReceiver.class);
PendingIntent mAlarmSender = PendingIntent.getBroadcast(ct,
constants.ALARM_ID, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager am = (AlarmManager) ct
.getSystemService(ct.ALARM_SERVICE);
Long totalTime = getCurrentTimeinMiliSeconds() + intervel;
am.set(AlarmManager.RTC, totalTime , mAlarmSender);
}
I need to check next time, if the alarm is already registered & its triggered. If its triggered then only i need to re-register.
So, i'm checking like this to know, if the alaram is already registered.
boolean alarmUp = (PendingIntent.getBroadcast(ct, id, intent, PendingIntent.FLAG_NO_CREATE)!= null);
If i call register using alaramevent method & check alarm is already registered i get NULL, literally it should return NULL, once the alarm is executed right?
How to check alarm is already fired or not?
According to docs FLAG_NO_CREATE:
Flag for use with getActivity, getBroadcast, and getService: if the described PendingIntent does not already exist, then simply return null instead of creating it.
So if the pending intent already created then it will return the reference to the previous pending intent. If not then it will return null.
And the answer to your question is maintain some shared preference value and change that value in broadcast receiver. Based on that value

Get list of registered Pending Intents in Android OS

I register alarms which I schedule to execute at given time, and it can be many alarms depending on the size of the scheduled list. But I have two questions which remains unclear to me:
1) How can I query the OS for the Pending Intents I registers? I need this for testing. The psudo code for what I want would be something like this:
List<PendingIntent> intentsInOS = context.getAllPendingIntentsOfType(AppConstants.INTENT_ALARM_SCHEDULE));
2) See the pending intent I create, I provide an action and extra data (the schedule id).
private Intent getSchedeuleIntent(Integer id) {
Intent intent = new Intent(AppConstants.INTENT_ALARM_SCHEDULE);
intent.putExtra(AppConstants.INTENT_ALARM_SCHEDULE_EXTRA, id);
return intent;
}
But we also say that the intent have FLAG_CANCEL_CURRENT. Will it cancel all pending intents with same action, or does it have to both same action AND extra data?
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, getSchedeuleIntent(schedule.id), PendingIntent.FLAG_CANCEL_CURRENT);
My code
#Override
public void run() {
List<ScheduledLocation> schedules = dbManager.getScheduledLocations();
if(schedules == null || schedules.isEmpty()){
return;
}
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//alarmManager.
// we need to get the number of milliseconds from current time till next hour:minute the next day.
for(ScheduledLocation schedule : schedules){
long triggerAtMillis = DateUtils.millisecondsBetweenNowAndNext(now, schedule.hour, schedule.minute, schedule.day);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, getSchedeuleIntent(schedule.id), PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, MILLISECONDS_IN_WEEK, pendingIntent);
}
// List<PendingIntent> intentsInOS = context.getAllPendingIntentsOfType(AppConstants.INTENT_ALARM_SCHEDULE));
}
private Intent getSchedeuleIntent(Integer id) {
Intent intent = new Intent(AppConstants.INTENT_ALARM_SCHEDULE);
intent.putExtra(AppConstants.INTENT_ALARM_SCHEDULE_EXTRA, id);
return intent;
}
1 How can I query the OS for the Pending Intents I registers?
I'm not sure you can, but you can check if a specific PendingIntent is registered or not like this :
private boolean checkIfPendingIntentIsRegistered() {
Intent intent = new Intent(context, RingReceiver.class);
// Build the exact same pending intent you want to check.
// Everything has to match except extras.
return (PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE) != null);
}
2 Will it cancel all pending intents with same action, or does it have to both same action AND extra data?
It will cancel all the PendingIntent that are resolved to be equal.
What exactly does equal means ?
The java doc of android says:
Determine if two intents are the same for the purposes of intent
resolution (filtering). That is, if their action, data, type, class,
and categories are the same. This does not compare any extra
data included in the intents.
You can read at the 7391 line here : https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/Intent.java
To sum up, all PendingIntent that are build exactly the same except extras will be cancelled.

How to properly cancel pending alarms

I can't seem to find an answer to this, but what is the criteria for passing in a matching PendingIntent to be removed from an alarm? It it based on the just the name like com.blah.package.myclass or do the Extras matter?
For example, I'm doing something like this and all alarms fire the same intent:
public void setAlarm(Context context, long nextAlarmMillis) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("alarm", this);
PendingIntent sender = PendingIntent.getBroadcast(context, 1234 /* unused */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
am.set(AlarmManager.RTC_WAKEUP, nextAlarmMillis, sender);
}
What happens is that the Alarm class can be altered, etc and passed in as an Extra. I am canceling the previous alarm, but I'm not sure if it's doing anything or if any left over alarms will remain.
Anyone know for sure?
Following is mentioned in AlarmManager documentation
Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.
Which, the filterEquals() is defined as:
Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.
I think the easiest to do is you keep the reference of PendingIntent passed to AlarmManager, and pass it to cancel. Or have a factory method to construct such pi.

When trying to set an AlarmManager event, previous one is resetting with new time and the new one is not getting triggerred

Here is my code which I tried, Steps.
1) creating an AlarmManager event by calling AM.Set( ) method suppose with time X.
2) creating another AlarmManager event suppose with time Y.
Result = first event is triggered at time Y in place of time X. and second is not triggered at all.
AlarmManager AM =(AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent();
intent.setAction(Constants.ALARM_ACTION);
intent.putExtra(Constants.EXTRA_DATA1, data[0]);
intent.putExtra(Constants.EXTRA_DATA2, data[1]);
long selectedTime = Long.parseLong(data[2]);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,0);
AM.set(AlarmManager.RTC,selectedTime, pi);
Am I doing something wrong? I need to trigger all the events .
Your first and second Intents are equivalent, and so you wind up with the same PendingIntent object as a result of your getBroadcast() call. Either:
Use a unique requestCode (2nd parameter to getBroadcast()), which I think will clear this up, or
Do something to have a unique action, data (Uri), categories, or MIME type on each Intent (extras being different are not sufficient)
By adding a count variable which will automotically increase when try to getBroadcast. it is working now.
AlarmManager AM =(AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent();
intent.setAction(Constants.ALARM_ACTION_MESSAGE);
intent.putExtra(Constants.EXTRA_NUMBER, data[0]);
intent.putExtra(Constants.EXTRA_BODY, data[1]);
long selectedTime = Long.parseLong(data[2]);
PendingIntent pi = PendingIntent.getBroadcast(mContext, count++, intent,0);
AM.set(AlarmManager.RTC,selectedTime, pi);

Display alertDialog on alarm?

I would like to display an alert dialog when the alarm goes off. Here is where i am so far. Im not sure if im doing it right.
#Override
void doTaskWork(Intent intent){
String taskId = intent.getStringExtra(TaskHelper._id);
NotificationManager mgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(this, TaskDetails.class);
notificationIntent.putExtra(TaskHelper._id, taskId);
PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Notification note = new Notification(R.drawable.stat_sys_warning, );
}
}
Alarm:
You can schedule a pending intent that drives what you want when the alarm fires. The process is:
Determine how often you want the alarm to fire. You can fire at an exact time, a specific time from now (in 10 seconds..), or a specific repeat at an interval (every x seconds/minutes/etc.). You can also set a specific time to start the repeat process. The interval isn't variable. Then you have to do one shots and set another alarm for the next time. You can also set flags that determine the time format (millis, RTC, ...). Finally, you can have the alarm firing wake up the device or let it sleep and get scheduled the next time the phone is awake.
Now, as to what is scheduled. A pending intent is scheduled. The pending intent wakes up a broadcast receiver. Here's some clips of code I use to fire a timer at 1 minute past midnight daily. (It updates a widget that has to update daily.)
Intent intent = new Intent(context, DaysReceiver.class);
PendingIntent receiverIntent = PendingIntent.getBroadcast(context,
DaysConstants.UPDATE_ALARM,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Schedule the alarm!
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(receiverIntent);
if (cancelAlarm) {
MyLog.d(TAG, "setAlarm cancel");
return;
}
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
JodaTime jtime = new JodaTime();
am.set(AlarmManager.RTC_WAKEUP, jtime.afterMidnight(), receiverIntent);
//am.setRepeating(AlarmManager.RTC_WAKEUP, jtime.nowPlusMillis(30 * 1000),
// 30 * 1000, receiverIntent);
MyLog.d(TAG, "setAlarm set");
}
The JodaTime class does date and time calculations. the afterMidnight() bit above returns 1 minute after midnight tonight. The routine can be used to just cancel an outstanding alarm.
The receiver is just a normal broadcast receiver and you can do anything in it that you can do in any other broadcast receiver. (Don't forget to put the usual stuff in the manifest. Permissions, and such like.
Here's the receiver I'm using less the imports. It's pretty straight forward. It grabs all the widgets that are on home screens and updates them. The update routine is a static function in the widget provider. It's a class because it is driven from two places. The widget config and the widget provider. The timer is rescheduled every 24 hours. The alarm won't live through a boot, but the provider's on update is driven at reboot. (All that's happening is the new day calculations are performed and the widget display is updated.) You could drop my code and put in a startActivity.
Ooops. Almost forgot. Use PendingIntent.FLAG_UPDATE_CURRENT so you don't have multiple intents stacked up accidentally...
public class DaysReceiver extends BroadcastReceiver {
static String TAG = "DaysReceiver";
#Override
public void onReceive(Context context, Intent intent) {
MyLog.d(TAG, "onReceive");
updateWidgets(context);
}
private void updateWidgets(Context context) {
MyLog.d(TAG, "updateWidgets");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName componentName = new ComponentName(context, DaysProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
final int N = appWidgetIds.length;
if (N < 1) {
MyLog.d(TAG, "No widgets");
return;
}
for (int i = 0; i < N; i++) {
MyLog.d(TAG, "Update widget " + Integer.toString(appWidgetIds[i]));
DaysProvider.updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
}
}
}
Hope I haven't rambled to much, but I'm in a rush to get back to some other business. I don't have the time to really edit the post. Hope this helped...
Do you really need a notification? Why not fire off an activity that can do the alarm notification and disappear. You can sound an alarm, vibrate the phone, whatever. Even do a notification if you still want to...
Intent intent = new Intent(context.MyAlarmResponse);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("REASONFORALARM", "What ever you want");
context.startActivity(intent);
In the manifest, use the following theme to look like a dialog:
<activity android:name=".MyAlarmResponse"
android:theme="#android:style/Theme.Dialog">
</activity>
It doesn't have to look like a dialog. You can do a full court press with a full screen display, animation, vibrate, and sound. The user than hits your cancel key and it all goes away.

Categories

Resources