Why is AlarmManager not updating my widget? - android

I have a widget that is simply a textview, that I am attempting to update every second using an AlarmManager. The Log.d("test", "hello1") shows up in my LogCat when I run the app, but the Log.d("test", "service") does not show up, so it appears the program is not even reaching my MyService class.
I would greatly appreciate any help.
Thank you.
Here is my AppWidgetProvider class:
public class NetworkSpeedWidget extends AppWidgetProvider {
private PendingIntent service = null;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Log.d("test", "hello");
super.onUpdate(context, appWidgetManager, appWidgetIds);
final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final Intent i = new Intent(context, MyService.class);
if (service == null)
{
service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
}
Log.d("test", "hello1");
m.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),1000,service);
}
}
Here is my MyService class:
public class MyService extends Service{
#Override
public void onCreate()
{
Log.d("test", "service");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
buildUpdate();
return super.onStartCommand(intent, flags, startId);
}
private void buildUpdate()
{
MainActivity object = new MainActivity();
String objectString = object.getMegaBitsPerSecondString();
AppWidgetManager manager = AppWidgetManager.getInstance(this);
ComponentName thisWidget = new ComponentName(this, NetworkSpeedWidget.class);
int[]ids = manager.getAppWidgetIds(thisWidget);
final int N = ids.length;
for (int i = 0; i < N; i++){
int awID = ids[i];
RemoteViews v = new RemoteViews(getPackageName(), R.layout.widget);
v.setTextViewText(R.id.widgetTextView,objectString);
manager.updateAppWidget(awID, v);
}
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}

All my code is correct, I just needed to declare it in my Manifest.
I simply added the following line:
<service android:enabled="true" android:name=".MyService" />
Thank you jul for your help.

Related

Play sound on widget click

Here's my code, it opens the main activity, but I can't seem to find a way to just make the widget play a sound.
I tried to:
add a button to the widget (didn't work)
add an OnClickListener to the main activity (which works but it opens the main activity and I just want the sound not the activity)
write a new method to play the sound with the MediaPlayer sound.start() method in it and calling it (didn't work)
I've looked in the android dev page and all I was able to find was how to use the MediaPlayer, but it says nothing about playing audio from a widget.
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
public class ClockWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
#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, MainActivity.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.clock_widget_layout);
views.setOnClickPendingIntent(R.id.AnalogClock0, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
To do it you need to use a service which you call like this
Intent svc=new Intent(this, BackgroundSoundService.class);
startService(svc);
public class BackgroundSoundService extends Service {
private static final String TAG = null;
MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.trck);
//configure other settings
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return 1;
}
public void onStart(Intent intent, int startId) {
// TO DO
}
public IBinder onUnBind(Intent arg0) {
// TO DO Auto-generated method
return null;
}
public void onStop() {
}
public void onPause() {
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
}
Please register this service in Manifest.
<service android:enabled="true" android:name=".BackgroundSoundService" />
and you could do smth like this in widget
public class ClockWidget extends AppWidgetProvider {
private final String ACTION_WIDGET_PLAY = "PlaySong";
private final String ACTION_WIDGET_PAUSE = "PauseSong";
private final String ACTION_WIDGET_STOP = "StopSong";
private final int INTENT_FLAGS = 0;
private final int REQUEST_CODE = 0;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews controlButtons = new RemoteViews(context.getPackageName(),
R.layout.main);
Intent playIntent = new Intent(this, BackgroundSoundService.class);
Intent pauseIntent = new Intent(this, BackgroundSoundService.class);
Intent stopIntent = new Intent(this, BackgroundSoundService.class);
PendingIntent playPendingIntent = PendingIntent.getService(
this, REQUEST_CODE, playIntent, INTENT_FLAGS);
PendingIntent pausePendingIntent = PendingIntent.getService(
this, REQUEST_CODE, pauseIntent, INTENT_FLAGS);
PendingIntent stopPendingIntent = PendingIntent.getService(
this, REQUEST_CODE, stopIntent, INTENT_FLAGS);
controlButtons.setOnClickPendingIntent(
R.id.btnPlay, playPendingIntent);
controlButtons.setOnClickPendingIntent(
R.id.btnPause, pausePendingIntent);
controlButtons.setOnClickPendingIntent(
R.id.btnStop, stopPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, controlButtons);
}
}

Android: Clickable imageview widget

I want to make a very simple widget:
It must consist from just one image view
1) on incoming sms it should change the image
2) on click it also should change the image
I tried to make it using ImageButton but failed: there were problems with changing the image on sms received event: new image had wrong scale.
Anyway now I want to make an ImageView without anything else.
The problem is that I can't handle onClick event:
I've got a running service which should handle all events: sms received and click:
widget provider:
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onDisabled(Context context) {
context.stopService(new Intent(context, UpdateService.class));
super.onDisabled(context);
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
Intent intent = new Intent(context, UpdateService.class);
context.startService(intent);
}
#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.main);
Intent widgetClickIntent = new Intent(context, UpdateService.class);
widgetClickIntent.setAction(UpdateService.ACTION_ON_CLICK);
PendingIntent pendingIntentViewClick = PendingIntent.getService(context, 0, widgetClickIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_imageview, pendingIntentViewClick);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
}
service:
public class UpdateService extends Service {
static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
static final String ACTION_ON_CLICK = "android.MyWidget.ACTION_ON_CLICK";
private final static IntentFilter intentFilter;
static {
intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_SMS_RECEIVED);
intentFilter.addAction(ACTION_ON_CLICK);
}
public final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(ACTION_SMS_RECEIVED)) {
reactOnSms(context);
}
if (action.equals(ACTION_ON_CLICK)) {
onCLick(context);
}
}
};
#Override
public void onCreate() {
super.onCreate();
registerReceiver(broadcastReceiver, intentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void reactOnSms(Context context) {
// doSomething
}
public void onCLick(Context context) {
// doSomething
}
Manifest:
<receiver a:name="..."...>
<intent-filter>
<action a:name="android.provider.Telephony.SMS_RECEIVED"/>
<action a:name="android.MyWidget.ACTION_ON_CLICK"/>
</intent-filter>
<meta-data a:name="android.appwidget.provider"
a:resource="#xml/my_widget_provider_info"/>
</receiver>
<service a:name=".UpdateService"
a:label="UpdateService">
<intent-filter>
<action a:name="android.provider.Telephony.SMS_RECEIVED"/>
<action a:name="android.MyWidget.ACTION_ON_CLICK"/>
</intent-filter>
</service>
I tried this Clickable widgets in android
I found the solution.
Sorry for those of you who read the question. Too much code inside, I understand.
The problem was that UpdateService was not the real handler of the broadcast intent. Anonymous implementation of BroadcastReceiver made all the work.
So the problem was in this code (widgetProvider):
#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.main);
// wrong:
// Intent widgetClickIntent = new Intent(context, UpdateService.class);
// widgetClickIntent.setAction(UpdateService.ACTION_ON_CLICK);
// PendingIntent pendingIntentViewClick = PendingIntent.getService(context, 0, widgetClickIntent, 0);
// correct:
Intent widgetClickIntent = new Intent(UpdateService.ACTION_ON_CLICK);
PendingIntent pendingIntentViewClick = PendingIntent.getBroadcast(context, 0, widgetClickIntent, 0);
///////
remoteViews.setOnClickPendingIntent(R.id.widget_imageview, pendingIntentViewClick);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}

Buttons in AppWidget

Hello I'm trying to add buttons to my Appwidget, but even after reading many codes, my buttons aren't working.
This is my AppWidgetProvider:
public class MyWidget extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Intent intent = new Intent(context, MyService.class);
intent.setAction("0");
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
views.setOnClickPendingIntent(R.id.button_widget, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, views);
}
}
And here is MyService:
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String command = intent.getAction();
int[] appWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
RemoteViews remoteView = new RemoteViews(getApplicationContext()
.getPackageName(), R.layout.widgetlayout);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(getApplicationContext());
if (command.equals("0")) {
remoteViews.setTextViewText(R.id.button_widget, "TextChanged");
}
RemoteViews remoteViews = new RemoteViews(getPackageName(),
R.layout.widgetlayout);
appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
super.onStart(intent, startId);
return 0;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
This is just a dummy code that is supposed to changed a button's text when you click it. It doesn't.
Any ideas about what I'm doing wrong?
Thanks.
i just take a look in your source code, it seem problem belong logic,
your re-create new RemoteView object after your change text content:
Solution: Comment out following line of code:
/* 22/07/2011 DELETE START */
//RemoteViews remoteViews = new RemoteViews(getPackageName(),
// R.layout.widgetlayout);
/* 22/07/2011 DELETE END */
In class MyService:
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String command = intent.getAction();
int[] appWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
RemoteViews remoteView = new RemoteViews(getApplicationContext()
.getPackageName(), R.layout.widgetlayout);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(getApplicationContext());
if (command.equals("0")) {
remoteViews.setTextViewText(R.id.button_widget, "TextChanged");
}
/* 22/07/2011 DELETE START */
//RemoteViews remoteViews = new RemoteViews(getPackageName(),
// R.layout.widgetlayout);
/* 22/07/2011 DELETE END */
appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
super.onStart(intent, startId);
return 0;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Try to put your code from onStartCommand into
public void onStart(Intent intent, int startId)
as you might run your code on older Android platforms that only use onStart.

