I have a widget that sets up a number of pendingIntents. All is working just fine on the widget as long as I only have a single widget on the home screen.
For the time being I decided that I was going to limit the user to only one of my home screen widgets. If one is already in use the ConfigureActivity gives the user an alertDialog box telling them they can't add a second one and then sets setResult(RESULT_CANCELED, null) and then finish().
This works just fine and keeps the user from being able to setup any further home screen widgets but for the one that is already in place most of my pendingIntents won't fire. Logcat tells me "Cannot send pending intent:"
Each of the pendingIntents is set to start up a service that is used to update the widget. If I remove the widget and reset it up it works just fine again, until I try to add a second widget. It is a bit baffling to me at this point. Anyone have any ideas as to why starting to add the 2nd widget but not completing it would cancel out my previous pendingIntents?
Incase it matters, the pendingIntents where setup with FLAG_CANCEL_CURRENT.
Here is the code used to set my intent and pendingIntents.
Intent intentDialog = new Intent(getBaseContext(), ScheduleActionsActivity.class);
intentDialog.putExtra("Action", ACTION_ENTER_SCHEDULE);
intentDialog.setAction("abc.hwRowOne");
intentDialog.putExtra("scheduleId", sch.getId());
intentDialog.putExtra("scheduleDescription", sch.getDescription());
PendingIntent pendingIntentDialog1 = PendingIntent.getActivity(getBaseContext(), 0, intentDialog, PendingIntent.FLAG_CANCEL_CURRENT);
views.setOnClickPendingIntent(R.id.hwRowOne, pendingIntentDialog1);
The line where intentDialog.setAction() changes to be unique for each row of the widget, so I thought that was making my pendingIntent unique as well.
I saw this answer last night after posting my question but I am not sure why/how it works and I am unsure where to put it in my area. It appears to set a unique data for each intent, but that is what I thought my .setAction() was doing. Multiple Instances Of Widget Only Updating Last widget
So to answer your question, no I am not using the appWidgetId at all in my intents, do I just need to pass it along as a putExtra() then on the intentDialog?
The answer to this question solved my issues:
Multiple Instances Of Widget Only Updating Last widget
I have no idea why adding the setData(uri) works but it did allow me to have more than one widget on the home screen now and the pendingIntents are unique and firing as I would expect them.
On the safe side I am also adding the appWidgetId to the intent and might need it later if I decide to allow more than one widget per device.
Related
Is it possible to create two PendingIntents with the same ID ( let's say 889) and the same intent (but different bundle) and then when I cancel PendingIntent with ID 889 will it cancel it both ?
As far as i know, you cant do that.
The System uses the ID to identify the Intents. So if you get a result you never know which of your Intents being processed.
You have to use different IDs if you want to set a repeating alarm for 2 different days. Because if you'll use the same id for each then the notification you set the latest will override the previous one and hence you'll have lose one notification.
I've got a somewhat graphically complex Android homescreen (via AppWidgetProvider) widget that I simply can't get to respond to touch events. The general idea is that tapping the widget should make it change modes for the next 4-5 seconds to display different information, but for the life of me it's showing no sign of ever receiving the Touch event.
The steps I've taken are as follows:
I've implemented an intent-filter within the Manifest.xml like so...
<action android:name="foo.kung.fancywidget.TOUCHED" />;
... and it's inside the <receiver /> container for the widget, right next to the expected APPWIDGET_UPDATE entry that Android Studio helpfully adds.
I've ensured that the Layout being used has the clickable attribute set to true on every single element (just to be thorough) including the top-level RelativeLayout itself.
I've defined the static string for the thing at the top of the ExtraFancyWidget.class, like so...
public static final String TOUCHED = "foo.kung.fancywidget.TOUCHED";
...and according to what I've been reading it should come through as the broadcast via the onRecieve handler when done like this...
if (TOUCHED.equals(intent.getAction())) {
Log.i("onReceive", "Touch event received");
}
...but with a Log.d entry at the top of the onReceive handler I can tell I'm not getting any sort of signals through there at all aside from the heartbeat coming from the system service every ten seconds.
Lastly, I'm assigning the intent just like I've been reading about
private PendingIntent createOnClickIntent(Context context) {
Intent intent = new Intent(context, ExtraFancyWidget.class);
intent.setAction(TOUCHED); // WHY DOESN'T THIS WORK?!?!?
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
...and it's literally the last thing happening in onUpdate before the view is updated
views.setOnClickPendingIntent(R.id.TheWholeWidget, createOnClickIntent(context));
appWidgetManager.updateAppWidget(appWidgetId, views);
What could I possibly be overlooking or not seeing at this point? I don't know of anything else I'm supposed to be doing or changing to make this work... it just mysteriously ignores the user. ADB never shows me any of the log entries (although it does show a number of other, silly log messages so I know that's working) that would indicate the widget ever sees me tapping it.
The problem is in step 5, where you're creating the intent. Do NOT set a specific class to the intent, rather create it with only an action, like this:
Intent intent = new Intent();
intent.setAction(TOUCHED); // this should work now
or the shorthand
Intent intent = new Intent(TOUCHED);
If it still doesn't work, consider putting a requestCode other than 0 when building the PendingIntent. Depending on the Android version you're building from, there were some bugs when using just 0.
return PendingIntent.getBroadcast(context, 1000, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Lastly, if this broadcast will be used only within your app (which is highly probable), consider using a LocalBroadcastManager.
I have created a simple application having a button. Clicking it triggers a notification, and clicking on the notification launches a new instance of the same application. However, I wanted that clicking on the notification should bring me back to the application instance from which the notification was triggered. For this I consulted the Android docs for the FLAG_ACTIVITY_NEW_TASK flag-
When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK for a flag to disable this behavior.
Based on this when creating the intent for passing to the PendingIntent, i set this flag. However, clicking on the notification still launches a new instance of the application.
What am I doing wrong ?
Remember that when you click the Notification it is from that Context that the intent is being launched. That context doesn't have the Activity on it's task (infact, it will be a blank task).
What this results in is two version of the same Activity (although still only one instance of you Application) running. Each Activity is running a different Task.
If you don't need duplicate Activities of the same type in any of your stacks you could use the answer here:
https://stackoverflow.com/a/2327027/726954
Otherwise, there are many ways to "fix" this problem, including singleton variables and Application Context methods that keeps track of which Activities are in a Running state.
You may need to search and refine your question for those.
A Task in Android is a separate User workflow. If you mange to see the Homescreen sometime, that usually means you start a new one.
Remove the flag and it should work. if it does not, try using Single top.
Try the below code:
Intent resultIntent = new Intent(context, YourActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN) resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
resultIntent, 0);
.setContentIntent(pendingIntent)
I am trying to cancel an alarm that was set last time my app was run. This alarm has a PendingIntent that was set with PendingIntent.getBroadcast and an inner Intent that contains some variables set by intent.putExtra. My question is this, I know that alarms can be canceled by calling alarmManager.cancel(pendingIntent) where pendingIntent is the same as the one used to set the alarm. But, if the variables placed into the intent are changed will the alarm still be canceled? For example, I set an alarm with intent.putExtra("Joe") where Joe is a contact name. Later my app is closed and when it is re-run I try and cancel the alarm for "Joe" but the user has changed the name of the contact to "Jones". Can I cancel the alarm without knowing the variables I put into the intent?
Thanks!
I think it should cancel the alaram anyway, even though some data is different. The cancel method says:
Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.
And filterEquals 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.
Anyhow, I'd still test it myself.
According to this question (which references the documentation), anything you add using putExtra is not taken into account when checking if an intent is equal to another one.
It shouldn't matter if the extra data is changed.
I have a widget and 4 buttons on it. The buttons are actually shortcuts to other applications. I've set an onClick pending intent for each of the buttons with this code:
Intent i = context.getPackageManager().getLaunchIntentForPackage(s);
PendingIntent pi = PendingIntent.getActivity(context, 0, i, Intent.FLAG_ACTIVITY_NEW_TASK);
remoteViews.setOnClickPendingIntent(curIconId, pi);
Usually it works fine, but sometimes it doesn't do anything and in the logcat I see a SendIntentException with the message "Cannot send pending intent".
If I update the widget (i.e. setting the pending intent again), it works fine again.
Any ideas on why it breaks down sometimes?
Thanks
It seems that whenever you send RemoteViews to a widget, you need to completely specify the widget. If you only partially specify the widget, if something causes your widget to be updated (such as a screen rotation) your widget will only be recreated with the most recent RemoteViews.
Here's the link that pointed this out to me http://www.androiddiscuss.com/1-android-discuss/95040.html
The problem was that I sent too much data to the remote views (in my case, too many icons). So the update actually failed. There is a size limit on what you can send, don't remember where I read it.
The solution in my case was to update the images with resource URLs instead of the actual images.
I'm afraid that I can't answer you - I get the same behavior on one coworker's (Motorola) phone, but not other phones.
I can point out, though, that your PendingIntent.getActivity() flags parameter is wrong: that Intent.FLAG_ACTIVITY_NEW_TASK needs to go on Intent i. The getActivity() call wants one of FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or one of the Intent.FILL_IN_ flags.
I can also mention that my clicks sometimes failed until I used PendingIntent.FLAG_CANCEL_CURRENT. This might be why adding "unique data" helps.
I had the same problem:
The widget didn't work after rotation. The problem in my widget was that I've overridden
the onReceive method and there touched the view to increment a text value. I solved the problem duplicating the setOnClickPendingIntent was in onUpdate, in the onReceive either.