How to broadcast intent to multiple WidgetProviders - android

I have 2 widgets, each having it's own WidgetProvider. This is the class hierarchy:
AppWidgetProvider
|
CommonWidgetProvider
| |
WidgetAProvider WidgetBProvider
Both widgets have a button which updates the widget, but I would like to update all widgets (both WidgetA and WidgetB) no matter on which one you click.
I broadcast the update intent like this (in WidgetA):
don't worry about EXTRA_APPWIDGET_IDS containing only current widgets' id - I later retrieve all widgets' IDs in the Provider
// setup click on update icon
Intent intent = new Intent(data.context, WidgetAProvider.class); // how can I broadcast to both A AND B? Now it will broadcast only to A.
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {data.widgetId});
PendingIntent pendingIntent = PendingIntent.getBroadcast(data.context,
data.widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetUpdateContainer, pendingIntent);
How can I broadcast this update to both WidgetProviders?

Don't use the PendingIntent to directly send a broadcast because this way you always have to target explicitly one of the AppWidgetProviders.
Instead, use the PendingIntent to start an IntentService to send a broadcast to every BroadcastReceiver which uses a certain IntentFilter. You can inhibit third party BroadcastReceivers from receiving your broadcast by using signature permissions (see for example this post)

Related

Android 12 - About Correspondence to notification trampoline

We are working on notification trampolines on Android 12.
Originally our app launches an activity by a broadcast receiver.
I found out that using PendingIntent.getActivity instead of PendingIntent.getBroadcast would solve the problem.
Regarding this, I have a following concern.
When the broadcast receiver is used, i.e. when PendingIntent.getBroadcast is used, I programmed so that the broadcast receiver determines whether to launch the app.
However, I no longer use the broadcast receiver due to notification trampolines. Therefore, PendingIntent.getActivity launches the app without choice.
I would like to know if there is any way to determine whether to launch the app depending of the state of app without using the broadcast receiver.
For example;
when App is in state A:Launch the app with a push notification tap
when App is in state B:NOT launch the app with a push notification tap
sort of workaround would be to launch some dedicated Activity, which may be set as fully transparent without any enter/exit animation, noHistory flag etc. and in there you may run your checking logic - starting "real" Activity or just finish() if there is no need
I'm using a transparent activity to handle this issue. all the notification related works are handled in the transparent activity.
Intent intent = new Intent(mContext, NotificationActivity.class);
intent.putExtra("notification", parseInt(this.mActionDetail.getNotifyId()));
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
notificationManager.notify(parseInt(this.mActionDetail.getNotifyId()), builder.build());
create a transparent activity NotificationActivity.class then you can identify the application state then you can decide the action

How to check for Proximity Alerts and find them

I have a question regarding proximity alerts.
In all tutorials I ve read they are created and destroyed while the activity that create them is still running.
But what happens if say an activity creates n proximity alerts and then the activity itself is destroyed (the PA are not)
Then if I want to build another activity that finds these Proximity Alerts, how can I do that? Is that even possible?
You have to maintain your own list of proximity alerts. There is no way to get them back. However, #Mercato is correct when he says that you can remove a PA using only pending intents, but you don't have to store them. According to the docs:
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.
This means that the system will store your PendingIntent for you between app restarts, and you can retrieve it by passing the same Intent you used to create it. So for example, if you created the following PendingIntent:
Intent intent = new Intent(context, Foo.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then all you have to store is the requestId (1) and the Class or class name (Foo.class or Foo.class.getName()). Then if you want to retrieve that same PendingIntent without creating a new one, you can do the following:
Class<Foo> className = retrieveClass(); //You implement this
//String clazz = retrieveClassName(); //This is another option
int requestId = retrieveId(); //You implement this
Intent intent = new Intent(context, className);
//The flag given attempts to retrieve the PendingIntent if it exists, returns null if it doesn't.
PendingIntent pi = PendingIntent.getBroadcast(context, requestId, intent, PendingIntent.FLAG_NO_CREATE);
if (pi != null) {
//This pending intent was registered once before.
//Go ahead and call the function to remove the PA. Also, go ahead and call pi.cancel() on this.
}
else {
//This pending intent was not registered, and therefore can't have a PA registered to it.
}
Technically, all proximity alerts need a PendingIntent defined and used as a parameter. Android's Documentation shows that if you know the list of PendingIntents then you can remove them as well.
removeProximityAlert(PendingIntent intent) Removes the proximity alert
with the given PendingIntent.
Since PendingIntent is Parecelable see here then you could add it as an Extra to any Intent. This means, that on starting another Activity, you can create an Parcelable[] array to hold all these PendingIntent, then
putExtra(String name, Parcelable[] value)
Add extended data to the intent.
then retrieve them in the next Activity via getIntent() and it's relevant methods.

Unable to retrieve new intent extras

I'd like to ask you for help as after trying to figure this issue out for a couple of hours still can't get it works.
I have a notification manager which process incoming GCM messages and creates notifications, however an intent, that is passed to pending intent, always got old extras (intent recycle) within activity.
intent.putExtra("user_id", id);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
Lets say that I will receive two notifications from two different users and intent starts the same activity which displays that user ID. After click on first notification, activity is launched as usually and intent's extras contains user ID of first user. However, if I will remain within this activity, and click on another push notification, an activity is recreated (onDestroy is called) but, intent's extras contains user id of first user, not the second one.
Here is my question. How can I retrieve new intent extras? I've already tried to implement onNewIntent callback method, but it never get called, also tried to change flags but unsuccessfully and what's kinda weird to me is, that even after onDestroy callback is called, intent extras in next instance of that activity have old data...
Thanks in advance
You need to pass unique Id in place of just 0 when fetching Activity from PendingIntent:
int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);
builder.setContentIntent(PendingIntent.getActivity(context, iUniqueId, intent, PendingIntent.FLAG_UPDATE_CURRENT));
I think you fire your notifications either with the same id or with a inappropriate intent flag. As it is mentioned here, when creating the pending intent you can set its flag. If you don't like the previous pending intent to be updated or overridden, you should set its flag to FLAG_ONE_SHOT. It indicates that although you have more than one pending intents sticking around in the system, each can be executed only once!
Conclusion: Your code should be sth like this:
PendingIntent pIntent = PendingIntent.getActivity(context, id,intent,PendingIntent.FLAG_ONE_SHOT);
In this code the "id" is unique per pending intent and "intent" is the actual intent for the target activity.
Cheers