Widget double click

I have a widget (AppWidgetProvider) and i want to know if there is a way to support multiple clicks.Example:
1)If is the first click on the widget, then the ImageButton of the widget changes (for example, changes the color).
2)If is the second time, then open an Activity.
-- There is some way to handle click events inside AppWidgetProvider?
My code:
public class MyWidgetProvider 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 intent = new Intent(context, MyActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.control_widget);
views.setOnClickPendingIntent(R.id.asdf, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
My widget is working fine. When i click the ImageButton(R.id.asdf), it goes to the activity MyActivity.
Id like to know how can i handle click events on my widget to make a different action (example: change the color of the ImageButton) instead of go to some activity. Is there some other way to some click handle besides setOnClickPendingIntent()?
Maybe this could help. It works for me:
public class WidgetProvider extends AppWidgetProvider {
private static final int DOUBLE_CLICK_DELAY = 500;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent intent = new Intent(context, getClass());
intent.setAction("Click");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.image, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, views);
context.getSharedPreferences("widget", 0).edit().putInt("clicks", 0).commit();
}
#Override
public void onReceive(final Context context, Intent intent) {
if (intent.getAction().equals("Click")) {
int clickCount = context.getSharedPreferences("widget", Context.MODE_PRIVATE).getInt("clicks", 0);
context.getSharedPreferences("widget", Context.MODE_PRIVATE).edit().putInt("clicks", ++clickCount).commit();
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int clickCount = context.getSharedPreferences("widget", Context.MODE_PRIVATE).getInt("clicks", 0);
if (clickCount > 1) Toast.makeText(context, "doubleClick", Toast.LENGTH_SHORT).show();
else Toast.makeText(context, "singleClick", Toast.LENGTH_SHORT).show();
context.getSharedPreferences("widget", Context.MODE_PRIVATE).edit().putInt("clicks", 0).commit();
}
};
if (clickCount == 1) new Thread() {
#Override
public void run(){
try {
synchronized(this) { wait(DOUBLE_CLICK_DELAY); }
handler.sendEmptyMessage(0);
} catch(InterruptedException ex) {}
}
}.start();
}
super.onReceive(context, intent);
}
}
I did it this way:
1)If is the first click on the widget, then the ImageButton of the widget changes
2)If is the second time, then open an Activity and return to the inicial ImageButton state.
Im handling click events with setOnClickPendingIntent:
private int[] RESOURCES = {R.drawable.button1,R.drawable.button2};
#Override
public void onUpdate(Context context, AppWidgetManager mgr, int[] appWidgetIds) {
ComponentName me = new ComponentName(context, MyWidgetProvider.class);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.my_widget);
Intent widgetIntent = new Intent(context, MyWidgetProvider.class);
Intent myIntent= new Intent(context, MyOtherActivity.class);
widgetIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
widgetIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent;
if(clicks == 0)
{
clicks = 1;
remoteViews.setImageViewResource(R.id.my_image_button, RESOURCES[0]);
pendingIntent = PendingIntent.getBroadcast(context, 0, widgetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
else if(clicks == 1)
{
clicks = 2;
remoteViews.setImageViewResource(R.id.my_image_button, RESOURCES[1]);
pendingIntent = PendingIntent.getActivity(context, 0, myIntent,0);
}
else //clicks == 2
{
clicks = 0;
remoteViews.setImageViewResource(R.id.my_image_button, RESOURCES[0]);
pendingIntent = PendingIntent.getBroadcast(context, 0, widgetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
remoteViews.setOnClickPendingIntent(R.id.my_image_button, pendingIntent);
mgr.updateAppWidget(me, remoteViews);
}
#Override
public void onEnabled(Context context) {
clicks = 0;
super.onEnabled(context);
}
Unlike Button and its subclasses, AppWidget doesn't have the concept of an onClickListener. AppWidgets have to provide a PendingIntent for the application that hosts them to fire when the widget is clicked. If you wanted to track multiple clicks, you would need to have a receiver that filters on an intent specific to your widget and keeps track of how many times it has received it.
Slightly-less-relevant: You might reconsider your behavior model. Android is a one-click-to-take-action environment that doesn't have the same "click-once-to-select" concept like you'd find in, say, Windows. By emulating that behavior, your widget won't behave like all of the other UI elements and may cause confusion. Additionally, if there are two of your widgets on the screen and the user taps one and then the other, both will appear "selected," which probably isn't what you want.
Why not just count the clicks yourself?
private class MyAwesomeClickListener implements OnClickListener {
private int clicks = 0;
#Override
public void onClick(View v) {
++clicks;
//do some cool stuff
}
}
Don't count it in a listener (it's ridiculous, you don't know when your widget will be recycled from the memory and you will lose the value of int clicks)
Persist the number of clicks (add +1 each time it is clicked, restart to 0 when you reach the end of the click "cycle", the end of different click behaviors).
You could persist them in a database, with serialization, or with the shared preferences (I guess the preferences are the easiest way)
This is what I'm doing. Works beautifully =]
public class MyWidgetProvider extends AppWidgetProvider {
//Length of allowed time in between clicks in milliseconds
private static final long DOUBLE_CLICK_WINDOW = 400;
private static volatile long firstClickTimeReference;
#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];
long currentSystemTime = System.currentTimeMillis();
if(currentSystemTime - firstClickTimeReference <= DOUBLE_CLICK_WINDOW) {
//double click happened in less than 400 miliseconds
//so let's start our activity
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity( intent );
} else {
firstClickTimeReference = currentSystemTime;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.control_widget);
Intent intent = new Intent(context, WidgetProvider.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.actionButton, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}
}
The solution by almisoft provides a double-click feel rather than simply successive clicks. And it works. Unfortunately you also get a lint message telling you that the 'handler class should be static or leaks might occur'. The solution is to use a weak reference and static handler - a generic version is here. Converting almisoft's code gives:
public class WidgetProvider extends AppWidgetProvider {
private static final int DOUBLE_CLICK_DELAY = 500;
private static Context mContext;
private static int mClickCount;
private static class MyHandler extends Handler {
//Using a weak reference means you won't prevent garbage collection
private final WeakReference<WidgetProvider> myClassWeakReference;
public MyHandler(WidgetProvider myClassInstance) {
myClassWeakReference = new WeakReference<WidgetProvider>(myClassInstance);
}
#Override
public void handleMessage(Message msg) {
WidgetProvider myWidget = myClassWeakReference.get();
if (myWidget != null) {
//...do work here as in almisoft original...
int clickCount = mContext.getSharedPreferences("widget", Context.MODE_PRIVATE).getInt("clicks", 0);
if (clickCount > 1) {
Toast.makeText(mContext, "doubleClick", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "singleClick", Toast.LENGTH_SHORT).show();
}
mContext.getSharedPreferences("widget", Context.MODE_PRIVATE).edit().putInt("clicks", 0).commit();
}
}
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent intent = new Intent(context, getClass());
intent.setAction("Click");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.image, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, views);
context.getSharedPreferences("widget", 0).edit().putInt("clicks", 0).commit();
}
#Override
public void onReceive(final Context context, Intent intent) {
mContext=context;
mIntent=intent;
if (intent.getAction().equals("Click")) {
int clickCount = context.getSharedPreferences("widget", Context.MODE_PRIVATE).getInt("clicks", 0);
context.getSharedPreferences("widget", Context.MODE_PRIVATE).edit().putInt("clicks", ++clickCount).commit();
final Handler handler=new MyHandler(this);
if (clickCount == 1) new Thread() {
#Override
public void run(){
try {
synchronized(this) { wait(DOUBLE_CLICK_DELAY); }
handler.sendEmptyMessage(0);
} catch(InterruptedException ex) {}
}
}.start();
}
super.onReceive(context, intent);
}
}

Android Widget update

Based on this tutorial I created a widget that should show the time. The java way works, but the service way doesn't.
HelloWidget.java:
public class HelloWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Intent intent = new Intent(context, UpdateService.class);
context.startService(intent);
}
}
UpdateService.java:
public final class UpdateService extends Service {
#Override
public void onStart(Intent intent, int startId) {
RemoteViews updateViews = new RemoteViews(this.getPackageName(), R.layout.main);
Date date = new Date();
java.text.DateFormat format = SimpleDateFormat.getTimeInstance(
SimpleDateFormat.MEDIUM, Locale.getDefault());
updateViews.setTextViewText(R.id.widget_textview, "Current Time " + format.format(date));
ComponentName thisWidget = new ComponentName(this, HelloWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
The hello_widget_provider.xml has this row: android:updatePeriodMillis="1000"
Problem:
The widget shows the current time but it's not updating (the java-way is).
My main goal is to update the widget at e.g. 18:56 every day.
Idk if this is the good way, but i tried to modify the onUpdate method like below, but it has a problem with ALARM_SERVICE: ALARM_SERVICE cannot be resolved to a variable
public class HelloWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
AlarmManager alarmManager;
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 18);
cal.set(Calendar.MINUTE, 56);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 86400, pendingIntent);
}
}
Any help is appreciated.
Looking back the time I asked this question makes me realize how much I learned in the past 1,5 years.
Since I have just been working with a widget in the last two weeks and I have just found this unanswered question of mine I decided to solve it. I hope it helps others.
The AppWidgetProvider should look like this:
public class MyWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
private PendingIntent service = null;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final Calendar TIME = Calendar.getInstance();
TIME.set(Calendar.MINUTE, 0);
TIME.set(Calendar.SECOND, 0);
TIME.set(Calendar.MILLISECOND, 0);
final Intent i = new Intent(context, MyService.class);
if (service == null)
{
service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
}
m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), 1000 * 1, service);
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (service != null)
{
m.cancel(service);
}
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
}
The Service:
public class MyService extends Service
{
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
buildUpdate();
return super.onStartCommand(intent, flags, startId);
}
private void buildUpdate()
{
String lastUpdated = DateFormat.format("hh:mm:ss", new Date()).toString();
RemoteViews view = new RemoteViews(getPackageName(), R.layout.widget_layout);
view.setTextViewText(R.id.btn_widget, lastUpdated);
ComponentName thisWidget = new ComponentName(this, MyWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, view);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
Also, register the provider and the Service in the Manifest:
<receiver android:name="MyWidget" android:label="Tutorial_Widget 1x1">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.something.MyWidget.ACTION_WIDGET_RECEIVER"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_info"/>
</receiver>
<service android:enabled="true" android:name=".MyService" />
ALARM_SERVICE is a static field of the Context class. So type Context.ALARM_SERVICE or use a static import.
Remember that when you set updatePeriodMillis attribute value it's not guaranteed for your onUpdate method to be called with that period exactly.

Categories

Resources