back after a break

It’s kind of gratifying to check the logs and see that people are still ending up at my little blog here even when I’m away having a baby for a month! Hope visitors found something useful.

I’ve had some troubles with DD-WRT since trying it out, just thought I’d note them. The first, major one was that all of the sudden the DHCP server stopped working. It just wouldn’t hand out IPs anymore – existing ones worked fine. I ended up resetting the router and losing configuration over that one. Then one day in the middle of a Skype session I simply lost connectivity. The router was up but I couldn’t ping the gateway for my ISP. I cursed the ISP at first but eventually figured out it wasn’t them, and a quick router reboot actually solved it. But this is disconcerting. Maybe I need a firmware upgrade, haven’t been paying attention.

Demoed WhenDidI at my Android meetup on Wednesday, and folks seemed to think it had good potential and were interested in how it worked. We started talking about the future log analysis capabilities, adding geotags to entries, sharing trackers between multiple people, etc. – stuff that’s mostly way in the future unfortunately, but interesting.

adding alarms to my android app

Well, the time had to come. WhenDidI logs reasonably well, so how about reminding the user when they haven’t done something in a while? Time to implement alarms.

It seems Android supplies an AlarmManager that can be used for this purpose. Alarms are passed to it as PendingIntent objects to be invoked at the time the alarm goes off. Alarms are only retained until the phone reboots – so I’ll have to take a page from the Alarms app that comes with the system and also set an alarm at system boot; when I get to that. For now, let’s just get this working at all!

There’s a fairly coherent tutorial to get started with. There’s the source code to Alarms within the Android source. And there are also some simple examples in the ApiDemos example supplied with the SDK. So this shouldn’t be too bad.

First, I’ll create an AlarmReceiver class that subclasses BroadcastReceiver. This will be used to create a notification and reset the alarm to the next time one’s due (if any) – this way we’ll only need one alarm set at a time, which should keep things simple. And in the interests of starting off simple, AlarmReceiver will just show a toast for now, as proof of concept. Alarm will need an entry in AndroidManifest.xml as a receiver. The one in ApiDemos looks like this:
        <receiver android:name=”.app.OneShotAlarm” android:process=”:remote” />
I haven’t noticed that android:process=”:remote” bit before, so I hope it doesn’t mind being cargo-culted to my app :-)

So, I created a quick test alarm functionality that I can use from any tracker to create an alarm specific to that tracker firing in five seconds. It works great – of course, for the first test all the alarm does is pop up a toast saying it fired. Let’s make it a little more interesting – have it fire a notification specific to the tracker, so I can see what it looks like when we have multiple alarms go off with multiple notifications. I add an extra to the intent for the alarm which includes the trackerId. The alarm receiver can read the ID and bring up the tracker from the database, and create a different notification based on that.

Here I notice a problem: sometimes I seem to be getting a previous intent instead of the one I sent (because the trackerId received doesn’t change when I send from a different tracker). Is the AlarmManager caching intents? I can’t find out much about this subject on the web. Perhaps it would help to cancel any previous alarms before creating a new one? That doesn’t seem to make a difference. Hmm, searching on that brings up a posting about the same problem.

[Returning to this after WEEKS – having a baby will really mess up your schedule!]

Turns out I had to overcome two problems. First, the alarm system will reuse previous PendingIntents according to how the alarm flags are set. I actually don’t remember exactly what this does now, will have to research again, but I ended up creating the PendingIntent like this:

        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context, AlarmManager.RTC_WAKEUP, intent,
               
// keeps from re-using the previous intent:
                PendingIntent.FLAG_CANCEL_CURRENT
        );

Once the alarm intent was successfully invoked, I had a second problem with notifications reusing the PendingIntent given to them (I wanted to have a different notification for each tracker that has an alarm). To get around this I added an otherwise useless Data entry on the wrapped Intent to distinguish them (Extras are apparently not considered):

        Intent showTrackerIntent = new Intent(context, TrackerDetail.class)
                                            .putExtra(C.db_ID, trackerId)
                // the data keeps the PendingIntents distinguishable:
                                            .setData(Uri.parse(“tracker://”+trackerId));

With this I could set different alarms that created different notifications for the same Activity with different inputs.