Get off my lawn.

Tuesday, November 25, 2008

Android: Ring Control

I've been playing around with a little Android application for a few weeks now, while taking occasional breaks from working on other, more "real" Android projects.

It's called Ring Control, and it puts your phone on vibrate (or silent, depending on your preferences) mode if you put it upside-down in your pocket, or lay it face-down on a table (again, depending on your preferences).

The idea is pretty simple, and the implementation was too, at least initially. It's easy: Get a reference to the SensorManager, tell it you want to know about orientation changes, calculate the degrees of pitch in the orientation, and set the ringer mode depending on the pitch value. I gave it about 50 degrees of latitude (or is that longitude) in either direction to keep it from being too touchy about device orientation.

The app consists mainly of two parts: The UI screen (for starting and stopping Ring Control and setting preferences), and the background service that actually controls the ringer. Probably the smallest Android app I've written since that "Hello World" app back in '08.

As I said, the idea is simple, but it turns out to be kind of a tricky problem. The "hard" part (well, not hard, now that I know what to do) is making it work like you would expect it to work.

As it happens, Android is pretty conservative about things like memory and battery power, and isn't keen on letting background services just sit there and nibble on the CPU while doing nothing else. ("nothing else" in this case defined as "not having any clients asking them for things"). So after about 1/2 hour, my background service would just stop, with no notifications or anything else. Since the whole point of Ring Control is to turn your ringer to vibrate and keep the phone quiet, it doesn't seem too useful to have it just stop suddenly, letting your phone spew out a loud "riiiiinnng..." (or other obnoxious ringtone) while you're in a funeral or something and need for it to be quiet.

I started reading about the various ways to tackle the problem, and read about "wake locks" and other things that you can use to poke at the phone's CPU to keep it alive so your service will work. That seemed like a good way to eat up batteries, and there was still nothing in the idea that would seem to actually ensure that the service kept working.

So, no.

As it turns out, there is an accepted way to keep a background service running, and that is to use the AlarmManager system service. Essentially, you schedule a repeating alarm, say, every 5-10 minutes, and the "alarm" is an "Intent" (Android-speak for "thing that runs something") telling the AlarmManager to start your service (or activity or broadcast message). It seems like kind of a goofy way to do it, really. I read about it, and thought "Seriously? I have the AlarmManager start me at regular intervals?" Whatever works, I guess. In any case, I set it up so the "start" signal just keeps the service running if it's already running, instead of starting another copy.

Having done that, the service now runs as long as it's supposed to, and doesn't poop out spontaneously.

Ring Control turned out to be pretty popular on the Android Market, with a lot of people downloading it and e-mailing me about it and commenting on it in the Android Market. (Best comment so far: "I give it 3 stars. I wish it would show movie times." Huh?) One feature people asked for was the ability to run it automatically when the phone boots.

Like a lot of things with Android, I seem to look in the wrong place initially for information about how to do something. I started thinking about some kind of "startup folder" metaphor somewhere, found nothing.

The way to get a service or application to run at startup is to create a "BroadcastReceiver", a class that receives a broadcast notification from the OS when something happens, and assign to it a key. There are keys for all kinds of events (e.g. incoming call, SMS message, blah blah blah). The one I was interested in was "android.intent.action.BOOT_COMPLETED." This notification gets sent to applications that want to know about it, even if they're not running. Android pulls a BroadcastReceiver out of bed and calls its onReceive() method, passing it some info about what's starting it. In my case, I just start the Ring Control service in my BroadcastReceiver, and that's it.

Now that that's done, I've got some other ideas on how to use the orientation sensor for something interesting.

