So you’re out and about. Having fun with your G1 (or other android phone) you’ve taken some pictures and you decide that right now you want to take one of thoe pictures and use it as the wallpaper on your laptop.
Well, you can e-mail it to yourself. Or you could post it on your picasaweb account, or well “neither of those really interest me.” you say? Well, if you had been thinking this morning when you left the house you probably would have packed along a usb cable to like up your computer to your phone, but if you are like most other people, you’ve decided that that really isn’t something you want to carry today, and you can always take care of that tonight. Or perhaps you have one of those micro sd-card to usb adapters on your keychain? No. Bummer.
Wouldn’t it be great if you could just fire up a small web server that points at your photo album? Point your web browser on your laptop at it and download the picture you want?
Actually if you have installed the Android Scripting Engine (ASE) you can.
ASE includes interpreters for Bean Shell, (a Java based shell scripting language) Lau, (found in some Linux distributions) Python, (pretty much everywhere these days) bash, (also pretty common) and more to come. Now I’ll be one of the first to admit that all of these are probably anything but feature complete. If you are thinking ‘Hey I’m going to write a push button app with custom lables using tk!’ sorry, tk is not included. However if you are interested in talking to the network, get information from features of the phone such as the location via gps, or the orientation of the phone (face up/down, on the side, etc) you can do some pretty interesting things. In time the screen may be dot addressable, and you may be able to do gui stuff, but it’s not currently being planned.
I’ve not done anything with Bean Shell, and not all that much with Lau. Both have fans and from what I have seen are likely to be used fairly heavily. However I do like to dabble with Python, so you’ll find most of my blog postings here relating to ASE are going to focus on Python.
But we’ve got that photo to get to the laptop. Right? Lets work on that.
Perhaps you haven’t installed ASE but that might work for you? Poing your browser at http://code.google.com/p/android-scripting/ and you should see a QRcode bar code on the page. If you have the BarcodeScanner application istalled fire it up on your phone, point the camera at the bar code on the screen, and you’ll end up in the application installer looking at the install helper for ASE.There are additional instructions that you will want to follow to add in the actual python interpreter as well as some sample scripts.
Now since the 0.10 alpha release of ASE, not only can you download the application itself via qrcodes, but you can enter small scripts that way as well. Launch ASE, hit ‘Menu’, pick ‘Add Script’ and select ‘Scan Barcode.’ The barcode reader will come up again, point it at the following qrcode based on the script posted by Mrflakey to the ASE-Scripting mail list:
You’ll actually be able to run it immediately, however it’s always a good idea to take a look at the code. It should look something like this:
from os import chdir
If all you wan to do is browse your pictures, then you will probably want to change the chdir line to read something a bit more like “chdir(‘/sdcard/dcim/Camera’)”
Now there is only one ‘issue’ left. “How do I get to the server?” Well, to tell the truth, that has been the real reason for this posting.
The first time I used the script and downloaded content from my phone, the way I found the IP address for my phone was to open a terminal session on my dhcp server and looked for the message indicating that my phone had just been assigned an address via dhcp. That’s all well and good for when I am at home, but if you are out on the road, you probably don’t have that ‘advantage.’ Last I checked T-Mobile wasn’t exactly giving me access to their system at a level where I could get the IP address that my phone was using from their servers. Not really expecting that any time soon either.
If you dig around, you can find the ip address, but wouldn’t it be nice if you could present it as part of that httpd.py script? Actually, you can. But it’s a bit more work.
The Android platform allows you to see the current IP addresses on your phone by using the command netcfg at the command prompt. You already know about 127.0.0.1. If you don’t a brief note, don’t bother to try to download anything from your phone by pointing your web browser on your laptop at 127.0.0.1:8000, it won’t work.
There are 6 different ‘interfaces’ that may have an IP address on your phone.:
lo UP 127.0.0.1 255.0.0.0 0x00000049
dummy0 DOWN 0.0.0.0 0.0.0.0 0x00000082
rmnet0 DOWN 126.96.36.199 255.255.255.252 0x00001002
rmnet1 DOWN 0.0.0.0 0.0.0.0 0x00001002
rmnet2 DOWN 0.0.0.0 0.0.0.0 0x00001002
tiwlan0 UP 192.168.0.2 255.255.255.0 0x00001043
The above is something ‘like’ what is deisplayed on my phone. Presumption being that I’m at an internet cafe with wifi access and I’ve gotten both the cell phone and my laptop on the wifi, I would simply point my web browser at http://188.8.131.52:8000/ after launching httpd.py on my phone and I would be up and running. (caveat the internet cafe or wifi provider has to have enabled the ability of wirelessly connected customers to communicate directly with each other.)
If rmnet0 was UP rather than DOWN, and unless you have a rooted phone or a more recent phone than the G1 you will find tiwlan0 will thus be DOWN, and the internet cafe allows internet browsing, I could point my browser at http://184.108.40.206:8000/ and I would be able to browse the content as well.
On the other hand that’s a couple of extra steps. First you get the IP address of your phone, then you launch the server, then you hope you remember what the IP address was so you can point your laptop at the address. Annoying right?
Well we’re going to add two bits of content to the httpd.py script in a bit, one imports the library we are going to write, the other displays what our IP address is. But in order todo that we need to add a script to the phone. Let’s call the script ‘netip.py’.It’s going to have to do a few things.
- Get the list of ip addresses and interfaces from the phone. We’ll call the program netcfg to get that.
- ignore the ‘lo’ interface.
- return the interface and ip address of the UP interface(s) or
- return the ip address of the UP interface(s)
- be able to show that the library functions.
There are some contitions that over the long term you will want to address as well, but I’m not going to for this script. What do you do when you are in a place without cell service or wifi? Currently the script does not address that.
Ok, we are going to import the following libraries.
import os, sys, android, string, time
os and sys allow us to talk to the operating system, android because the script will want to be able to show us things like what IP address we got using the makeToast() android call. The time librarry we are using to allow us to display two or more results with a delay between them. We are going to be using the string library to manipulate the output of the system call to netcfg. but we better get that first:
def colint(): status =  a = os.popen('netcfg','r') while 1: line = a.readlines() if line: status.append(line) else: return status break return status
Ok, status is set to an empty list. the os.popen() call tells the phone to run the netcfg program and we are going to ‘read’ the results from the system call. Start a while loop. ’1′ is always ‘true’ so we’ll use that for the test. In the loop we assign ‘line’ to the result of doing a readline on a. Now if the result of that is true, i.e. we got something other then an end of file mark we append the content of line as a new list entry to status. if we don’t get anything from the readline we return the status and break out of the while loop. The final ‘return status’ is not necessarily required, but I would rather have the function return a blank status if the while fails for some reason. Up to you.
Of cours we’re really only interesetd in entries that have a status fo UP right? so let’s get rid of the rest.
status = 
a = 0
while a < len(work):
if "UP" in work[a]:
a += 1
This time we call the function with a list and presumably in that list there are some entries that have the string ‘UP’ in them.
And of course we are not interested in the ‘lo’ interface so we’ll clean that out:
# given a list of strings (with embeded '\n') break as needed, return
# list of strings w/o 'lo' in them)
status = 
a = 0
while a < len(work):
if "lo" in work[a]:
a += 1
a += 1
if len(status) == 1:
rets = status
statusl = rets.split()
status = statusl
If there is only one interface with an up status (other than lo) we also break up the string and only return the IP address. That’s done by calling the ‘split’ string function and assigning the resulting list to ‘status1′ then status will get the third entry (first is at 0 and is the interface name, ‘lo’, ‘tiwlan0′, etc. the second at 1 will be the up/down state.) Otherwise if it looks like there are multiple interfaces up besides the lo interface we will return a list of the entire strings.
The rest of this can either be considered ‘test’ code, or you can call the next to functions directly. The labels are a bit misleading. At an early stage in development these functions actually displayed the IP addresses. I decided later on that I really just wanted them to return them to the calling function. At some point you may be interested in binding to the up interface. The two functions are displayUp() and displayNoLo() which returns all up interfaces, or all but the lo interface. You will probably be most interested in the displayNoLo() function, but who knows.
nets = colint()
nets = upips(nets)
nets = colint()
nets = upips(nets)
nets = nolo(nets)
Now then it’s always a good idea to include in a script some code to run to make sure that it all works. Since each of the two functions above will call the earlier functions we really only need to call those two functions. However we are going to make use of the makeToast() android call so we need ot initialize android. Also makeToast() displays a popup for about 2 seconds so let’s give it a chance to complete between calls to it, and exiting the program.
if __name__ == '__main__':
droid = android.Android()
The ‘if’ conditional at the top is the first line that will be run if you execute the program directly. I personally recommend including all of this. At the very least you will be able to look at how various functions can be called later on.
Ok, if you have a clean camera lens, you may be able to load the entire program via qrcode. Again launch ASE, ‘Add Script’ from the Menu button, and ‘From Barcode’ Once that is up, point the camer at the screen and see if it will read the following bar code:
And a modified httpd that uses the code is at:
If you would rather, the full text of the scripts are at http://www.beresourceful.net/~rusty/android/netip.py and http://www.beresourceful.net/~rusty/android/httpd2.py
Now if you have an available network connection and access to the internet, you should never be unable to get documents off your sdcard for your Android based cell phone.
Once you run a program that imports a python library you will end up with both a .py and a .pyc of that file in your list of scripts. The .pyc edition can be run the same as the .py, but is a ‘compiled’ version of the program that speeds up execution of library system calls in the future.
You may wish to create a ‘shared’ folder on your sdcard that you point httpd2.py at instead of pointing at the entire card. Or as noted earlier just point at your /sdcard/dcim/Camera/ folder for images only. The reason for that is that there are no restrictions on who can download content from your phone while httpd2.py is running, except for the limitation that it is in a subdirectory of the current directory. You may also want to change the print out to read more like ‘print “connect to http://”, netip.displayNoLo(), “:8000/”‘ to give you a reminder that it is on port 8000 and that you use a web browser. If 8000 is entirely too likely for someone to connect to, you can point SimpleHTTPServer.test() at a different port. I’ll leave learning how to do that to you. If you don’t have a rooted phone, you can’t point at anything below 1023, but you could point it at 58080 if that works better for your mental image.
Enjoy, and play around.