Can you use pending intents with localbroadcasts?

I am interested in using pending intents with local broadcasts.
To make myself clear, I am using the following for registering receivers and sending broadcast: android.support.v4.content.LocalBroadcastManager.
I have a local broadcast receiver in a service which works. I am trying to send local broadcasts from a custom notification layout which includes click-able items.
The local broadcast receiver - just receives simple action intents.
I was trying something like this to no avail:
Intent backintent = new Intent("GOTO_START_BROADCAST");
PendingIntent backIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, backintent, 0);
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification);
contentView.setOnClickPendingIntent(R.id.imageView1, backIntent);
I am interested in using pending intents with local broadcasts.
That is not possible.
The point behind a PendingIntent is to allow some other process to perform an action you request, such as sending a broadcast.
The point behind LocalBroadcastManager is to keep broadcast within your process.
Hence, a PendingIntent can issue a regular broadcast, but not one via LocalBroadcastManager.

multiple proximity alert based on a service

I have my application, which uses ProximityAlerts to fire up when the user enters on the designated radios.
My proximityAlert fires up a service which shows a Toast telling me that I've entered the designated radio of the events.
The problem comes that I cannot make my application to fire several registered locations, it only react to the last one that was registered and ignore the earlier registered events
Any help please? I have seen people using broadcast receiver but in my case I use a service instead.
To build an Android app with proximity alert, the main ingredient are Broadcast Receiver, Intent, PendingIntent, and AddProximityAlert.
The workflow should be as following: -
Register an IntentFilter with a Broadcast Receiver
Create an Intent
Get a PendingIntent that will perform a broadcast
Set proximity alert
In order to make your app fire several registered locations, your must first register the broadcast receiver with correct IntentFilter and create the respective Intent for each Proximity Alert. Remember to use unique intent action for each location as follows
.....
IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT + uniqueID);
.....
Intent mIntent = new Intent(PROX_ALERT_INTENT + uniqueID);
......
For more information, you can read my post on the topic
There are a couple points to be made here:
Use a broadcast receiver to handle the PendingIntent that fires for a proximityAlert.
When creating the PendingIntent for a proximityAlert, the PendingIntent must be unique for each location. The easiest way to do this is to create a unique action string for each location.
Here's an example of a PendingIntent you can create for a proximityAlert:
int uniqueID = <unique_id_for_location>;
String intentAction = "PROXIMITY_ALERT." + uniqueID;
PendingIntent proximityIntent = PendingIntent.getBroadcast(getApplicationContext(),
uniqueID, new Intent(intentAction), PendingIntent.FLAG_CANCEL_CURRENT);
Then, add the proximityAlert for your location (I'm assuming you know how to do this part).
Next, register your broadcast receiver to handle the intent action string you created for your pendingIntent:
IntentFilter filter = new IntentFilter(intentAction);
registerReceiver( new ProximityItentReceiver(), filter );
Here, ProximityIntentReceiver is the name of the BroadcastReceiver class you have created.
It's all about the request_id in pendingIntent, you assign a requestid for pendingIntent..and if your first service uses the request id 1 means and second service uses the request id 2..so the first service not be killed and the service occurs concurrently ..
the count i used as request id in pending intent
int COUNT=Integer.parseInt(some_text.getText().toString());
if(COUNT==1)
{
PendingIntent proxi_pi=PendingIntent.getService(class_name.this,COUNT,service_class_intent,Intent.FLAG_ACTIVITY_NEW_TASK);
location_manager.addProximityAlert(location.getLatitude(), location.getLongitude(), radius, -1, proxi_pi);
}
else if(COUNT==2)
{
PendingIntent proxi_pi=PendingIntent.getService(class_name.this,count,service_class_intent,Intent.FLAG_ACTIVITY_NEW_TASK);
location_manager.addProximityAlert(location.getLatitude(), location.getLongitude(), radius, -1, proxi_pi);
}
else if(COUNT==so..on){
}
i hope this helps you..
Have you considered using a broadcast receiver then launching a service from the receiver?
When I first used them I found the system cached the results somewhat so had to set an ID (Which the docs claim not to be used). By doing this the intents weren't cached and I got the appropriate information to handle multiple proximity alerts.
Source code is available through github (See the bottom of this post) Gaunt Face - Multiple Proximity Alerts

Categories

Resources