I am trying to make a widget for my app, and I want it to be with a buttonm progress bar and text view, which would later be changed, so I need to somehow work with the views themselves, like I can from an activity, show a view, hide a view, change a button background etc...
I tried tweaking with the sample code from the Android documentations, but I can only start an activity with this
public class WidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, ActivityMain.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
}
Does the widget need to be connected to an activity in order to make actions (connect to the internet, write in the database, write in the objects of the apps instance (if there is one))? And can I work with views the way I am asking?
Outside of setting on-click PendingIntents on views, there isn't much you can do inside of a widget. The standard recipe is:
Make a PendingIntent that sends a broadcast (PendingIntent.getBroadcast()) and set it on the appropriate view in your widget.
In the BroadcastReceiver that receives the intent, you update the widget to show a spinner and start a Service to do whatever long-running work you want to do (e.g connect to the internet).
Once that work is done, you can update your widget again and remove the spinner.
Related
Good Day! I want to add text from inside application to widget, i have a main activity and it has list view and lots of text contents and it has a button to add the text to widget via shared preference, it's works fine when i close the widget and recreate it only, otherwise it's not automatically refresh.if anyone know; how to solve this please help me. here i attached the widget code below.
public class WidgetMaster extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
Intent intentHome = new Intent(context, MainActivity.class);
PendingIntent pendingIntentHome = PendingIntent.getActivity(context, 0, intentHome, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_master);
views.setOnClickPendingIntent(R.id.wid_home, pendingIntentHome);
final SharedPreferences sharedPreferencestoWi = context.getSharedPreferences(String.valueOf(R.string.addTextToWidgetPref), MODE_PRIVATE);
String forWidget = sharedPreferencestoWi.getString("textToWidget", "");
String dum = "add from reading";
if(forWidget.equals("")){
views.setTextViewText(R.id.dum_appwidget_text, dum);
appWidgetManager.updateAppWidget(appWidgetId, views);
} else {
views.setTextViewText(R.id.appwidget_text, forWidget);
views.setViewVisibility(R.id.appwidget_text, 0);
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);
}
}
#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
}
}
How do you update the widget from mainActivity?
In the widget configuration file you can specify a fixed update interval. The smallest update interval is 1800000 milliseconds (30 minutes).
But its better to update widget programmatically, to do this You should send a broadCast to update widget and use a
method like alarmManager or Handler for a repeating task for example you can use the following broadCast to update widget form mainActivity:
Intent intent = new Intent(this, WidgetMaster.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
int[] ids = AppWidgetManager.getInstance(getApplication())
.getAppWidgetIds(new ComponentName(getApplication(),WidgetMaster.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
sendBroadcast(intent);
I am developing an Android app with a homescreen widget, which is an imageButton, and i want the image of the button to change after its been pressed. I have tried selector in an xml file, to change the image of the button, but it changes it only when it is pressed, but it goes back when its released.
I want it to change image after it was pressed and when the code inside the WidgetProvider is executed, it changes the image back to the default one.
I tried to do it programatically(in onRecieve() method), I guess it should be something with RemoteViews but whatever i try, it doesnt work.
Could someone help my with this? I saw many people asking about it, but most of the posts were either pretty old or the solutions were not working for me.
Thank you :)
Normally you'd set the image on the surface of the ImageButton using the setImageResource method (ImageButton inherits it from ImageView), but that method isn't available for RemoteViews.
RemoteViews offers a corresponding setImageViewResource method that does what you want (as well as setImageViewBitmap and setImageViewUri depending on how you'd like to provide the image data).
The code to set the image (say, within your BroadcastReceiver's onReceive method) would look something like this:
#Override
public void onReceive(Context context, Intent intent) {
int appWidgetId = intent.getIntExtra("appWidgetId", -1);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setImageViewResource(R.id.imageButton1, R.drawable.awesome_image);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
Note that the code above assumes you've added the id of the widget to be manipulated as an extra to the broadcast intent (wrapped in a PendingIntent that is sent when the user clicks the ImageButton) using the key "appWidgetId". You'll most likely want to do that in the onUpdate method of your AppWidgetProvider, like so:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent ("YourActionHere");
intent.putExtra("appWidgetId", appWidgetId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, i, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setImageViewResource(R.id.imageButton1, R.drawable.initial_image);
views.setOnClickPendingIntent(R.id.imageButton1, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
A simple but not elegant way is:
boolean isButtonSelected = false;
..
button.setOnClickListener(buttonListener);
..
OnClickListener buttonListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
if(isButtonSelected ){
isButtonSelected = false;
button.setBackgroundResource(R.drawable.buttonOff); // or setImageResource(..);
} else{
isButtonSelected = true;
button.setBackgroundResource(R.drawable.buttonOn);
}
}
};
I created a class that downloads some text from the internet and I want to take that text and update a TextView in my widget. I know that the event (OnDownloadCompleteListener) is getting triggered because I'm Logging it but I can't figure out how to update the TextView from within that event. I know it's a newbie mistake, just not sure what I'm missing.
public class Widget extends AppWidgetProvider{
InternetText internettext; //Handles downloading the text from the internet
RemoteViews views;
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.tvWidgetVerse, pendingIntent);
internettext = new InternetText(context);
internettext.setOnDownloadCompleteListener(new OnDownloadCompleteListener() {
#Override
public void onEvent() {
TheText thetext = internettext.downloadedText(); //The text object
Log.i("", "Widget Text Downloaded " + thetext.getText()); //This fires so I know we've downloaded the text
TextStyling textStyle = new TextStyling();
//*****THIS IS WHERE I'M HAVING THE PROBLEM********
views.setTextViewText(R.id.tvWidgetText, Html.fromHtml(textStyle.boldWords(thetext.getText()))); //this never updates
}
});
internettext.getText();
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Ok, I figured it out. I have to call appWidgetManager.updateAppWidget() from within the event. I knew it was a no-brainer...
appWidgetManager.updateAppWidget(appWidgetId, views);
which also means I have to make appWidgetManager and appWidgetId final
public void onUpdate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds) {
...
}
When I click on my application widget, instead of going back to the last activity I left open (when going into the home screen), Android restarts my application from scratch.
Is there a way to make that click behave exactly like my app icon, or like the "recent apps manager"?
Here is how I implemented the widget:
public class WidgetLauncher extends AppWidgetProvider {
#Override
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];
Intent active = new Intent(context, COPD_Main.class);
active.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, active, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.launch_support);
views.setOnClickPendingIntent(R.id.launch_support_launcher, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
PS: I am aware there are several questions around like:
this
but it did not fix my problem at all.
I believe the problem is the Intent flag you are using. Try to use:
active.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
isntead of NEW_TASK.
From the docs:
If set, the activity will not be launched if it is already running at
the top of the history stack.
When I'm running in debugging mode I can't seem to reach any breakpoints that are inside of the service, why is that?
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
context.startService(new Intent(context, UpdateService.class));
}
public static class UpdateService extends Service {
#Override
public void onStart(Intent intent, int startId) {
// Build the widget update for today
RemoteViews updateViews = buildUpdate(this);
// Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(this, WidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
public RemoteViews buildUpdate(Context context) {
return new RemoteViews(context.getPackageName(), R.id.widget_main_layout);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
The "onUpdate"-method is only executed if the widget is initalized (e.g. put on the homescreen) or the updatePeriodMillis are expired. If you want to execute the service e.g. by a click on the widget, you have to "attach" a pending intent like this:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final Intent intent = new Intent(context, UpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener to
// the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout....);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
for(int i=0,n=appWidgetIds.length;i<n;i++){
int appWidgetId = appWidgetIds[i];
appWidgetManager.updateAppWidget(appWidgetId , views);
}
(cleaned up version of a working widget).
The point is, that the onUpdate() method is really very seldom executed. The real interaction with a widget is specified through pending intents.
Your Service might not be registered in the manifest. Or your AppWidgetProvider might not be registered in the manifest.
You might want to think of not using a service for what you're doing. If it's just running the updateViews() once a day then consider just setting android:updatePeriodMillis to 86400000 in the XML file that's linked to your appwidget. Your XML file would look something like this:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="72dp"
android:maxWidth="72dp"
android:updatePeriodMillis="86400000" >
</appwidget-provider>
This will have android update your appwidget once a day without having a service run in the background that might get killed by a task killer that the user is running which then stops your widget from updating. Just a note, if you need it to update faster than every 30 minutes then android:updatePeriodMillis won't work (it's minimum value is 30 minutes) at that point I'd recommend using an AlarmManager since that'll use up less battery than a Service and also won't be killed by task killers.