Android Pending Intent to start service - android

So I have a service, in the onCreate() I setup 3 pending intents to start the same service, each having different extra data to specify the action. I'm creating a notification, and I want to use one pending intent as the click action, one as the dismiss action, and the third is for an alarm.
Intent iCancel = new Intent(this, BootService.class);
Intent iAlarm = new Intent(this, BootService.class);
Intent iDismiss = new Intent(this, BootService.class);
// each will have actions
iAlarm.putExtra(INTENT_ACTION, INTENT_ALARM_FIRED);
iCancel.putExtra(INTENT_ACTION, INTENT_CANCEL);
iDismiss.putExtra(INTENT_ACTION, INTENT_DISMISS);
PendingIntent piCancel = PendingIntent.getService(
this,
0,
iCancel,
Intent.FILL_IN_DATA);
mPiAlarm = PendingIntent.getService(this, 0, iAlarm, Intent.FILL_IN_DATA);
PendingIntent piDismiss = PendingIntent.getService(this, 0, iDismiss, Intent.FILL_IN_DATA);
mNotifyBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_action_about)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(piCancel)
.setDeleteIntent(piDismiss);
The problem is all pending intents seem that have the same intent extra data, so when onStartCommand is launched no matter whether the notification was clicked or dismissed or neither, constant INTENT_CANCEL is received from intent.getIntExtra(INTENT_ACTION)
I believe it has something to do with the flags used in PendingIntent.getService(), i'm confused about which to use. I've tried using PendingIntent.FLAG_CANCEL_CURRENT, and UPDATE_CURRENT, neither seem to fix the issue but the result is different, I receive constant INTENT_ALARM_FIRED for every action.
How can I get each pending intent to have its own intent extra data?
Solution
I discovered an exact warning about this scenario right in the PendingIntent doc. http://developer.android.com/reference/android/app/PendingIntent.html
just changed my request codes and it works

This has to do with Intents being considered the same. See PendingIntent for more information.
One way to get around this would be to just vary the requestCode for each Intent. (The 2nd parameter in the getService call)

Related

Pending Intent for more than one notification

