Below is some code for my widget extending AppWidgetProvider. The widget renders correctly when put on a home screen, but the view is empty. Using logging, I found that no methods are called from the classes I used to extend RemoteViewsService (BudgetWidgetService), which returns an implementation of RemoteViewsService.RemoteViewsFactory.
Is there a mistake causing BudgetWidgetService to never be instantiated or used?
I can't even find a way to check if the BudgetWidgetService is even bound to the RemoteViews layout I create. If you can think of any I can further diagnose this problem, other than logging method calls in my AppWidgetProvider and extension of RemoteViewsService, I would appreciate that as well,
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.i("Budget Widget", "Provider onUpdate called");
// Update each of the widgets with the remote adapter
for (int i = 0; i < appWidgetIds.length; ++i) {
RemoteViews layout = buildLayout(context, appWidgetIds[i]);
appWidgetManager.updateAppWidget(appWidgetIds[i], null);
appWidgetManager.updateAppWidget(appWidgetIds[i], layout);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
private RemoteViews buildLayout(Context context, int appWidgetId) {
Log.i("Budget Widget", "Provider buildLayout called");
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_budget);
RemoteViews list_item = new RemoteViews(context.getPackageName(), R.layout.widget_budget_item);
list_item.setTextViewText(R.id.widget_budget_item_text, "Test #1");
final Intent intent = new Intent(context, BudgetWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(R.id.widget_budget_list, intent);
rv.setEmptyView(R.id.widget_budget_list, R.id.empty_view);
final Intent refreshIntent = new Intent(context, BudgetWidgetProvider.class);
refreshIntent.setAction(BudgetWidgetProvider.REFRESH_ACTION);
final PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, 0,
refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.refresh_button, refreshPendingIntent);
return rv;
}
I was having the same problem, and discovered that I had forgotten to add the android.permission.BIND_REMOTEVIEWS permission to my RemoteViewsService in my AndroidManifest.xml:
<service android:name="MyWidgetService"
...
android:permission="android.permission.BIND_REMOTEVIEWS" />
I found my answer under the section "Manifest for app widgets with collections" on the App Widgets guide.
Related
I have some buttons in my widget that I want to send a intent extra string and also open my Main Activity. This process seems easy enough when it comes from Activity to Activity but I can't make it work from Widget to Activity. I saw some other answers here but I must be missing something because my Logs are not going off.
Here is my updateAppWidget method:
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.budget_keeper_widget);
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("widget_one", "widget_one");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.button_1_widget, pendingIntent);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
Here's my MainActivity
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String intentFromWidget = intent.getStringExtra("widget_one");
Log.e("WIDGET MAIN INTENT", intentFromWidget);
}
This opens my Activity fine but I get no intent extra in my Logs. What's the trick to making this work?
Thank you!
I have a widget that display a simple text and 3 buttons:
Refresh (Picks another random string and displays it)
Copy (Copy the contents of the textview to the clipboard)
Share (Share the content of the textview to social media and such)
I already Got the refresh button setup and working just fine but I can't seem to figure out a way to handle the other two buttons
PS. I don't need the actual code I already know how to do the copying and sharing I just need to know how to handle click events
Here is my code so far:
Button copy_content;
Button share_content;
void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
/** Code below will be executed once the timer is over*/
String widgetText = RandQuotes[rand.nextInt(RandQuotes.length)];
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.quotes_widget);
views.setTextViewText(R.id.sayings, widgetText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
final int count = appWidgetIds.length;
for (int i = 0; i < count; i++) {
int widgetId = appWidgetIds[i];
String on_sayings = RandQuotes[rand.nextInt(RandQuotes.length)];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.quotes_widget);
remoteViews.setTextViewText(R.id.sayings, on_sayings);
Intent intent = new Intent(context, HavamalWidget.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.switch_trigger, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
Just make pending intents on buttons with action. So in onReceive() just check action of intent and make some logic on that. If you make some long tasks, better to make all logic in IntentService.
Set pending intents on your buttons that are in RemoteViews like this:
public static final String ACTION_BUTTON_SHARE = "ACTION_BUTTON_SHARE";
public static final String ACTION_BUTTON_REFRESH = "ACTION_BUTTON_REFRESH";
Intent refreshIntent = new Intent(context, ExampleAppWidget.class)
.setAction(ACTION_BUTTON_REFRESH);
PendingIntent refreshPI = PendingIntent.getBroadcast(context, 0, refreshIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.refresh_button, refreshPI);
Intent shareIntent = new Intent(context, ExampleAppWidget.class)
.setAction(ACTION_BUTTON_SHARE);
PendingIntent sharePI = PendingIntent.getBroadcast(context, 0, shareIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.share_button, sharePI);
In ExampleAppWidget.class (that extends from AppWidgetProvider) override OnReceive() method
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
if (intent.getAction().equals(ACTION_BUTTON_REFRESH)) {
//make some logic here on button refresh
} else if (intent.getAction().equals(ACTION_BUTTON_SHARE)) {
//make some logic here on button share
} else {
super.onReceive(context, intent);
}
}
}
I made an widget which have the image and show the time. howerver , the time cannot update.so I try to implement that the time will be updated when user click on the widget.
I find some tutorial said that using setOnClickPendingIntent can do this but my code not work.
Any solutions can let the widget update the time onClick or Auto Updating?
public class NewAppWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date());;
// Construct the RemoteViews object
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
Intent intent = new Intent(context, NewAppWidget.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
updateViews.setOnClickPendingIntent(R.id.imageView, pendingIntent);
updateViews.setTextViewText(R.id.editText2, widgetText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}
Change you PendingIntent like this
Intent intent = new Intent()
intent.putExtra(EXTRA_VALUES, values)
intent.setComponent(new ComponentName(context, NewAppWidget.class));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
I am doing the widget development first time. So please bear with me. I have an Android service that starts the widget from onStart(). So I am in my WidgetProvider class onUpdate() and update the views like buttons.
Now my question is -
1) How do I handle press of buttons in widget and tell the service about button press so that service does its work?
2) After the service has done its work, it needs to update the widget buttons and how do I handle this?
3) When the app is killed, the service is also killed. So when I click on widget, how do I determine that app is killed and open the app?
4) If the UI in app is talking to service and receiving responses from service, how do I tell these responses to widget too?
My widget code is like this -
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews;
ComponentName componentName;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
componentName = new ComponentName(context, MyWidgetProvider.class);
remoteViews.setOnClickPendingIntent(R.id.button1,getPendingSelfIntent(context, "Play",componentName));
remoteViews.setOnClickPendingIntent(R.id.button2,getPendingSelfIntent(context, "Pause",componentName));
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
if ("Play".equals(intent.getAction())) {
//I really dont know what to do here....
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews;
ComponentName watchWidget;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
watchWidget = new ComponentName(context, MyWidgetProvider.class);
appWidgetManager.updateAppWidget(watchWidget, remoteViews);
}
}
protected PendingIntent getPendingSelfIntent(Context context, String action, ComponentName componentName) {
Intent intent = new Intent(context, MyService.class);
intent.setAction(action);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, componentName);
return PendingIntent.getService(context, 0, intent, 0);
}
}
Request you to please help me in this
1) You're already doing that with your getPendingSelfIntent() method. Although your target should be MyWidgetProvider like this:
Intent intent = new Intent(context, MyWidgetProvider.class);
Then in your onReceive you will check if the intent action is "Play" and start your service from there:
Intent serviceIntent = new Intent(context, MyService.class);
2) In order to your service communicate to your Widget you need to send a broadcast:
Intent widgetUpdateIntent = new Intent(this, MyWidgetProvider.class);
widgetUpdateIntent.setAction(ApplicationEvents.DATA_FETCHED);//this is your custom action
widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
sendBroadcast(widgetUpdateIntent);
3) You don't need to explicit open the app (you can't do that, actually), if you have your update cycle set to 30 mins you will receive the onUpdate callback and you need to start your service from there too.
4) You will update the UI in the onReceive event when the action matches your custom action (ApplicationEvents.DATA_FETCHED).
I have an app widget and the click event can be received in onUpdate() in my provider.
However, when I try to force close the home launcher, the click event is lost.
I even put breakpoints in all onEnabled(), onReceived()...etc: the connection seems to be lost.
As a result, how can I "re-connect" the button event?
WidgetProvider extends AppWidgetProvider:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.d(TAG, "onUpdate()");
Log.d(TAG, "isLoading: " + CONSTANT.isLoading);
// update each of the widgets with the remote adapter from updateService
// Get all ids
ComponentName thisWidget = new ComponentName(context, ScoreWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
// Update the widgets via the service
context.startService(intent);
// super.onUpdate(context, appWidgetManager, appWidgetIds);
}
UpdateWidgetService extends Service:
#Override
public void onStart(Intent intent, int startId) {
Log.i(TAG, "Called");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
for (int i = 0; i < appWidgetIds.length; ++i) {
// Here we setup the intent which points to the StackViewService which will
// provide the views for this collection.
Intent remoteViewsIntent = new Intent(this.getApplicationContext(), ScoreWidgetRemoteViewsService.class);
remoteViewsIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
remoteViewsIntent.setData(Uri.parse(remoteViewsIntent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews rv = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.widget_layout);
rv.setRemoteAdapter(appWidgetIds[i], R.id.score_list, remoteViewsIntent);
// Set the empty view to be displayed if the collection is empty. It must be a sibling
// view of the collection view.
rv.setEmptyView(R.id.score_list, R.id.empty_view);
// Bind the click intent for the refresh button on the widget
final Intent refreshIntent = new Intent(this.getApplicationContext(), ScoreWidgetProvider.class);
refreshIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
refreshIntent.setAction(ScoreWidgetProvider.REFRESH_ACTION);
final PendingIntent refreshPendingIntent = PendingIntent
.getBroadcast(this.getApplicationContext(), 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.btn_refresh, refreshPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
// stopSelf();
super.onStart(intent, startId);
}
Make sure that you are using the correct context in your onStart function. Check out getApplicationContext in the onStart part of your code, passing in the wrong type of context can cause errors. Here is a link for more information: Context.