Posts tagged ‘Timer’

Android Beer timer Widget

A friend of mine said he wanted a beer app for the Android, really what’s that ? It goes something like this, a beer glass on your Android desktop. The beer glass fills up from 9am to 5pm, once it’s full, well then it’s time to stop working and go out for a beer. On the weekends the glass is always full of course. This would have to be a widget on the desktop so the image / icon can be changed on a timer through the day. Since I hadn’t written an Android widget before, I told my friend, no problem I will write it for you.

Lets declare the widget in the manifest, the service and the alarm receiver as well.

<receiver android:name=“.FxBeerWidget” android:label=“Beer time widget”>
  <intent-filter>
    <action android:name=“android.appwidget.action.APPWIDGET_UPDATE” />
  </intent-filter>
  <meta-data android:name=“android.appwidget.provider” android:resource=“@xml/beerwidgetlayout” />
</receiver>
<service android:name=“.CxUpdateWidgetService” />
<receiver android:name=“.CxBeerAlarmReceiver” />

Then in the AppWidgetProvider we use AlarmManager to update our receiver

// Setup receiver that will call the widgetService     
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent2 =  PendingIntent.getBroadcast(context, 0,
      new Intent(context, CxBeerAlarmReceiver.class),  PendingIntent.FLAG_CANCEL_CURRENT);
// Use inexact repeating which is easier on battery (system can phase events and not wake at exact times)
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 500, (60*1000), pendingIntent2);

Note that you have to be mindful of the resources you are using and use a long interval. If the person using the phone is playing a game for example when the timer goes off. You do not want to take much resources in order for his game to keep playing smoothly. In our case it’s a simple check and a quick update of a icon if needed.

The CxBeerAlarmReceiver is a BroadcastReceiver which when woken up will start the CxUpdateWidgetService which is a IntentService. The CxUpdateWidgetService will take care of updating the widgets.

public static void updateAllWidgets(Context context)
{
  //
  final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
  final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, FxBeerWidget.class));

  // Remote view for the widget
  RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.beerwidget );
       
  // Setup the beer main Activity as Intent
  Intent beerIntent = new Intent();
  beerIntent.setClass( context, FxMain.class);
  beerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  // Setup pending intent, when widget clicked show main screen
  PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, beerIntent, 0);
  views.setOnClickPendingIntent(R.id.Widget, pendingIntent);
        
  // Time status
  int iCurrentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
  // Format it in clock like format, leading zero
  views.setTextViewText( R.id.lbStatus, CxUtil.getTimeString() );
       
  // Update image only if needed
  int plusNum = whichIcon( iCurrentHour);
  CxLog.d( CxLog.TOKEN, “updating beer image, currhour=” + iCurrentHour + “, plusNum=” + plusNum   );
       
  // Set the current image
  views.setImageViewResource( R.id.widgetImage, R.drawable.beer72_0  + plusNum );
       
  // Associate the update views – Loop all id’s
  for(int i=0; i<appWidgetIds.length; ++i)
     AppWidgetManager.getInstance(context).updateAppWidget( appWidgetIds[i], views );
}

Note that the user can have more than more widget running, there could be one on each desktop, etc. The for loop will take care of that and update all of the widgets. Another cotcha is that you will have to set the click intent for the widget each time the update function is called. Otherwise it will get disconnected from the widget and clicking the widget will not open the FxMain screen.

Here is the Widget if you like to download and install on your Android – BeerTimeWidget

Here is how it looks in action.

Android GUI thread timer sample

I was looking for a simple Android timer to do updates on ticks in one of the views I’m playing with. The problem with spinning off another thread brings up two issues, one is that it takes more resources and the second one is that you will have to switch back over to the UI thread to update the screen. Then I came across a much better solution in the SDK documentation click here. I had to read it a couple of times and when I imported it into my app had to figure out some things a long the way. So for your benefit here is a cut down simple version.

In case you didn’t know see how easy it’s to use the built in Log class, the output will be visible in LogCat output. Also note the call Handler.removeCallbacks(mUpdateTimeTask); to free resources.

//
package us.kristjansson.test;
//
import us.kristjansson.test.R;
//
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Window;
//

public class FxFireWorks extends Activity
{
        // Timer
        private Handler mHandler = new Handler();
        //
        private Runnable mUpdateTimeTask = new Runnable()
        {
           public void run()
           {
               // Do something
               Log.d( this.toString(), “Do something !!”);
               // timer
               mHandler.postDelayed(mUpdateTimeTask, ( 2 * 1000)) ;
           }
        };
       
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Hide the title bar
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.fireworks);
   
        // timer
        mHandler.removeCallbacks(mUpdateTimeTask);
        mHandler.postDelayed(mUpdateTimeTask, 100);
    }

    @Override
    public void onStop()
    {
        super.onStop();
       
        // timer
        mHandler.removeCallbacks(mUpdateTimeTask);
    }
   
}