My application hosts user installed widgets, same as a launcher application.
Once I bind the widget, everything works fine. Widgets are created, updated automatically, I can click to navigate inner views.
Everything keeps working fine, until I update my application from Play store (or manually with a signed APK).
After the update, the widgets still show but they won't update anymore. Some widgets function when I click on them but the view is stuck and never gets updated until I re-create the widget (get a new ID and bind it).
I tried forcing an update using
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.setComponent(appWidgetInfo.provider);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]
{appWidgetId});
context.sendBroadcast(intent);
but that doesn't help...
I wanted to try a forced update on click but I couldn't find any way to get the widget's RemoteViews (as this is not my widget, I just host it).
RemoteViews views =
new RemoteViews(context.getPackageName(),R.layout.mywidget_layout);
Intent updateIntent = new Intent();
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
updateIntent.putExtra(myWidgetProvider.WIDGET_IDS_KEY, ids);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.view_container, pendingIntent);
Also implemented an AppWidgetProvider to listen to widgets' ID changes (APPWIDGET_HOST_RESTORED) but it doesn't get called on my application update.
My next step would be to re-create all widgets after application update, but I really prefer not to do so.
Would appreciate any help!
Solved.
The last thing I wanted to do, was probably the first thing I should have tried.
I moved on to re-creating the widgets and I found that I don't have to fully re-create them, just re-call bindAppWidgetIdIfAllowed() with the same Widget ID I already have.
The method will return true if everything is still OK and if not, the widget may not be installed anymore or you need to trigger its configuration screen.
Certain Android functionality will break if the widget is installed on the SD Card. Try moving it to the device storage and re-test.
make sure you use unique keys with putExtra(MyWidgetProvider.WIDGET_ID_KEY, ids);
Do not use putExtra(AppWidgetManager.EXTRA_WIDGET_IDS, ids);
Related
My widget application only works if I install the widget add it to the screen and then install it again, if i add another widget i have to install again in order for the second one to start working (rebooting the device also helps, after the reboot all the widgets on the screen work,
I have config file, and it does not reach my appWidgetProvider (the action is set on the onUpdate method), how can i force my APP to update the widget from the configuration file?
my entire project:
https://github.com/vlad1001/Widget
Thanks!
The only difference is see on your code is that your are finishing the activity before updating the widget.
From documentation, the onUpdate method will not be called the first time.
I think that your have to add the following:
super.onCreate(icicle);
setResult(RESULT_CANCELED);
Remove this line:
setResult(RESULT_CANCELED, resultValue);
After that, change the call to update before setResult and finish():
//make the update before finish()
appWidgetManager.updateAppWidget(appWidgetId, views);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, resultValue);
finish();
I have not reproduce your issue, please let me know if this work for you.
After you share the source code, the base issue, is that on the first creation you are adding click intent to Text and on the update you add the pending intent to your imageView...
changing this line resolve your issue. Test on the PR...
views.setOnClickPendingIntent(R.id.example_widget_imageview, clickPendingIntent);
My first shot. Take a look at file AndroidManifest.xml in Your project.
There is a line which might cause problem You have described.
android:allowBackup="true"
Whether to allow the application to participate in the backup and restore infrastructure. If this attribute is set to false, no backup or restore of the application will ever be performed, even by a full-system backup that would otherwise cause all application data to be saved via adb. The default value of this attribute is true.
In short: uninstalling app doesn't mean You have uninstalled app's content and settings.
Try set it to false.
Related problem: https://stackoverflow.com/a/35296675/619673
Alternative: after first installation, clear cache of app, then run (or call in terminal adb shell pm clear <your.package.name).
I'm trying to figure out how to send an intent to the home screen to add a Widget to it if I can. Any ideas? Here is some code I've been fooling around with to at least prompt the Add Widget selection.
AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
selectWidget();
mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetHost = new AppWidgetHost(this, R.id.APPWIDGET_HOST_ID);
}
void selectWidget() {
int appWidgetId = this.mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(pickIntent, R.id.REQUEST_PICK_APPWIDGET);
}
Thank you to anybody who contributes.
You can send the ACTION_APPWIDGET_PICK intent to the system, but your app cannot process it, unless what you're coding is a Home screen replacement, i.e. a launcher.
Take a look at the documentation for App Widget Host, in particular the section about Host Binding. The code you're using in the selectWidget() method is the same used in the original Launcher app (under title Binding app widgets on Android 4.0 and lower). Then comes an implementation for onActivityResult, where the intent is processed. This method is what is missing in your code, but if you include it, you will end up doing all the work the Home screen app does (see addAppWidget(Intent data) next in that page).
If you continue reading the App Widget Host doc, you will see that the binding process changed on Android 4.1 and there is also a new intent for this task that requires a permission in the manifest. And to complicate things more, keep in mind #CommonsWare's comment: there are a lot of Home screen implementations, that probably do the binding process differently :(
To summarize: there's no way to get the list of app widgets and process what the user selected, neither is a way to ask the launcher app to do this for us, unfortunately. Perhaps in a future Android version, as this comment in the latest Launcher source code reveals:
/**
We will likely flesh this out later, to handle allow external apps to place widgets, but for now,
we just want to expose the action around for checking elsewhere. */
Well this is driving me crazy. I have developed an App-widget. Everything is working fine.
I have a configuration activity which launches every time a widget is added on the home screen and works beautiful. I save the user settings per widget id etc.
The widget has some buttons, one of them launches an activity with about information, the "About Activity".
The "About Activity" has a button which I want to use to launch the configuration activity for the widget id that launched the "About Activity". The reason I want to do that is because I want the user to be able to configure the contents of any instance of my widget without having it removed and added again (in order to launch the configuration activity).
The configuration activity needs the AppWidgetManager.EXTRA_APPWIDGET_ID in order to make the job (save the user settings for this specific widgetid) so I must somehow pass this extra when I 'm calling it from another activity. The obvious think to do is this:
startActivity(new Intent(context,act_configure.class).putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, ??? ));
Now my question is where is the widgetid? I found a million ways to get the widgetids (the array) but not a single clue on how to get the specific widgetid which launched the "About Activity"
Any help about this will make the hours I spent to find a solution, worth something. Thank you in advance.
p.s. Please forgive my English as they are not my native language...
Thanks to Cory Chaltron here is the solution to my problem.
In the widget provider onUpdate method I should create a "unique" intent to pass to the pending intent which handles the launch of the about activity. Because of the way Android compares Intents, passing the WidgetID in the extras IS NOT ENOUGH, you should also pass it as data to the intent in order to be unique. So here is the code:
Intent aboutIntent = new Intent(cx, act_about.class);
aboutIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetIds[i]);
// Make this unique for this appWidgetId
aboutIntent.setData(Uri.withAppendedPath(Uri.parse("customuri://widget/id/"), String.valueOf(widgetID)));
PendingIntent aboutPendingIntent = PendingIntent.getActivity(cx, 0, aboutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.cmdabout, aboutPendingIntent)
Although I answer my own question I am not accepting it because it is based on Cory's answer. Thank you all for the help...
How are you setting your widget views? I have an app where I iterate over the active widgets and configure set the RemoteView there. You could set your widget id in the onClick you are attaching to the "About" button.
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
final ComponentName widgetName = new ComponentName(this, WidgetProvider.class);
final int[] widgetIds = widgetManager.getAppWidgetIds(widgetName);
for (int widgetId : widgetIds) {
final RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.widget);
// This is the important part :-D
remoteViews.findViewById(R.id.your_about_button).setOnClickListener(... a listener to start your about activity that puts the widget id in the extra like you suggest in your question ...);
widgetManager.updateAppWidget(widgetId, remoteViews);
}
I'm having the hardest time figuring out how to remove home screen AppWidget's programmatically (i.e. without the user actually dragging one into the trash). As an example, consider an app that can have multiple accounts, with any number of widgets for each account - once an account is removed, widget should be deleted as well.
I've tried following an obscure example from http://www.netmite.com/android/mydroid/cupcake/frameworks/base/services/java/com/android/server/AppWidgetService.java, but that doesn't seem to even trigger OnDeleted, much less remove the AppWidget from the home screen.
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
intent.setComponent(info.componentName); // references AppWidgetProvider's class
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
sendBroadcast(intent);
Does anyone have any advice on how this can be accomplished? An example would be the bee's knees. Thanks.
You cannot add or remove app widgets from the home screen. Only the user can do that.
Any app widgets tied to a deleted account could show a different account, or adopt some "(account deleted)" look that would trigger the user to get rid of the app widget or reconfigure it.
I'm pretty sure this should work:
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName("com.example",
"com.example.Widget"));
AppWidgetHost host = new AppWidgetHost(ctx, 0);
host.deleteAppWidgetId(appWidgetIds[0]);
Posted: Mon Nov 30, 2009 5:08 pm Post subject: Simple Problem With Intent Extras
Hello,
I'm working on an app widget for the home screen. I'm trying to make it so when a user taps on the widget it changes the data being displayed in the widget. However, I'm also allowing multiple instances of widgets open with different data. So in order to tell my method which widget to update, I'm adding an extra to the intent that is launched to change the data.
Here's the intent I have:
Java:
Intent changeData = new Intent("com.tonycosentini.mintdroid.CHANGE_DATA");
changeData.putExtra("widget_id", currentWidgetId);
PendingIntent changeDataPendingIntent = PendingIntent.getBroadcast(this, 0, changeData, 0);
//This will return the correct value, but if I call it in my onreceive() method it won't.
Log.v(TAG, "stored id is: " + changeData.getIntExtra("widget", 0);
This correctly stores the widget id, but when the change data method is called, the widget id that is read from the intent is the first widget instance. That is, there is is a for loop that generates all of the widgets and no matter what widget you tap, the widget id that is recieved is always the first widget id in the first widget.
Anyone have an idea on how to solve this? Hopefully I didn't word it too poorly.
Thanks for reading,
Tony
This is a known issue with PendingIntents; when Android compares PendingIntents it does not compare Intent extras, so you can't schedule the same basic Intent multiple times with only different extras. Right now, you can only solve this by making the Intent unique in some way other than extras, such as adding extra information to the Intent data.
There's a little bit of discussion of this on the Google Android Group: http://groups.google.com/group/android-developers/browse_thread/thread/81100da6ddb21136