It’s been a long time since I’ve had a chance to play with electronics.
I guess that’s what happens when you spend your time leaving your software development manager role at Linden Lab to set up a new software development company focusing on scalable reliable large scale software at Singing Horse Studio
Anyway, I finally got round to assembling an Ardweeny. It’s a great little device. It’s an Arduino clone that piggy backs off of the ATMega328 chip and is fully breadboard compatible.
I’ve built a few projects with the Arduino, but every time I then have to re-code or re-jig the hardware replacing the “bulky” arduino kit. Now, I can breadboard a prototype with the Ardweeny, and then simply use an ATMega328 with Arduino bootloader and my sketch. It means my prototypes turn into full blown projects more quickly. Win!

You can get the Ardweeny from Solarbotics for less than $10, though remember that you’ll need an FTDI breakout board to load up your code from your computer via USB, unless you already own an Arduino in which case you can carefully remove your current IC and replace it with your Ardweeny. Hrm. I’d rather spend the extra few quid on a no-nonsense solution.
Incidentally, if you have a quick search on Instructables, you’ll see a great intro on how to put an Ardweeny together, as well as ways in which you can pimp it up!
Anyway, now that I’ve assembled my Ardweeny, I can get on with my next secret electronics project for work …
It’s been a long time, but hey, you know what work’s like — yeah, I’ve been busy busy busy. It’s about time I got back to some play time, eh?
Anyway, I wanted to demonstrate some of the new dialog features in ASE (Android Scripting Environment), and at the time of writing this is from ase_r25.apk release.
I was pondering what to build, and then thought of a simple news reader, something that you can modify to view any RSS feed, but initially to demonstrate it with BBC News.
Now, one thing to remember about coding in Python with ASE is that it’s still Python. Yeah, stating the obvious, I know, but what that means is you can use all those Python modules that are already out there. Ok, there’s some restrictions based on whether the modules call underlying C code, and if so you need to do some cross-compiling of your own. But other than that, if you have a pure Python module, you can include it in your code very easily.
Now, there’s a nice module called feedparser which is great for parsing RSS and Atom feeds. All you have to do to use it within your ASE Python script is to copy the feedparser.py to your ASE extras directory on your Android, e.g. /sdcard/ase/extras/python/feedparser.py
Once the file is there, you can reference it just like any other Python module with a simple import.
import feedparser
There’s some great examples on the feedparser.org site, so I won’t repeat those here. Instead I’ll dive straight into the code, and I’ll pull out interesting sections afterwards.
The BBC News site has an RSS feed that anyone can freely subscribe to, and as with the BBC’s usual excellent service they cover everything from World news, politics, sport, entertainment. You name it, they’ll have it covered. Of course, coming from the UK, I’m more interested in UK news, so that’s what I’ll be looking at in this code example.
The main RSS URL for the UK news is http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml and so that’s what we’ll use for our example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | """ Google Android Python Development example, using the Android Scripting Language (ASE). This example uses dialog alerts and dialog lists, plus how to use an external python module to read an RSS feed Author: Howard Sandford, July 2010 Released under CC BY-SA-NC 3.0 """ import android import feedparser import time droid = android.Android() def show_news_list(): """ @brief show a dialog on the screen with a list of news items @return int index of the selected news item """ droid.dialogCreateAlert(channel_title, ' ') droid.dialogSetItems(news_items) droid.dialogShow() response = droid.dialogGetResponse().result selected_news_index = response['item'] return selected_news_index def show_news_summary(selected_news_index): """ @brief Show a dialog with a brief synopsis of a particular news item @param[in] selected_news_index int The news index item to show @return string Representation of the button that was pressed e.g. "neutral", "positive", or "negative" """ droid.dialogCreateAlert( news_items[selected_news_index], news_summaries[selected_news_index] ) droid.dialogSetPositiveButtonText('Read News') droid.dialogSetNegativeButtonText('Back') droid.dialogSetNeutralButtonText('Done') droid.dialogShow() response = droid.dialogGetResponse().result return response['which'] def remove_news_item(selected_news_index): """ @brief Remove a news item from our data structures @param[in] selected_news_index int The news item index to remove """ # once we've shown one news item, # we don't need to see it again news_items.remove(news_items[selected_news_index]) news_summaries.remove(news_summaries[selected_news_index]) news_urls.remove(news_urls[selected_news_index]) # Let the user know that something is happening droid.dialogCreateSpinnerProgress('Please wait', 'Downloading news items from the BBC news website ...', 100) droid.dialogShow() # set up the feedparser to look at the BBC news site news_feed = feedparser.parse("http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml") # initialise our data structures, ready for the parsed RSS feed news_items = [] news_urls = [] news_summaries = [] show_news_items = True # grab the title of the feed channel_title = news_feed.feed.title # sort through our data for news_item in news_feed.entries: news_items.append(news_item.title) news_urls.append(news_item.id) news_summaries.append(news_item.summary) # we're done with the long process ... so stop the spinner droid.dialogDismiss() while (show_news_items): try: selected_news_index = show_news_list() except KeyError: # the user pressed the back button on the Android show_news_items = False # and clear any selected item selected_news_index = None try: button_pressed = show_news_summary(selected_news_index) if button_pressed == 'positive': # open up the URL (in the browser) # making sure we open the mobile version of the news rather than the hi bandwidth version droid.view(news_urls[selected_news_index].replace('/hi/', '/mobile/')) # we don't want to see this news item again, so remove it from the list remove_news_item(selected_news_index) # here's the hack! time.sleep(30) # and kill the browser so we return to our script droid.forceStopPackage('com.android.browser') elif button_pressed == 'negative': # just remove the news item, as we're done with it remove_news_item(selected_news_index) elif button_pressed == 'neutral': show_news_items = False except KeyError: # the user pressed the back button on the Android remove_news_item(selected_news_index) except NameError: # raised because of the previous back button press # so we just want to stop - show_news_items is already false pass except TypeError: # raised because of user pressed back twice # so we just want to stop - show_news_items is already false pass # and finish droid.exit() |
So let’s start dissecting this code a little more.
The main part of the script starts on line #61
61 62 63 64 65 66 | # Let the user know that something is happening droid.dialogCreateSpinnerProgress('Please wait', 'Downloading news items from the BBC news website ...', 100) droid.dialogShow() # set up the feedparser to look at the BBC news site news_feed = feedparser.parse("http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml") |
We’ve seen this before. It’s simply a spinner that shows the user that some long process is happening, and in this case we’re showing this whilst we download the BBC news feed, which is easy to do thanks to the feedparser module.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | # initialise our data structures, ready for the parsed RSS feed news_items = [] news_urls = [] news_summaries = [] show_news_items = True # grab the title of the feed channel_title = news_feed.feed.title # sort through our data for news_item in news_feed.entries: news_items.append(news_item.title) news_urls.append(news_item.id) news_summaries.append(news_item.summary) # we're done with the long process ... so stop the spinner droid.dialogDismiss() |
We then initialise our python list data structures where we store the parsed news stories, and then run through each item in turn, assigning titles, urls and summaries of each news item.
Once we’ve got all the data we need, we dismiss the spinner dialog from the screen.
Now we get to the fun stuff from ASE. We create a dialog alert which contains a list of items, in our case the titles of news items given to us by parsing the RSS feed.
20 21 22 | droid.dialogCreateAlert(channel_title, ' ') droid.dialogSetItems(news_items) droid.dialogShow() |
The dialog simply takes the Python list, news_items, and displays each element as an item in the ASE list.
We determine which item the user selects from the droid.dialogGetResponse() call.
24 25 26 | response = droid.dialogGetResponse().result selected_news_index = response['item'] return selected_news_index |
It’s possible that the selection fails with a KeyError, i.e. ‘item’ is not in the list. This can happen if the user presses the “back” button on the Android, so we catch this in a try/except. Obviously, if the user has pressed back, we make sure we don’t show any items and remove any selection.
85 86 87 88 89 90 91 92 | try: selected_news_index = show_news_list() except KeyError: # the user pressed the back button on the Android show_news_items = False # and clear any selected item selected_news_index = None |
Ok, so then, with a news item selected, we want to show the details of that news item to the user. Well, when I say details, I mean a summary of the news story. The ASE dialog calls allow us to set up to three buttons. In our example we’ve used the “positive” button to open up a web-browser to see the full version of the news, the “negative” button to go back to the list of news items, and the “neutral” button “quits” out of the application.
34 35 36 37 38 39 40 41 42 43 44 45 | droid.dialogCreateAlert( news_items[selected_news_index], news_summaries[selected_news_index] ) droid.dialogSetPositiveButtonText('Read News') droid.dialogSetNegativeButtonText('Back') droid.dialogSetNeutralButtonText('Done') droid.dialogShow() response = droid.dialogGetResponse().result return response['which'] |
Now, here comes the hack. When we open up the web-browser to see the full story, it would be great to wait in the background for when the web-browser finishes and then we take over from where we left off. However, ASE doesn’t yet (as of ase_r25.apk) provide the startActivityForResult call which allows us to open another activity and wait for a result. [Ed: since writing, ASE has been renamed Scripting Layer for Android - SL4A - and the latest version sl4a_r2.apk implements the startActivityForResult call] As such, we set up a timer which kills the web-browser after 30 seconds. This is fine for me, and you might want to adjust this timeout to suit your own purposes. [Ed: either that, or rewrite it using startActivityForResult!]
96 97 98 99 100 101 102 103 104 105 106 107 108 | if button_pressed == 'positive': # open up the URL (in the browser) # making sure we open the mobile version of the news rather than the hi bandwidth version droid.view(news_urls[selected_news_index].replace('/hi/', '/mobile/')) # we don't want to see this news item again, so remove it from the list remove_news_item(selected_news_index) # here's the hack! time.sleep(30) # and kill the browser so we return to our script droid.forceStopPackage('com.android.browser') |
Incidentally, when we open the webpage with the full news item, we simply change “/hi/” to “/mobile/” in the URL because the BBC News website provides both a hi definition and a mobile version of its news items. Nice.
So there we have it, an RSS news reader on the Android using the ASE Android Scripting Environment in Python.
Next time I’ll make sure I download the latest SL4A and work from that release.
[All files are released under Creative Commons BY-SA-NC 3.0]