-
-
Save rock3r/9809139 to your computer and use it in GitHub Desktop.
package net.frakbot.gists.widgethelper; | |
/* | |
* Copyright 2014 Sebastiano Poggi | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
*/ | |
import android.appwidget.AppWidgetManager; | |
import android.content.ComponentName; | |
import android.content.Context; | |
import android.content.Intent; | |
/** | |
* An helper class for handling homescreen widgets. | |
* | |
* <b>NOTE:</b> this class assumes that you have an {@link android.appwidget.AppWidgetProvider} | |
* named <code>WidgetProvider</code> (that handles widgets events). | |
* In <code>WidgetProvider</code>, you have to define: | |
* <code>public static final String EXTRA_WIDGET_IDS = "widget_ids";</code> | |
* | |
* It would also be good practice to have widget updates happening in an | |
* {@link android.app.IntentService} to avoid ANRs, as <code>AppWidgetProvider</code> | |
* is a <code>BroadcastReceiver<code> and can't block the main thread for long. | |
* You would then invoke this updater service from both the <code>WidgetProvider</code> | |
* and from the {@link #updateAllHomescreenWidgets}. For the latter, you | |
* simply have to change the <code>updateIntent</code> declaration to: | |
* <code>Intent updateIntent = new Intent(c, <b>UpdaterService.class</b>);</code> | |
*/ | |
public class WidgetHelper { | |
/** | |
* Updates all the homescreen widgets for this application. | |
* | |
* @param c The Context used to update the widgets. | |
*/ | |
public static void updateAllHomescreenWidgets(Context c) { | |
AppWidgetManager widgetMgr = AppWidgetManager.getInstance(c); | |
if (widgetMgr != null) { | |
int[] widgetIds = widgetMgr.getAppWidgetIds(new ComponentName(c, WidgetProvider.class)); | |
Intent updateIntent = new Intent(c, WidgetProvider.class); | |
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); | |
updateIntent.putExtra(WidgetProvider.EXTRA_WIDGET_IDS, widgetIds); | |
c.sendBroadcast(updateIntent); | |
} | |
} | |
} |
Thanks Mark, I'm adding the ComponentName
-- that is also most likely the cause of a strange bug I've seen on Samsung devices. I'm writing an article on that, will update it because I think your comment just got me to an epiphany on what was going on there!
Preview, long story short: probably Samsung doesn't filter intents by process when it comes to updating widgets. Meaning, you can update other apps' widgets when you use the TouchWiz launcher. This doesn't happen on other devices though (and, security-wise, it shouldn't as I think it's a pretty dangerous security hole for phishing).
@rock3r: I seem to recall hearing about that security issue before, though I don't see it in my archived emails to the Android security team. It's certainly worth writing about. Ideally, the CTS would check this for stock home screens, though third-party home screens could still screw up. If you think of it, hit me up on Twitter or email or something when you post your articles -- thanks!
Using the BroadcastReceiver
/ AppWidgetProvider
when you're triggering the widget update yourself is a complete red herring. Just talk directly to the AppWidgetManager
from a background thread (ideally wrapped via a Service
).
@tiwiz: I do not understand. The launcher is not directly involved in the
ACTION_APPWIDGET_UPDATE
flow, particularly if the broadcast is targeted at your specific component. Hence, the launcher should neither know nor care whether the app widget IDs were passed around viaEXTRA_APPWIDGET_IDS
or any other extra name.