I've followed a bunch of tutorials, search on google and on stack overflow and came up with this code to update my widget when i touch it:
public class WidgetService extends Service{
#Override
public void onStart(Intent intent, int startId) {
Log.i("WidgetService", "Called");
String fakeUpdate = null;
Random random = new Random();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
int[] appWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds.length > 0) {
for (int widgetId : appWidgetIds) {
int nextInt = random.nextInt(100);
fakeUpdate = "Random: " + String.valueOf(nextInt);
RemoteViews remoteViews = new RemoteViews(getPackageName(),
R.layout.widget);
remoteViews.setTextViewText(R.id.txt_updated, fakeUpdate);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
}
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
And for widget provider:
public class Widget extends AppWidgetProvider{
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget);
Intent intent = new Intent(context.getApplicationContext(),
WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getService(
context.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.cnt_widget, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
context.startService(intent);
}
}
In manifest:
<receiver
android:label="#string/next_trip_text"
android:name=".widget.Widget" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
And xml:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="272dp"
android:minHeight="72dp"
android:updatePeriodMillis="0"
android:initialLayout="#layout/widget"
android:configure="se.webevo.basttrafik.widget.WidgetConfigActivity" >
</appwidget-provider>
The service doesn't seem to be called at all. Any ideas? :)
Thanks!
add this to manifest:
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/-- ur appwidgetprovider location here--">
</meta-data>
also try adding:
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_ENABLED"/>
</intent-filter>
see if it works
Related
I have an widget and I must update the widget when action android.media.RINGER_MODE_CHANGED occurs. I have the folowing broadcast receiver:
public void onReceive(Context context, Intent intent) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
ComponentName thisWidget = new ComponentName(context.getApplicationContext(), ExampleAppWidgetProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (appWidgetIds != null && appWidgetIds.length > 0) {
for (int widgetId : appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context
.getApplicationContext().getPackageName(),
R.layout.widget1);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}
and this si code for my widget
public class ExampleAppWidgetProvider extends AppWidgetProvider {
DateFormat df = new SimpleDateFormat("hh:mm:ss");
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
//my pudate widget code
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
<receiver android:name=".ExampleAppWidgetProvider" android:label="demo widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget1_info" />
</receiver>
so my problem is that even if the instruction appWidgetManager.updateAppWidget(widgetId, remoteViews); from my broadcast receiver is executed, the update method inside the widget is not executed. Does anybody knows why?
it seems that AppWidgetProvider extends BroadcastReceiver so here is my code :
public class ExampleAppWidgetProvider extends AppWidgetProvider {
DateFormat df = new SimpleDateFormat("hh:mm:ss");
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
//my update code here
}
#Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
ComponentName thisWidget = new ComponentName(context.getApplicationContext(), ExampleAppWidgetProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (appWidgetIds != null && appWidgetIds.length > 0) {
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
}
<receiver android:name=".ExampleAppWidgetProvider" android:label="demo widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<intent-filter>
<action android:name="android.media.RINGER_MODE_CHANGED"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget1_info"/>
</receiver>
I create a keyguard widget that has a button that upsate textview with Random number when clicking. it works properly on the home screen but on the lock screen (android 4.2.2) it(s button) works just when i add it to my lock screen widgets but when i turn screen off and return; it(s button) doesn't work !!
Widget.java
public class Widget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new MyTime(context, appWidgetManager), 1, 50000);
}
class MyTime extends TimerTask {
RemoteViews remoteViews;
AppWidgetManager appWidgetManager;
ComponentName thisWidget;
Context context;
public MyTime(Context context, AppWidgetManager appWidgetManager) {
this.appWidgetManager = appWidgetManager;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
thisWidget = new ComponentName(context, Widget.class);
this.context=context;
}
#Override
public void run() {
Intent configIntent = new Intent(context, WidgetReceive.class);
configIntent.setAction("updateTextView");
PendingIntent configPendingIntent = PendingIntent.getBroadcast(context, 0, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.button1, configPendingIntent);
remoteViews.setTextViewText(R.id.widget_textview, String.valueOf(new Random().nextInt(100)));
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
}
}
WidgetReceive.java
public class WidgetReceive extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
ComponentName thisWidget = new ComponentName(context, Widget.class);
if(intent.getAction().equals("updateTextView")){
remoteViews.setTextViewText(R.id.widget_textview, String.valueOf(new Random().nextInt(100)));
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
}
}
AndroidManifest.xml
<receiver android:name=".Widget" android:label="#string/app_name">
<intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/hello_widget_provider" />
</receiver>
<receiver android:name=".WidgetReceive">
<intent-filter>
<action android:name="updateTextView"/>
</intent-filter>
</receiver>
The problem might be that the following line
remoteViews.setOnClickPendingIntent(R.id.button1, configPendingIntent);
is missing from WidgetReceive.onReceive(...)
When updating an app widget with a RemoteViews object, you must create all the contents of the widget, including the listeners, every time.
I want to do a widget with a list inside, I have to implement a class that extends of RemoteViewsService, but this class never execute, my code is the following:
MyWidgetProvider
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);
Intent updateIntent = new Intent(context, WidgetService.class);
for (int appWidgetId : appWidgetIds) {
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
updateIntent.setData(Uri.parse(updateIntent.toUri(Intent.URI_INTENT_SCHEME)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
views.setRemoteAdapter(appWidgetId, updateIntent);
else
views.setRemoteAdapter(appWidgetId, R.id.events_list, updateIntent);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.events_list);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
WidgetService
public class WidgetService extends RemoteViewsService {
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new WidgetFactory(getApplicationContext(), intent);
}
}
And the Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.widget.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".MyWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/appwidget_info" />
</receiver>
<service android:name=".WidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false">
</service>
</application>
Edit;
I have found the error, i have to use:
views.setRemoteAdapter(R.id.events_list, updateIntent);
instead of
views.setRemoteAdapter(appWidgetId, updateIntent);
See RemoteViews.html#setRemoteAdapter
The SetRemoteAdapter function with 3 parameters is deprecated in API level 14+, and even if you called the 3 parameters one, the widget id parameter is ignores. So the function always receive only 2 valid parameters, i.e. view_id and intent.
This function basically says I'm going to use the intent as a data source for the view (indicated by view_id).
for me this works
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int widgetId : appWidgetIds) {
RemoteViews mView = initViews(context, appWidgetManager, widgetId);
appWidgetManager.updateAppWidget(widgetId, mView);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
private RemoteViews initViews(Context context,
AppWidgetManager widgetManager, int widgetId) {
RemoteViews mView = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
Intent intent = new Intent(context, WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
mView.setRemoteAdapter(widgetId, R.id.widgetCollectionList, intent);
return mView;
}
I've read a lot of Q&As but I couldn't find my answer.
May be something in my implementation is wrong.
The problem is that my TextView in the widget doesn't get updated.
The logic is this:
1.setOnClickPendingIntent on a specific button in the onUpdate()
2.clicking on this button will broadcast an intent with a declared action
3.at last i'll update the text of the textView in the onRecieve()
Widget2.class :
public class Widget2 extends AppWidgetProvider {
private static final String SCROLL_LEFT = "widget2.SCROLL_LEFT";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.small);
Intent scrollLeft = new Intent(Widget2.SCROLL_LEFT);
PendingIntent leftScrollPendingIntent = PendingIntent.getBroadcast(context,
appWidgetId, scrollLeft, appWidgetId);
remoteViews.setOnClickPendingIntent(R.id.left_scroller, leftScrollPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
Log.e(getClass().getSimpleName(), "onReceive()");
int appWidgetId = intent.getFlags();
if (intent.getAction().equals(SCROLL_LEFT)) {
updateCurrentWidget(context, appWidgetId);
Log.i("onReceive", SCROLL_LEFT + " appWidgetId = " + appWidgetId);
}
super.onReceive(context,intent);
}
private void updateCurrentWidget(Context context, int appWidgetId) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.small);
remoteViews.setString(R.id.name_of_the_app, "setText", "android os");
remoteViews.setTextViewText(R.id.description, "best ever");
Log.i("updateCurrentWidget", "the text have been set");
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(appWidgetId, remoteViews);
}
manifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="14" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<receiver android:name=".Widget2" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="widget2.SCROLL_LEFT" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_small" />
</receiver>
</application>
</manifest>
and here is the simplified logcat logs:
onReceive()
"myPackageName".Widget2.SCROLL_LEFT
the text have been set
"myPackageName".Widget2.SCROLL_LEFT appWidgetId = 268435456
everything seems to be correct but the text is never changed!
The key in the widget is you have to set every View and every Intent before calling the updateAppWidget() method. Here You can call updateWidgetInstance(...) from your onReceive() method:
// action = the String that you get from your intent in the onRecive() method
// id = the id of the appWidget instance that you want to update
// you can get the id in the onReceive() method like this:
// int id = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
private static void updateWidgetInstance(Context context, AppWidgetManager manager, String action, int id) {
RemoteViews remoteViews = updateCurrentWidget(context, id);
remoteViews = setIntents(remoteViews, context, id);
manager.updateAppWidget(id, remoteViews);
}
updating the View: (Here you can also change the layout of this instance depending on your needs)
private static RemoteViews updateCurrentWidget(Context context, int appWidgetId) {
RemoteViews remoteViews;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_small_layout);
remoteViews.setTextViewText(R.id.widget_name_of_the_app, "Android OS");
remoteViews.setTextViewText(R.id.widget_app_description, "best ever");
remoteViews.setImageViewUri(R.id.widget_icon_of_the_app, ...);
return remoteViews;
}
updating intents:
private static RemoteViews setIntents(RemoteViews rm, Context context, int appWidgetId) {
Intent click = new Intent(context, Widget.class);
click.setAction("[name of the action]");
click.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, appWidgetId, click, PendingIntent.FLAG_UPDATE_CURRENT);
rm.setOnClickPendingIntent(R.id.button1, pendingIntent);
return rm;
}
you are setting your appWidgetId in the PendingIntent flags. that's just wrong since PendingIntet flags have meanings, they are not meant to save some data.
You should use the extras for that.
I have a widget that lets you select from 2 sizes, it also has a config. For some reason after some time goes by, the buttons on my widget will unbind and you will not be able to click anything. I dont know why this is happening. Could it be the super.onReceive(context, intent) in my OnRecieve method? Would that cause it to unbind possibly? Also what would the sure fire way to make sure the buttons are ALWAYS binded be?
AppWidgetProvider
public class mWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_REFRESH = "Refresh";
public static final String PREFS_NAME = "mWidgetPrefs";
#Override
public void onEnabled(Context context) {
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews = buildLayout(context);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
RemoteViews views = buildLayout(context);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static RemoteViews buildLayout(Context context) {
RemoteViews remoteView = new RemoteViews(context.getPackageName(),
R.layout.widget_4x2);
Intent intent = new Intent(context, mWidget.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
intent = new Intent(context, mWidget.class);
intent.setAction(ACTION_WIDGET_REFRESH);
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteView.setOnClickPendingIntent(R.id.refresh, pendingIntent);
return remoteView;
}
#Override
public void onReceive(Context context, Intent intent) {
RemoteViews remoteView = null;
remoteView = new RemoteViews(context.getPackageName(),
R.layout.widget_4x2);
if (intent.getAction().equals(ACTION_WIDGET_REFRESH)) {
Toast.makeText(context, "here", Toast.LENGTH_LONG).show();
} else {
super.onReceive(context, intent);
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".mwidgetConfig" android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity android:name=".mwidgetConfigSmall"
android:label="#string/app_name" android:theme="#android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- BEGIN 4X4 WIDGET -->
<receiver android:label="Test Widget 4x4"
android:name="com.test.mwidget.mWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action
android:name="com.test.mwidget.mWidget.ACTION_WIDGET_REFRESH" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_4x4_provider" />
</receiver>
<!-- BEGIN 4X2 WIDGET -->
<receiver android:label="Test Widget 4x2"
android:name="com.test.mwidget.mWidgetSmall">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action
android:name="com.test.mwidget.mWidgetSmall.ACTION_WIDGET_REFRESH" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_4x2_provider" />
</receiver>
</application>
You should bind your pending intent on each onUpdate event.
You should iterate through all appWidgerIds.
Usually, I implement widget stuff as the following:
public void onUpdate(Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
updateAllWidgetsInternal(context, appWidgetManager, appWidgetIds);
}
private static void updateAllWidgetsInternal(Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final RemoteViews views = buildLayout(context);
final int N = appWidgetIds.length;
for (int i=0; i<N; ++i) {
appWidgetManager.updateAppWidget(appWidgetIds[i], views);
}
}
// This function can be executed anywhere in any time to update widgets
public static void updateAllWidgets(Context context) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, mWidget.class));
updateAllWidgetsInternal(context, appWidgetManager, appWidgetIds);
}
I don't understand why you implemented onReceive().
It's only necessary if your widget is configured to catch other broadcasts than the standard widgets broadcast which are ACTION_APPWIDGET_DELETED, ACTION_APPWIDGET_DISABLED, ACTION_APPWIDGET_ENABLED and ACTION_APPWIDGET_UPDATE.
If not necessary, try without onReceive().