i have one widget in which there are two buttons and one service class in which i have two methods on clikcing of button i want to call the methods in service class.
any reference or code example?
how can i do it?
thankx
I'm guessing that your question pertains to appWidgets. If not, the answer below will probably be less useful, although you can still adapt part of it to your own use, I think.
First declare some action(s), like this:
public static final String ACTION_HIDE_GUIDE_OVERLAY = "dk.something.appwidget.calendar.guide.hide";
Use the action(s) to declare an Intent and a PendingIntent:
Intent intent = new Intent(context, CalendarService.class);
intent.setAction(CalendarService.ACTION_HIDE_GUIDE_OVERLAY);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent buttonPendingIntent1 = PendingIntent.getService(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then register the pendingIntent with the RemoteView for your widget:
views.setOnClickPendingIntent(R.id.calendar_button_1, buttonPendingIntent1);
Finally, in the onStartCommand or onHandleIntent of your service, examine the action of the intent to determine which of your methods to call:
if (intent.getAction().equals(CalendarService.ACTION_INITIALIZE_CALENDAR)) {
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
onInitializeCalendar(appWidgetIds);
} else if (intent.getAction().equals(CalendarService.ACTION_HIDE_GUIDE_OVERLAY)) {
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
onHideGuideOverlay(appWidgetId);
} else ...
Note: The code snippets are taken almost directly from my Glass Widgets, so to adapt it to your own use, you would have to replace the action constant with your own two actions (one action for each button), replace R.id.calendar_button_1 with the actual id of one of your buttons, replace the CalendarService with the name of your own service class and the methods onInitializeCalendar and onHideGuideOverlay with the name of the two methods in your service class that you want to call.
If you only ever have one instance of your widget visible at one time, then you don't need to fiddle around with the appWidgetId, but you probably can't guarantee that. I have some settings that can vary from widget instance to widget instance, so I put the id of the appwidget that was clicked into the intent, where the service can get at it when servicing my request.
Related
My WidgetConfigActivity creates an onClickListener PendingIntent to pass through RemoteViews to perform two tasks: (1) open SliderActivity and (2) pass the appropriate appWidgetId.
val views =RemoteViews(context.packageName, R.layout.widget)
views.setOnClickPendingIntent(
R.id.tv_widget_access_slider,
getSliderPendingIntent(this, appWidgetId)
)
fun getSliderPendingIntent(context: Context, appWidgetId: Int): PendingIntent {
val intent =Intent(context, SliderActivity::class.java)
intent.putExtra("appWidgetId", appWidgetId)
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) //tried this but didn't help
Log.d("APP WIDGET PENDING INTENT", "$appWidgetId")
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_IMMUTABLE
)
}
I need to get the appWidgetId in my SliderActivity so that the correct data can be displayed. So, I get the intent in onCreate.
val appWidgetId =intent.extras?.getInt("appWidgetId", 0) ?: 1
Log.d("APP WIDGET ID RECEIVED", "$appWidgetId")
intent.removeExtra(AppWidgetManager.EXTRA_APPWIDGET_ID) //tried this but didn't help
It works except for one thing. By logging, I've learned that the same appWidgetId is always received in SliderActivity onCreate even though unique appWidgetIds are added to the PendingIntent
First widget added to home screen Pending intent id =187, Slider onCreate id =187
Second widget added to home screen Pending intent id =188, Slider onCreate id =187
Third widget added to home screen Pending intent id =189, Slider onCreate id =187
How can I get the correct appWidgetId to my widget onClickListner to my SliderActivity?
Each distinct app widget needs a distinct PendingIntent, where "distinct" is largely determined by the ID that you pass as the second parameter to the PendingIntent.getActivity() method. If you use the same ID for multiple app widgets, they all wind up using the same PendingIntent, despite code that otherwise looks like it is creating three PendingIntent objects.
If you need to change the contents of the Intent for a PendingIntent, use FLAG_UPDATE_CURRENT as part of your flags in the PendingIntent.getActivity() call. Otherwise, an existing PendingIntent for that ID will be left alone.
IOW, think of PendingIntent.getActivity() as being a lazy-create mechanism — you need to take steps to force it to give you distinct objects and to update what is in them.
I'm new in this whole Android environment and I usually have some doubts that maybe you can consider very basic knowledge and a bit stupid. I will try to do my best explaining the doubt I have and why i have it to make me understand.
I'm doing an application where you can set notifications to remind you the scholar classes you want. I have done a class that extends BroadcastReceiver so it can reset all the alarms after the device has booted. I have a database where I keep information about the alarms: the class, the time it has to be configured, etc. I retrieve all the alarms and set them to the alarmManager this way:
intent = new Intent(ctxt.getApplicationContext(), Notificacion.class);
intent.putExtra("TAG", tag);
intent.putExtra("SUBJECT", cursor2.getString(0));
intent.putExtra("AULA", cursor2.getString(1));
displayIntent = PendingIntent.getBroadcast(ctxt, Integer.parseInt(tag), intent, PendingIntent.FLAG_UPDATE_CURRENT );
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY*7, displayIntent);
Well, I guess this should work fine until here. The problem is that when you use the app and you want to set a notification, you are doing it from the class "Schedule.class" so the intent would have this context:
Intent intent = new Intent(getApplicationContext(), Notification.class);
PendingIntent pend = PendingIntent.getBroadcast(this, Integer.parseInt(tag), intent, PendingIntent.FLAG_UPDATE_CURRENT);
In the app, you can delete an alarm, and you have to call alarmManager.cancel(pend) in order to do that. So my doubt is if it will be able to cancel it.
If the contexts are different, it won't find the match with the pending intent, because it was set from the context I got in my extension of BroadCastReceiver (ctxt), and the alarm was set with the context I got from Schedule.class.
So.. is the application context always the same? I know that the context is set in order to give information to other classes about what has been going on, but I'm not sure if the Intent filter will differentiate where the context was given.
Thank you in advance!
Looking at the AlarmManager documentation for the cancel method you're using:
public void cancel (PendingIntent operation)
Added in API level 1
Remove any alarms with a matching Intent. Any
alarm, of any type, whose Intent matches this one (as defined by
filterEquals(Intent)), will be canceled.
So, the Intent.filterEquals documentation says the following:
public boolean filterEquals (Intent other)
Added in API level 1
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 can't think of any reason why the action, data, type, class, or category would be different from one explicit Intent to another (unless, obviously you went out of your way to change those things). The contexts do not appear to be in the criteria for the matching, so I think you can be fairly confident that it will be cancelled no matter which context was used to create it in the first place.
I'm working on an Android application which includes a widget. The main interface of the app is a simple activity, but some of the things users can do in the activity make it necessary to update the widget - i.e. run its onUpdate method.
How can I trigger this method from the activity? Looking at other questions, I've been able to write code which changes its layout, but it doesn't seem to run onUpdate (since I'm just left with the empty layout and none of the data which is added during onUpdate).
Any ideas or code samples very much appreciated!
I am still pretty new to Android, but I accomplished this with three steps:
First, I put the contents of my AppWidgetProvider.onUpdate in a method (myUpdate(Context)).
Second, I overrode AppWidgetProvider.onReceive() to look something like this:
public void onReceive(final Context context, final Intent intent)
{
super.onReceive(context, intent);
if (MY_PUBLIC_STATIC_STRING.equals(intent.getAction()))
{
myUpdate(context);
}
}
Third, from my other activity, I just send a generic broadcast with the action set on the intent.
Intent updateWidgetIntent = new Intent(context, MyWidget.class);
updateWidgetIntent.setAction(MyWidget.MY_PUBLIC_STATIC_STRING);
context.sendBroadcast(updateWidgetIntent);
This does have the down side of having to find the AppWidgetManager yourself from the context and the app widget ids, instead of the nice interface onUpdate gives you. So I am skeptical that this is the right approach. Best of luck.
myUpdate(Context) starts like this:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds =
appWidgetManager.getAppWidgetIds(new ComponentName(context, this.getClass()));
I have a WidgetProvider and an Configure Activity
When the Widget is started it starts with the configure activity and I set it up by making a custom call to the widgetprovider
(which you will notice is from the sdk tutorial examples)
// Push widget update to surface with newly set prefix
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
AwarenessWidget.updateAppWidget(context, appWidgetManager,
mAppWidgetId, position);
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
I pass the Widget ID to the function.... inside the widget I create a Intent like this:
Intent configIntent = new Intent(context, Configure.class);
configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getActivity
(context, 0, configIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.MainImage,pendingIntent);
views.setImageViewResource(R.id.MainImage, lv_images[version]);
appWidgetManager.updateAppWidget(appWidgetId, views);
I am always referencing the widget ID and even add it as a extra on the intent
but when I get two of these widgets on the home screen the widget ID is always referencing the last placed widget ID
I had a similar problem. Just add this to your config activity, where you set your PendingIntent:
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME + "://widget/id/")
,String.valueOf(appWidgetId));
intent.setData(data);
The variable URI_SCHEME is a String, and can be whatever you'd like.. ie - "ABCD" This causes each widget to have a unique PendingIntent.
Here is a more in-depth explanation of why your code doesn't work and how to fix it. From the Android SDK Documentation:
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.
Because of this behavior, it is important to know when two Intents are
considered to be the same for purposes of retrieving a PendingIntent.
A common mistake people make is to create multiple PendingIntent
objects with Intents that only vary in their "extra" contents,
expecting to get a different PendingIntent each time. This does not
happen. The parts of the Intent that are used for matching are the
same ones defined by Intent.filterEquals. If you use two Intent
objects that are equivalent as per Intent.filterEquals, then you will
get the same PendingIntent for both of them.
Note that specifying differing "extra" contents isn't enough for the PendingIntents to be considered unique, but setting a unique URI with setData is. That is why Snailer's URI solution "magically" fixes the problem.
The documentation also offers a different (arguably simpler) solution to the problem. Instead of creating a custom URI just set a unique requestCode when you call getActivity:
PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Source: http://developer.android.com/reference/android/app/PendingIntent.html
In my testing, using the setData(...) on the PendingIntent doesn't fix the issue on a Verizon Thunderbolt running Android 4.0.4. It works on my other test devices and emulator.
I tested the use of the requestCode instead, and it works in all cases. I just set the requestCode to be the widget ID:
pendingIntent = PendingIntent.getService(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
I have an application, which sets an alarm using AlarmManager, which starts another Activity when it goes off. The AlarmManager takes a PendingIntent and spawns a BroadcastReceiver class when the specified time comes. I'm wondering whether there is any way that I can pass arguments to this BroadcastReceiver through the Intent object which goes into PendingIntent?
Basically what I'd like to do is something like this:
Intent my_intent = new Intent(this, BroadcastService.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, my_intent, 0);
my_intent.putExtra("arg1", arg1);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000), pendingIntent);
and I'd like to be able to retrieve arg1 in the BroadcastReceiver's onReceive(Context, Intent) method. I figured that the local variable my_intent would be the second parameter passed on to onReceive by the PendingIntent, but apparently that's not quite right. Is it possible to pass parameters between an Activity and a BroadcastReceiver in this fashion (using Intent.putExtra()) or should I use a ContentProvider instead?
Thanks!
Iva
I had a similar problem, but I was already populating the Intent first before wrapping it in a PendingIntent. But the answer to my problem was, as pointed out above, that I needed to use the PendingIntent.FLAG_UPDATE_CURRENT flag. Once I set the flag, it worked! I hope this helps others.
-Jeff
int code=1;
Intent i2 = new Intent(StartAlarm);
i2.putExtra("_id",code);
class test extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
int i=arg1.getIntExtra("_id",-1);
}
}
I have an application, which sets an
alarm using AlarmManager, which starts
another Activity when it goes off.
That is bad form. Do not pop up activities unannounced like this without a very good reason (e.g., an incoming phone call). What if the user is in the middle of doing something, like TXTing or playing a game or trying to tap numbers for a phone menu?
Is it possible to pass parameters
between an Activity and a
BroadcastReceiver in this fashion
(using Intent.putExtra())
Yes. However, bear in mind that you will want to use PendingIntent.FLAG_UPDATE_CURRENT when you create your PendingIntent, to ensure that any new extras you supply on the Intent actually get used.
Yes, I think it is possible to pass any data of basic Java type and Serializable/Parceable types in the extras of an Intent wrapped around a PendingIntent and then retrieve them using the Intent instance passed to the onReceive of the Broadcastreceiver. Your approach looks okay to me.
What is the problem/error that you are getting? Is "arg1" instance Serializable?