I go out for beer and supper with my pal, Jim Flanagan, and use what I've learned to explain why his attempt to put a random Java app onto his girlfriend's Android phone failed.
Teaching someone else what I know is a good way to review and uncover what I don't really understand well enough to explain.
"You thought I wanted to put a Java app onto Marcia's phone?" Jim has no idea what I'm talking about.
He has, he explains, read that he can use SL4A and JRuby to run Ruby programs on Android devices. Marcia has an Android phone, and he knows Ruby. A natural match.
He doesn't understand what SL4A is or why it would need JRuby, or, for that matter, even what Sinatra is, which is also required, "... But maybe you do."
Well, no, but at least this time I've paid close enough attention to know what the question is. I've heard of JRuby and Sinatra. SL4A? Nope, but it's "Scripting Layer For Android."
Jim says that the place he found this information has an example -- only a few lines of code -- that turn an Android phone into a spy camera. He could install it on Marcia's camera and spy on her from his laptop. Of course, he could just go over and see her whenever he wants, but okay, we're guys, so spy camera is enough to make this compelling.
After supper, we head back over to Caffe Sole, where they now have a band playing live, bad, jazz.
He shows me the code and yes, just a handful of lines of Ruby, running on the phone, are claimed to tell the camera to take a picture, and then serve the picture up over the internet, on Webrick's port 4567. (Webrick is Ruby's built-in, light-weight web server).
Browsing to that port at the phone's IP address, from any browser, should show the picture. Somehow, the code also lets the laptop instruct the phone when to take pictures.
Only one way to find out.
I google for SL4A from my phone, and install it from Google Code. SL4A, in turn, lets me install JRuby. The code samples that come with that installation work indifferently. The "Hello, World" app works okay, the app to toggle airplane mode seems to work once, but we can't repeat that.
But who cares about airplane mode if we can have a Spy Camera?
I connect the phone to his Mac with a USB cable, and the phone asks me if I want to allow him to "Download files via USB."
Well, sure.
After some trial and error, we download the spy-camera app and and associated directory, uh, folder, I poke around, turn on the phone's WiFi, and figure out the phone's IP address: 192.168.1.8. Jim browses to it to 192.168.1.8:4567. The phone's camera makes a loud shutter click.
Actually, that's just Android generating a "shutter-click sound" electronically, since the camera shutter is also entirely electronic, but we'll take it. Houston, we have ignition.
After a couple second or two, a picture appears on Jim's browser. It's almost black. The coffee shop is dark and the pictures are darker. We try a few more. I finally realize I'm trying to take a picture with the phone's rear-facing camera, but it doesn't have one.
I turn the phone around.
I try to take a picture of the woman sitting next to Jim. She says, "Why do you want to take my picture?" turns her head away, and puts up her hand. I bet real spies never have this sort of problem.
I go over to the counter, where the light's better, and take a picture of Katie, the barista. It works! We show her on the laptop. It's sideways, but she's still still pleased.
So are we. We leave the coffee shop in triumph.
Thursday, December 27, 2012
The Application Lifecycle and Its Dual
Building an app was fun, so let's look at the next tutorial, on lifecycles. Maybe it'll modify the app I have to help me understand Karim's slide 46.
Slide 46 is the dual of the pyramid graphic, in the tutorial, which shows the states as nodes, with the functions that move between them as edges. Slide 46, in contrast, has the functions as nodes, and the states as edges.
Either way, I need to learn the states and how activities move among them.
Reading through the general description, I look back at my sources and find both of my activities have an OnCreate(), but none of the other functions. I wonder where those are.
Another mystery is the difference among what look like almost identical things, such as Paused and Stopped. "Paused" means "partially obscured," but when does that ever happen? Apps always take up the whole screen, right?
The next step in the tutorial answers that one, right away! A popup, such as a dialogue box, partially obscures, so it pauses the app.
The rest of the tutorial talks in generalities. There are code snippets, but there's no real exercise.
Bummer.
I Can Install Apps Via Email
I'm on a roll now.
If I understand what I've read, I should be able to install apps by emailing them to myself.
I attach the apk to a mail message, install it on my tablet (which asks me if I want to "install an update"), put the icon on the home screen, and take it over to Katie, behind the counter.
"Press this," I say. She presses the clock in the center of the screen.
I bring back the home screen, point to the little, green, Android icon, labelled MyFirstApp, and say, "No, the green thing."
She presses it, the app comes up, she reads it, and asks, "What's a 'string' ?"
Typical demo.
If I understand what I've read, I should be able to install apps by emailing them to myself.
- I disconnect the phone and uninstall the app.
- On my netbook, I attach the .apk file to a gmail message and email it to myself.
- I pick up my phone, go to my Gmail, and there's the message. I click on the attachment.
- The phone asks me if I want to install the .apk. Yes, I do.
- The app installs, I open it. It works!
There's an icon for it in my list of apps. It's really installed.
Oho. This trick should work for any Android device.
I pull out my Nexus 7 tablet. Look ma, no cables.
I know that it will install non-Play apps, because I have some from the Amazon store.
On the tablet, I go to Gmail, the message is still there, in my inbox, albeit read. Again, I click on the attachment. Again, the app installs and works. There's an icon for it in my list of apps, so it's really installed.
Yesterday, Katie, the Caffe Sole barista, pointed at my Beagleboard and said, "What's that? An external hard drive?"
I said, "No, it's an external computer." I showed her the Android GUI, and explained that she was seeing a "Desktop" on a completely separate computer.
"That totally rocks!" she said.
I go back to my app and change the strings (res/values/strings.xml) so that instead of saying, "Enter a string." it says "Enter Katie\'s string." Eclipse explains that I need to escape the single quote.
I also change the second activity, which displays the string I enter after I press the Send button, (To do this, I have to look up how to append to a string in Java, and hope that the code in the second activity is handling multi-line strings, but that makes it a good experiment.)
I can't figure out how to rebuild the .apk, so I go back, use the AVD manager to create and bring up an emulator, and click "Run" to get it onto the emulator. This both verifies that my changes worked, and rebuilds the apk.
I attach the apk to a mail message, install it on my tablet (which asks me if I want to "install an update"), put the icon on the home screen, and take it over to Katie, behind the counter.
"Press this," I say. She presses the clock in the center of the screen.
I bring back the home screen, point to the little, green, Android icon, labelled MyFirstApp, and say, "No, the green thing."
She presses it, the app comes up, she reads it, and asks, "What's a 'string' ?"
Typical demo.
I Pour the App I Built onto My Own, Android Phone
Yesterday, I built an app that runs on my Beagleboard. I should be able to put the same app onto my phone, right? Yes, this is a sidebar, but I have to know.
First step: My computer needs to be able to talk to the phone when I plug it in. It needs to recognize my phone as a legitimate peripheral.
This should just take an addition to my udev rules.
I hunt for the right udev settings for the phone -- a two-and-a-half year old HTC magic. This table reminds me that I can use per-vendor settings, so I add a line to /etc/udev/rules.d/51-android.rules:
Next, I look on my phone to see what version of Android it's running. I remember that when setting up the Eclipse project, I specified a minimum Android version the app would run on. I'd better check what version the phone has.
Menu->Settings->About Phone->Android version, tells me it's running 2.2.3 (Froyo).
Unfortunately, I don't remember what I said at setup (I bet I just took defaults), and it isn't obvious to me how to get back to that page. Googling tells me the information's in AndriodManifest.xml, so I look there and it says
This page tells me that 2.2.3 is SDK API version 8. Whew.
Plugging in the phone and permitting USB debugging (Applications->Development->USB debugging) makes /dev/sdc and /dev/sg2 appear, though nothing's mounted.
I bring up eclipse, pick MyAndroidProject, and press Run. The Choose a running Android device screen pops up and, sure enough, there's htc_t-mobile-mytouch-3g!
Crossing my fingers, I click on OK, and ... there it is. MyFirstApp appears on the phone, and behaves just as it did on the Beagleboard. There's even an icon for it in the list of apps. How cool is that?
First step: My computer needs to be able to talk to the phone when I plug it in. It needs to recognize my phone as a legitimate peripheral.
This should just take an addition to my udev rules.
I hunt for the right udev settings for the phone -- a two-and-a-half year old HTC magic. This table reminds me that I can use per-vendor settings, so I add a line to /etc/udev/rules.d/51-android.rules:
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"and run
sudo udevadm control --reload-rulesto get udev to re-read it.
Next, I look on my phone to see what version of Android it's running. I remember that when setting up the Eclipse project, I specified a minimum Android version the app would run on. I'd better check what version the phone has.
Menu->Settings->About Phone->Android version, tells me it's running 2.2.3 (Froyo).
Unfortunately, I don't remember what I said at setup (I bet I just took defaults), and it isn't obvious to me how to get back to that page. Googling tells me the information's in AndriodManifest.xml, so I look there and it says
android:minSdkVersion="8"
Great. I don't know which Android that is yet.
This page tells me that 2.2.3 is SDK API version 8. Whew.
Plugging in the phone and permitting USB debugging (Applications->Development->USB debugging) makes /dev/sdc and /dev/sg2 appear, though nothing's mounted.
I bring up eclipse, pick MyAndroidProject, and press Run. The Choose a running Android device screen pops up and, sure enough, there's htc_t-mobile-mytouch-3g!
Crossing my fingers, I click on OK, and ... there it is. MyFirstApp appears on the phone, and behaves just as it did on the Beagleboard. There's even an icon for it in the list of apps. How cool is that?
Wednesday, December 26, 2012
The Build Succeeds! Plus, I Now Have Timing Info
Having modified the makefiles to do a 32-bit build, it finally completes.
Eventually, with the modifications described earlier, the build succeeds.
How long has all this taken my little netbook? Here are the times for the two tries: the first failure, followed by the second success.
build-android.OUT:[ 11:29:21 ] : == ./build-android: BEGIN
build-android.OUT:[ 12:06:16 ] : == ./build-android: FAIL
build-android.OUT2:[ 12:36:49 ] : == ./build-android: BEGIN
build-android.OUT2:[ 18:01:25 ] : == ./build-android: SUCCESS
Started before lunchls, ended after supper.
How about once it's already built? How long does a no-op rebuild take?
[ 19:33:42 ] : == ./build-android: BEGIN
[ 19:38:18 ] : == ./build-android: SUCCESS
Three minutes. Not instant, but not bad.
How about a more interesting test? I'll clean it, then build using the cache.
[ 20:04:01 ] : == ./build-android: BEGIN
[ 22:49:13 ] : == ./build-android: SUCCESS
Two-and-three-quarters hours. Certainly much faster than a build from scratch.
Wait. "Cache"? What's this "cache"?
While Waiting on the Build, I Write an App
The build's slow, but chugging away steadily, so it's back to looking through the slides with google-mediated side-trips.
I finally finish the introductory material, about things like licenses and lawsuits, and get to section 1: "Android Internals"
At some point, perhaps the mention of Views and Viewgroups in slide 53, I wind up in the training tab of developer.android.com and think, "Oh, what the heck," so I set out to build their "My First Android App."
It's pretty fun, makes me use Eclipse and Java, neither of which I'm comfy with, but they're already installed, so it's another "opportunity for growth."
Sure enough, after following instructions, I end up with a two-activity application running on the Beaglebone. Now that's cool.
I also confirm that a real mouse, plugged into my host, actually lets me scroll around on the VNC'd Android GUI. Phew. If I still couldn't do that, I'd be in trouble.
The next step in their training is managing the app lifecycle, which meshes perfectly with slide 46. I could also try getting the app onto my cell phone. Plenty of directions to go.
Right now, though, I have to pack up and go home, with a stop at King Soops along the way, so I can pick up a cake for tonight's Wednesday night jam.
The build's still chugging away; I'll just let it run in the back seat of my car while I'm shopping.
I finally finish the introductory material, about things like licenses and lawsuits, and get to section 1: "Android Internals"
At some point, perhaps the mention of Views and Viewgroups in slide 53, I wind up in the training tab of developer.android.com and think, "Oh, what the heck," so I set out to build their "My First Android App."
It's pretty fun, makes me use Eclipse and Java, neither of which I'm comfy with, but they're already installed, so it's another "opportunity for growth."
Sure enough, after following instructions, I end up with a two-activity application running on the Beaglebone. Now that's cool.
I also confirm that a real mouse, plugged into my host, actually lets me scroll around on the VNC'd Android GUI. Phew. If I still couldn't do that, I'd be in trouble.
The next step in their training is managing the app lifecycle, which meshes perfectly with slide 46. I could also try getting the app onto my cell phone. Plenty of directions to go.
Right now, though, I have to pack up and go home, with a stop at King Soops along the way, so I can pick up a cake for tonight's Wednesday night jam.
The build's still chugging away; I'll just let it run in the back seat of my car while I'm shopping.
The Sources Need Minor Tweaks for a 32-Bit Build.
Final preps concluded, I guess I'm finally ready to try the big Android build on my little machine. Sadly, when I do it, it fails after half an hour.
frameworks/base/libs/utils/RefBase.cpp:483:67: error: passing ‘const android::RefBase::weakref_impl’ as ‘this’ argument of ‘void android::RefBase::weakref_impl::trackMe(bool, bool)’ discards qualifiers [-fpermissive]
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] Error 1
Googling a bit, I wind up at "You can't build from Gingerbread forward with a 32-bit machine." Which is what I have.
Harumph.
Well, perhaps I'm not the first person to face this. Another google shows I'm not, and there's ways past this.
The post lists three sets of changes I need to make to build files in the system to permit a build on a 32-bit host. TI seems already to have made he first. I'll make the other two and try again.
Subscribe to:
Posts (Atom)