Overall, I kind of enjoy walking around with a device with all this stuff on it. It has a compass, orientation sensors, GPS, internet access, audio and video playback (makes a good iPod), functions as a mirror when the screen's turned off, makes a good hand warmer if you surf the web a lot, is heavy and chunky enough to ward off an attacker, and has changed my life in general: I no longer have time to sit in meetings getting annoyed at people playing with their fancy phones. I'm too busy playing with my phone.


  • At 11:47 AM , Blogger Bitner said...

    You released any new versions?

  • At 11:56 AM , Blogger Bitner said...

    Any chance you could either add settings to determine the angles that both put the phone in "upside down" mode and return the phone to normal. When putting the phone in your pocket upside down and then sitting, the phone goes back to ring mode. As putting the phone upside down in my pocket is the slickest move to make sure the phone is quiet when going into a meeting, it would be nice to err on the side of having the phone go to vibrate. Sweet & Simple app!

  • At 10:16 AM , Blogger Kelly said...

    Bitner, I like the calibration idea. I'll see what I can do. I'll even let you have the upgraded version for free when I get it done. :-)

  • At 6:28 PM , Blogger Calvin said...

    Keep up the good work man! People like you help me love my G1 even more!

  • At 11:54 AM , Blogger Michael said...

    I love it. This has totally eased my woes of losing "holster detection" that is standard on the Blackberry, and taken it a step further. I can bring my phone to a meeting, and place it on silent just by turning it over!

  • At 2:24 PM , Blogger yipcanjo said...

    Hey, there! I'm wondering if you could build in a *very handy* feature to the Ring Control app? (Great APP, by the way).

    Anyhow, could you have a setting where RingControl sets the phone to "silent" when you are in a meeting -- based upon your "calendar", of course. This is a setting that Windows Mobile has had for years, but few (if any) others offer it. It's really nice to have. Another option, of course, is to have a "timed silent" mode where you choose "Silence until 2PM" or "Silence for the next 1 hour", and then it comes out of silent mode automatically. My old Nokia had that feature, which was nice.

    Thoughts on that stuff? :)



  • At 10:00 AM , Blogger Kelly said...

    That's actually a cool idea. I hadn't thought of turning the ringer to vibrate based on a calendar. So, does the WM version silence your phone for any event in your calendar (e.g. "Go to the store and buy eggs"), or only items meeting certain criteria? (Being Windows Mobile, I'm guessing it probably silences the ringer by springing a huge memory leak, draining the battery, things of that nature? :-)

    I really like the "timed silence" mode. That wouldn't be hard to implement, and I can see situations where that might be really handy. I'll put that on the list of things to look into.

  • At 4:37 PM , Blogger yipcanjo said...

    Thanks for looking into that! I'd be happy to beta test the added Ring Control functionality, if you need help with that. Just let me know!

    yipcanjo "at" yahoo "dot" com

    In the "automatic" profile mode, Windows Mobile would put the phone into 'silent' for all meetings that showed you as "Busy", which is more or less the default. That said, I could make a note to myself in my calendar -- say "Pick Up The Drycleaning" -- and select 'free' instead of 'busy'. For those items, the ringer would stay as is.

    The timed silent mode was also *VERY* handy, and was great for heading to the movies, etc., where it was easy to forget to un-silent your phone!

    Thanks again!


  • At 9:45 PM , Blogger Kelly said...

    Cool idea... A Google Calendar entry has a "busy/available" status member like an Outlook meeting does, I bet I could use that. I'll definitely look into the idea.


  • At 2:53 PM , Blogger Fred said...

    One thing I hate about the G1 is that I'm constantly missing events because of inadvertent lowering of the ringer volume. If you could add an option to this program (which I already have and like) to always keep the ringer volume at it's max, I think this would be a great feature.

    Fred Putnam,

  • At 2:18 AM , Blogger David said...

    I also would love to be able to fix the volume on max. My biggest prob lem is not everyone hearing my ringtone but rather not even me hearing it!

  • At 10:37 AM , Blogger Kelly said...

    Not a bad idea. Will do!

  • At 9:07 AM , Blogger Gwen Morse said...

    This post immediately put the thought into my head -- you know what Android phones "need"???


    One process that uses minimal power that stays running. It can be configured to start other processes as defined in the configuration file. It could have a plugin system so other devs could tie their programs into it.

    That way, instead of 10 processes all fighting to stay active and each do one thing every 30 minutes, you can have one process staying active and doing 10 things every 30 minutes. It's more power efficient.

  • At 5:44 PM , Blogger Ayelis said...

    How about a feature/app that silences the ringer when the camera/cameras turn dark? That would solve the "put it in your pocket" problem... Unless you were wearing thin slacks!

  • At 8:23 AM , Blogger Kelly said...


    I'm actually working on a long-overdue update to RingControl. I'm putting out a new app in the next couple of weeks, then I'll resume work on RingControl. The "silent in the dark" feature is one thing it will include.



Post a Comment

Subscribe to Post Comments [Atom]

<< Home