I have app which sends notifications, I used this code for pending intent
Intent myIntent = new Intent(getApplicationContext(),MainActivity.class);
myIntent.putExtra("link",Link);
PendingIntent intent2 =
PendingIntent.getActivity(getApplicationContext(),1,myIntent,
PendingIntent.FLAG_ONE_SHOT);
and it worked nice for the first time, but I use this piece of code inside a method that invokes every 1 minute.
The problem is that the link variable changes from one to another.
and when I get the data in the MainActivity I found the last link only, all the notifications created has the last link.
and I don't know how to avoid this.
You are sending the same request code for your pending intents. These codes are defined as the 2nd parameter of your Pending intent declaration
Change
PendingIntent intent2 =
PendingIntent.getActivity(getApplicationContext(),1,myIntent,
PendingIntent.FLAG_ONE_SHOT);
To:
PendingIntent intent2 =
PendingIntent.getActivity(getApplicationContext(),UNIQUE_INT_VALUE_FOR_EVERY_CALL,myIntent,
PendingIntent.FLAG_ONE_SHOT);
If you use the same id, the intent will be reused and you will only get the last data rather than getting new data for every call.
Try This,
PendingIntent contentIntent = PendingIntent.getActivity(GCMNotificationIntentService.this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
In Kotlin
Make a notification
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
For one and more just change the request Code number:
val pendingIntent = PendingIntent.getActivity(context,
System.currentTimeMillis().toInt(),intent, 0)
then
builder.setContentIntent(pendingIntent)

Notification PendingIntent Intent extras are overridden by another notification

When creating a new notification with a new PendingIntent, the extras in its intent override any previous notification's PendingIntent Intent extras.
For example, lets say I create Notification1 with PendingIntent1, which has Intent1 and its extras.
When I create Notification2 with PendingIntent2, which has Intent2 with its own different extras, Intent1 will now have the same extras as Intent2. Why is this happening? How do I work around this?
There are two ways to solve this:
One is to set a different action on the Intent. So in your example, you could set Intent1.setAction("Intent1") and Intent2.setAction("Intent2"). Since the action is different, Android will not override the extras on the intent.
However, there may be a case where you actually need to set a specific action on this intent (i.e. your action corresponds to a specific broadcast receiver). In this case, the best thing to do is set the request code to something different in each PendingIntent:
PendingIntent pendingIntent1 = PendingIntent.getActivity(context,
(int) System.currentTimeMillis() /* requestCode */, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent2 = PendingIntent.getActivity(context,
(int) System.currentTimeMillis() /* requestCode */, intent2,
PendingIntent.FLAG_UPDATE_CURRENT);
By setting a new request code on the PendingIntent, Android will not override the extras on each of their corresponding intents.
In my case it worked with by using unique notification id each time like below:
mNotificationManager.notify((int) System.currentTimeMillis(), mBuilder.build());
Generate the unique id each by using (int) System.currentTimeMillis() and give this to NotificationManager object.

PendingIntent and Notification Intent

I find the code below redundant. Am I missing something basic here ? Is there a way to reduce the duplicate code here. Can I use either Intent or PendingIntent object, why both ?
Intent updateUI = new Intent(SENDTOBACKGROUND_SERVICE);
updateUI.putExtra("Signal", God.YELLOW);
sendBroadcast(updateUI);
Intent sendNotification = new Intent(DriverService.this, DriverHome.class);
sendNotification.putExtra("Signal", God.YELLOW);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, sendNotification, PendingIntent.FLAG_UPDATE_CURRENT);
Notification n = new NotificationCompat.Builder(DriverService.this)
.setContentTitle("Attempting to update location")
.setContentText("Cab #(last) " + currentLocationInText)
.setSmallIcon(R.drawable.yellow).setContentIntent(pIntent).setAutoCancel(true)
.build();
((NotificationManager) DriverService.this.getSystemService(NOTIFICATION_SERVICE)).notify("Taxeeta", R.id.cabLocation, n);
No, you need both. A PendingIntent is a wrapper around an Intent. You can't have a PendingIntent without an Intent to wrap. And you can't put an Intent in a Notification. You need to use a PendingIntent when you want to hand over an Intent to another component, so that the other component can send the Intent for you (as a kind of "proxy") at some point in the future.
As explain in the doc
http://developer.android.com/reference/android/app/PendingIntent.html#getActivity%28android.content.Context,%20int,%20android.content.Intent,%20int%29
"Retrieve a PendingIntent that will start a new activity, like calling Context.startActivity(Intent)" so you need PendingIntent and Intent.

Android: Start Service with Context.startService vs PendingIntent.getService

Context.startService
Intent intent = new Intent(context, MyService.class);
context.startService(intent);
PendingIntent.getService
Intent intent = new Intent(context, MyService.class);
PendingIntent pi = PendingIntent.getService(context, 0, intent, 0);
pi.send();
Questions
When would you start a service with Context.startService vs a PendingIntent?
Why would you use one over the other?
There really is no difference.
Specifically the Context method is used to directly start it where as a PendingIntent is typically used with a notification to fire this intent when it is tapped, which is delayed until the user taps it (typically). However; you wouldn't typically send the PendingIntent directly because that is not what it is for.
A PendingIntent is an Intent that is pending, pending, meaning that its NOT supposed to happen now, but in the near future. Whereas with an Intent, it is sent at the very moment.
If a PendingIntent is not pending when it is used, then it is no longer a PendingIntent and it is infact an Intent. Defeating the purpose entirely.
PendinIntents are very much used for widgets. As the layout of a running widget doesn't "belong" to your code, but it is instead under control of the system, you can't assign directly click listeners to the interface elements. Instead you assign a PendingIntent to those elements (like buttons) so when the user touches them, the PendingIntent is "executed", something like:
// get the widget layout
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.id.widget_layout);
// prepare to listen the clicks on the refresh button
Intent active = new Intent(context, WidgetCode.UpdateService.class);
PendingIntent refreshPendingIntent = PendingIntent.getService(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.buttonWidgetRefresh, refreshPendingIntent);
// send the changes to the widget
AppWidgetManager.getInstance(context).updateAppWidget(appwidgetid, remoteViews);
In this case a button in the widget starts a service. Usually you put extra info in the intent, with putExtras(), so the service will get any needed information to do its job.

Intent extras not removed/replaced

I am setting an alarm on a button click.
The alarm is triggered with an intent.
This intent get an extra "int" to pass to the Broadcast Receiver.
The problem is that the intent's extra gets set once on the first
click of the button and never changes on the other clicks:
Intent intent = new Intent(A.this, B.class);
intent.putExtra(WAKEUP_DURATION, wakeUpDuration);
PendingIntent sender = PendingIntent.getBroadcast(A.this, 0, intent, 0);
I tried removing it in the Broadcast Receiver, but no luck:
intent.removeExtra(A.WAKEUP_DURATION);
Use FLAG_UPDATE_CURRENT when creating your PendingIntent to update the extras from a new Intent.
Thanks! That did the trick.
For those of you who would like to know the exact answer.
The "FLAG_UPDATE_CURRENT" goes as the fourth argument in the method 'getBroadcast'.
It should look like this:
PendingIntent sender = PendingIntent.getBroadcast(A.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

Categories

Resources