Friday, August 07, 2009
I wish Blogger would let me rename tags
T-Mobile Visual Voicemail Problems
T-Mobile recently released their Visual Voicemail application in the Android market. It had some launch problems, but those are mostly smoothed out at this point. The app works pretty well, and I'm glad that they have finally implemented it. However, the app does have its share of first-release problems. They are listed here, in the order that I hope T-Mobile addresses them.
VVM doesn't work with Wifi. Most people probably have Wifi enabled on their phones. After all, it's the most efficient (both bytes / time and power / byte) way to tranfer data. However, VVM doesn't work with Wifi. It will neither notify you of new voicemails, nor will it download new messages. In order to make it work, you need to
- Turn off Wifi
- Wait or click "Synchronize Voicemails"
- Turn Wifi back on
VVM has a separate notification icon. Every time you get a new voicemail, you get the standard voicemail icon. In addition, you get a new VVM icon. For now, this is fine. If I have Wifi enabled, I still get notified of a new voicemail (via the standard voicemail icon). When the Wifi issue is fixed, however, I would like to see the new icon go away. The notification bar is crowded enough.
VMM uses the wrong audio stream. VVM uses the "media" audio stream. Many people complain that prevents you from using a bluetooth headset to listen to your VM. I don't have a bluetooth headset, so I can't confirm this. It should use the "phone" audio stream.
The UI needs polish. There are some small look-and-feel issues:
- The VVM status bar icon doesn't match the Android UI Guidelines.
- After pressing the "Synchronize Voicemails" button, there is no feedback. No spinner, no progress bar, nothing.
- The long-press context menu on a VM does not include a "delete" option (only Open, Reply As, and Copy To)
- The buttons that appear when you press the "Menu" button have no icons.
- The "Copy to" screen is a little too technical. The file name defaults to vmn (i.e. vm0, vm1, vm2). It should instead default to something like "Voicemail from John Smith on 22 Jul, 2009". In addition, the save directory defaults to "/sdcard". Should users really be exposed to UNIX pathnames? Clicking the Save in Directory dropdown presents me with a file browser for my SD card. For me, this lists locations like ".Trashes" (I use a Mac), espeak-data (the data files for the Text-To-Speech engine), "where" (the data for Where), and other places that I probably shouldn't be saving random files. Do I really need to be able to specify the location to save the voicemail? Why not just save everything to /sdcard/voicemails? Or at least, why not assume that all voicemails get saved to /sdcard/voicemails or a subdirectory (i.e. you can't save a voicemail outside this directory, only inside)?
Initial, first-run experience is lousy. When I first installed and ran the app, it wasn't able to connect to the server. After disabling Wifi, it worked. I was taken to a set-up screen, but then got distracted by something and hit the back button. When I relaunched the application, the set-up screen wasn't presented. This worried me (is there some setup that needed to occur), so I uninstalled the app and re-installed it. I don't think I did any harm, but the app didn't behave as I expected, so I didn't know what to think.
Deleting doesn't always work. I'm going to chalk this up to glitch behavior. The first time I used the app, I went through and deleted some old messages. Then I went into the analog voicemail system, and they were back! I deleted them a second time, and now they're really gone. shrug
Now, I don't mind all of those problems. I'm glad that T-Mobile finally released a VVM app. I'm glad that they released it early, warts and all. I hope that they are not done working on it. For me, the Wifi issue is huge. I'm connected to Wifi 90% of the time, and that means that the VVM app doesn't function as a voicemail app 90% of the time. I suspect many other people are in the same boat as me. Furthermore, Google Voice is coming. If the Wifi issue isn't fixed by the time GV is generally available, I might just jump ship, and T-Mobile doesn't want me to do that. I understand if T-Mobile can't fix this on their own - they might need support from Google. Still, every carrier is going to want to provide VVM, and it would behoove Google to provide whatever support necessary.
Saturday, July 18, 2009
Getting Started with Stack Overflow
I joined Stack Overflow shortly after it launched, but I didn't do anything with it. I found it in search results here and there, but I never asked any questions. I would have done more, but new users are pretty helpless. You can't vote up or down, you can't comment on answers, you can't post an answer with more than 1 link, etc. It's almost like you're not wanted. Compared to the relative freedom of Wikipedia, it was really demoralizing to me.
I decided tonight to actually try to get some reputation. Most of the interesting stuff happens around 50 reputation, so that's my goal. I answered 2 questions this evening. Suddenly, my rep is skyrocketing. I'm at 31 right now, and I bet that will continue to climb on its own. It seems that people are very willing to vote your answers up if they are relevant. As you can see, it shouldn't be hard to get to the point of actually being able to contribute.
So, if you want to get started with Stack Overflow, here are my suggestions.
- Go to the newest questions page.
- Find something that you know something about. Don't troll, and don't post to random topics about which you know nothing.
- Write an answer.
Thursday, July 16, 2009
Fixing the Xbox 360 's Grinding Noise / Tray Ejection Problem
I spent an evening performing unexpected surgery on my Xbox 360. When I put a game in, the drive made the most horrible grinding noise. On top of that, the drive would not stay closed. The tray would almost always eject seconds after being closed. Research led me to conclude that the rare earth magnet that is part of the disc clamp had probably become unglued. Since my initial warranty has long since expired and the red ring of death warranty only has another year, I decided to crack the case myself.
It's not worth going through the details, but I did find two useful videos. The first is an overview of the problem. The second is a good tutorial on opening the 360's case. I used some Zap-A-Gap brand contact adhesive that I had laying around to actually reattach the magnet.
I felt quite proud to have diagnosed, researched, and fixed the problem on my own (without sending my console to Microsoft for repairs). $100 plus shipping just to have some intern apply some glue is a little extreme. So many people have had this problem that YouTube videos just refer to it as "the grinding noise problem." Either Hitachi (the drive manufacturer) just made a lousy drive, or Microsoft didn't correctly anticipate the effect that their game furnace would have on the glue that Hitachi used. I don't know who is to blame, but Microsoft should extend their warranty on the 360 to 3 years for all defects, not just those that cause the red LEDs to light up in a circular fashion. I don't expect my car to wear out in 2 years, and I use it every day. My game console shouldn't wear out, either.
Wednesday, July 15, 2009
Feedback Works!
It's hard to say if this is coincidence, but it's worth mentioning. A few weeks ago, I sent eBay feedback on their new site design. My gripe was that they were nesting scrollable areas within scrollable areas. As I was using the site today, it dawned upon me that the bad behavior was gone. Somebody actually fixed it. Perhaps it was my email; perhaps it was the combined voice of thousands of users; perhaps some developer just realized that there was a better way. Whatever the case, I'm glad that eBay made the change, and I like to think that I helped in some way. Thanks, eBay!
Before, things just felt wrong. I would be scrolling the page, and it would mysteriously stop. This happened on every single page, it seemed. When they switched to good design, I didn't even notice at first. It just felt natural. This brings to light a sort of design axiom: design successes are invisible, design flaws are glaring.
Sunday, June 28, 2009
Excellent Customer Service at Adafruit
I've been meaning to write this post for a while, but I just haven't gotten around to it. Well, that ends now! The time has come!
A little over a month ago, I ordered a couple of kits from Adafruit Industries. When the box arrived at my doorstep, it seemed a little too small. Once I opened the package, my fears were confirmed: they had only included one of the two kits.
I typed up a quick email to customer support that night, and figured I'd hear back in a few days time. After all, they are a small company (I think they are small. I don't really know.). The next morning, I was surprised to find this email in my mailbox:
hi daniel -
that's odd - we're going to send out a starter pack immediately - and
we will check the order to see what happened.
cheers,
adafruit
That email was sent at 3:03AM. They immediately sent out the second kit. It arrived a couple of days later.
I was surprised and pleased with their customer service. They didn't question my claim, didn't beat around the bush, and didn't make me wait. They corrected their mistake as quickly as they could. Adafruit Industries is a top-class outfit. I will be ordering (many things) from them in the future.
Saturday, June 27, 2009
Arduino librxtxserial.jnilib on MacOS
After re-installing MacOS from scratch, I found that I was having problems launching Arduino. I got the following error:

In order to solve this, I followed the instructions at rancidbacon.com. The solution was to use Finder to configure the application to launch in 32-bit mode. I quickly looked to see if I could modify the Info.plist file to enforce this behavior, but I don't see any way to do that.
Another solution from technobabble is to replace the library inside the Arduino app bundle with a 1.6 compatible version.
Thursday, June 18, 2009
Quick, Over There!
I'm going to try to continue posting stuff here, but it's worth mentioning that I will also be posting over at the Gents with Beards blog. Anything related to the iPhone will go there (though I will make brief mention of it here). Anything else might go there, might come here, or might get cross-posted.
I made a couple of posts so far, related to my experiences with OpenAL in the iPhone Simulator and differences in the Initial Developer Experience between iPhone and Android. I hope to write one or two about Git, and who knows what after that.
Friday, May 15, 2009
JTextArea and javax.swing.text.Document
I was playing with a JTextArea in my Swing project today. My underlying data is actually quite simple (a list of names and quotes), and my JTextArea is read-only. Therefore, I decided to try to make my own class that implements javax.swing.text.Document, but whose internal structure more closely models my real... model.
I had a hard time getting started. From poking around in Document's Javadocs and in related Java source code, it appears that Document is a very general concept. It seems to have originally been intended to model an SGML document's structure - or something like that. The Document interface lets you navigate a tree structure that represents the document. However, when it comes to modeling data for a JTextArea, things are much simpler. Instead, it appears that JTextComponent (the base class of JTextArea) assumes that the Document models a list of lines of text. That is to say, it seems to expect that the Document has one root element which contains a separate element for each line. This is most obvious from JTextArea's getLineCount() method:
public int getLineCount() {
Element map = getDocument().getDefaultRootElement();
return map.getElementCount();
}Now, the problem with all of this is that Document is a pretty complicated interface. On top of that, since SGML is a tree-oriented structure, it is not quite intuitive to map the concepts of "stream of text" to "tree-shaped structure". More problematically, I didn't see anything in the documentation to even begin to shed some light on this unspoken relationship. I stumbled upon it while examining stack traces from my first cut. I vaguely recall this being much easier in the little bit of Cocoa that I dabbled in, but I can't be sure. Maybe I'm just crazy - there are certainly a number of other concrete, Document-derived classes out there.
So remember, if you want to implement Document, make sure to model your document as a list of lines of text.
Tuesday, April 07, 2009
Something Nice
I don't like that most of my blog posts have a negative tone. I'd like to balance that by talking a bit about something that was really cool. Let me wax lyrically about MacHeist.
After buying the last MacHeist bundle a year ago, I got put on the MacHeist mailing list. As a result, I was able to participate in the missions that they've been putting out for the past few months. Between the free apps I got from completing the missions, the apps in the actual heist, referring 2 friends, and tweeting once, I managed to score 40 apps worth a theoretical value of almost $1700. It cost me $33 (I got a $6 discount by completing in the missions), and a few hours of my time. Let me go into a little more detail about the whole thing.
In order to drum up support, the MacHeist team starts by putting out challenges for several months before the actual sale. In order to solve these riddles, you need to do a little internet sleuthing. This year, they got the cooperation of Veronica Belmont, Lisa Bettany, and Chris Pirillo. People work hard to figure them out but, if you're lazy, you can just follow the walkthroughs that people post. I usually do about 50/50 - working on the challenge until I'm out of ideas, then go read what smarter people than me wrote. By doing this, I got $541 of software (and a $6 off rebate on the actual bundle) for just a few hours of time. Lisa Bettany also starred in a handful of mission briefings as Sophia, the Eastern European secret agent trying to save the world from time glitches. A little campy, but entertaining nonetheless.
Of course, there's also the heist itself. The whole bundle was introduced this year in a 90ish minute live streaming show with an overview of every app. They started this one by selling 8 apps for $39. From each sale, 25% of all sales go to charity. When they reach certain charity milestones, they add more apps. This year, there were 3 milestones. The last was $500,000 for charity, and that unlocked the final 2 apps. It was a little scary this year, because sales stagnated after a couple of days. The last two apps, one of which was Espresso, were still locked. Fortunately, there was a last-minute sales frenzy, and now they're waaay over their final unlock milestone. To try to incentivize people who were sitting on the fence, they added two more apps during the sale, for a total of 14.
Since Twitter is popular with the kids these days, MacHeist took the opportunity to reach tons of people by hyjacking the social experience. If you were willing to tweet a short message to get the word out about MacHeist, they gave you two more applications. Was I just helping The Man by giving free advertising? No! I wanted other people to have the chance to get these apps. This is the tweet they asked me to post:
I bought the @MacHeist 3 Bundle. 12 Top Mac apps worth $900+ for just $39 AND I just got Delicious Library 2 FREE!That's not too bad!
Finally, I managed to refer two of my friends to the sale, and I got an additional 2 apps from that.
Now, I realize that I didn't actually get $1700 of worth from this bundle. I will probably never even start some of these apps. However, if you can find even 2 apps that you want, this deal makes sense. In my case, I had my eye on several of these apps for a while, and just never got around to buying them. Also, keep in mind that a big pile of them were totally free. I could have walked away with a bunch of software for just a few hours of puzzle solving (or walkthrough-reading). This sale always amazes me. Past sales have included Delicious Library 1, TextMate, CSSEdit, PixelMator, and other great apps. Good job, MacHeist.
Bundle apps
- Acorn
- Cro-Mag Rally
- BoinxTV Sponsored Edition (which means that you have to indicate that you used Boinx to record your video, which kinda sucks)
- Espresso
- iSale
- Kinemac
- LittleSnapper
- PhoneView
- Picturesque
- SousChef
- The Hit List
- Times
- WireTap Studio
- World of Goo
Apps for completing missions (these only took a few hours to get, but were only available for a limited time)
- 3D Hearts
- Agent Craig
- AllSecure
- BabelBloX
- Blitz
- Fresh
- Hyperspaces
- iStock
- KavaTunes
- MacDust
- MiniOne Racing
- Overflow
- Pandora's Pests
- Process
- Scribbles
- ShoveBox
- Sticky Notes
- Timepost
- Typinator
- Webbla
Apps for tweeting about the bundle (only available after buying the bundle)
Apps for referring others (only available after buying the bundle)
Wednesday, February 25, 2009
Android SDK + eBay SDK
I haven't done anything with Android in a while, so I thought I would see whether I could get my phone talking to eBay. I grabbed the eBay SDK for Java, stuck it in my project, wrote a small demo app, tried it out, and BOOM!
VFY: unable to resolve new-instance 1516 (Ljavax/swing/event/EventListenerList;) in Lcom/ebay/sdk/ApiCredential;
VFY: rejecting opcode 0x22 at 0x0015
VFY: rejected Lcom/ebay/sdk/ApiCredential;.<init> ()V
Verifier rejected class Lcom/ebay/sdk/ApiCredential;
Shutting down VM
threadid=3: thread exiting with uncaught exception (group=0x4000fe68)
Uncaught handler: thread main exiting due to uncaught exception
java.lang.VerifyError: com.ebay.sdk.ApiCredential
at com.ebay.sdk.ApiContext.<init>(ApiContext.java:41)
at org.balefrost.bodacious.Bodacious.onCreate(Bodacious.java:75)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1122)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2104)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2157)
at android.app.ActivityThread.access$1800(ActivityThread.java:112)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1581)
at android.os.Handler.dispatchMessage(Handler.java:88)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3739)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
at dalvik.system.NativeStart.main(Native Method)
It looks like it depends on a Swing class (EventListenerList), but Swing isn't available on Android. I guess I'm rolling it by hand then. It's actually unfortunate that EventListenerList is a part of Swing - it looks generic enough that maybe it should be promoted to the core library. For that matter, I'm a little surprised that this made it past the apk builder. Perhaps that is outside the scope of the apk builder.
Wednesday, January 28, 2009
Looking For a Laptop Table
I'm looking to get a small side table so that I can use my laptop in my living room without it burning my lap. I'm considering a LapDawg, but the $130 price tag isn't too appealing. Whatever I end up with, it won't be a Freedom Furniture Laptop Table II Mobile.
Does anybody have any suggestions?
Sunday, January 18, 2009
Vista Taskbar Transparency
One quick Vista UI tidbit. Window decorations (titlebars and borders) in Vista are normally translucent. When you maximize a window, its titlebar become opaque. The Vista taskbar is also normally translucent and, like window titlebars, also turns opaque whenever any window is maximized.
Interestingly, this is done even if the window is maximized on another screen. I recently switched from a dark background picture to a nearly white picture, and it's getting frustrating to see my taskbar alternate between black and gray for what seems like no good reason.
Ultimately, this is a small gripe. It's doesn't really get in the way. It's just odd. It reflects a lack of focus on fit and finish at Microsoft. I hope Windows 7 ends up being better.
Tuesday, December 02, 2008
G1 Camera Tricks
The G1's camera seems to be slow. Really slow. As in several-seconds slow. I always wondered why; then I started to look at my pictures from the Macy's Thanksgiving Day Parade.

Ah. I see. I don't think that's because of the curvature of the lens (it's not curved THAT much) I was apparently panning the camera when I took this picture (to keep up with the float, though I didn't correctly account for the very long shutter delay, and the float ended up behind the pole). You are seeing the effect of the CCD "scanning". This reminds me of this project, in which a dude builds a digital camera from a flatbed scanner.
This is a picture of his garage door opening and closing while he takes a single exposure.
I hope this isn't an actual limitation of the G1's hardware. My cheap Nokia 6267, a feature phone, had an excellent 2MP camera that took pictures nearly instantaneously. So far, the G1's camera reminds me of my short experience with Windows Mobile 5's camera app - slow and clunky.
Using a Horizontal Progress Bar in Android
I was working on my Android downloader application yesterday, when I ran into a bit of a snag. I wanted to display a list of downloads (similar to the Firefox downloads window). Each item in the list should show the file name and a horizontal progress bar. I started to implement this, and several hours later stumbled upon the arcane solution. I wanted to share this, both to help anybody who may be trying to do something similar, and also to illustrate how the lack of good documentation is hurting aspiring Android developers.
I thought that I could put a ProgressBar instance in my xml, set it to be indeterminate, give it a max and a value, and be done. However, it wasn't nearly that easy. After a few hours of hunting on Google and the Android Groups, I stumbled upon the solution in an online preview of The Busy Coder's Guide to Android Development. In short, I had to set the following on my ProgressBar's XML:
style="?android:attr/progressBarStyleHorizontal"WTF?
Let's try to break this down. The ? on the front indicates that this is a reference to something in the current theme. What is a theme? Well, Android's UI infrastructure is similar to Swing or HTML in that it tries to accommodate components whose size is not known until runtime. Android's components are also themeable (similar to the Swing Synth LAF). A theme is a collection of related component styles. You can control the theme used by your application in the AndroidManifest.xml file. So, I think we can safely conclude that attr/progressBarStyleHorizontal is something whose actual value is defined in a particular theme.
If you take a peek in the android source code, inside frameworks/base/core/res/res/values/attrs.xml, you will find the following definition:
<resources>OK, not very useful. However, in frameworks/base/core/res/res/values/themes.xml, we find:
<declare-styleable name="Theme">
<!-- snip -->
<attr name="progressBarStyleHorizontal" format="reference" />
<resources>Nowe we're getting somewhere. Finally, inside frameworks/base/core/res/res/values/styles.xml, we see:
<style name="Theme">
<item name="progressBarStyleHorizontal">@android:style/Widget.ProgressBar.Horizontal</item>
<resources>
<style name="Widget.ProgressBar.Horizontal">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
</style>
What's going on here? Well, it looks like themes.xml defines a theme as a collection of styles. Along with that, styles.xml specifies a set of attributes that should be applied to a particular XML element. By saying
<ProgressBar style="?android:attr/progressBarStyleHorizontal">we are really saying
<ProgressBar style="@android:style/Widget.ProgressBar.Horizontal">which is like saying
<ProgressBarSpiffy.
android:indeterminateOnly="false"
android:progressDrawable="@android:drawable/progress_horizontal"
android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal"
android:minHeight="20dip"
android:maxHeight="20dip">
For bonus points, we can look in frameworks/base/core/res/res/drawable/progress_horizontal.xml. This file apparently contains the declarative expression of the horizontal scrollbar graphic. I don't know how extensive this syntax is, but a quick peek at progress_indeterminate_horizontal.xml indicates that it is possible to specify animations in this XML file format.
All this seems really powerful, only somewhat useful, and totally confusing. All I wanted was to create a horizontal progress bar. I can't tell why the Android widget collection includes only one ProgressBar class that is meant to be used for horizontal, indeterminate horizontal, indeterminate circular, and every other kind of possible progress indicator. Perhaps there would be duplication of code if those were separated into different classes. Whatever. I actually don't mind that they stuffed all those progress indicators into a single class. There are some questionable decisions (like having both indeterminate and indeterminateOnly), but I can deal with it. On the other hand, the incantations that you have to use to get the Progress Bar to behave are truly arcane. I think I have proven in this blog post that there is some method to the madness and, as is often the case, easy access to the source code is a must. What bothers me most is that there was absolutely no documentation on the subject. Google seems silent on this topic, and even The Busy Coder's Guide mentions that the style attribute won't be covered until a later edition of the book (though it is possible that the Google Books sample chapter is out of date at this point).
I still maintain that Android is one of the most unique application systems that I've seen. However, as I've tried to develop for it, I have encountered a general lack of polish. Many things that you want to do as a developer are confusing and poorly documented. Familiarity with existing technologies (such as Swing or Applet programming) is pretty much useless here. On the other hand, the core concepts (such as the use of Intents to start applications and communicate between processes, the HEAVY use of message passing, and the declarative nature of the AndroidManifest.xml file) seem to be an excellent base upon which to build not just an open operating system, but a truly open user experience. A power user can really replace virtually any aspect of the system. Perhaps developers will create third party libraries that make Android a little easier within which to develop, or maybe Google itself will provide simpler interfaces for developers. Or perhaps Android will die out because developers had a difficult time building anything particularly complex. Whatever the outcome, I'm excited for the ride.
Thursday, November 13, 2008
Grep is fun
I'm not what you would call a UNIX power user. I'm more of a UNIX casual user. I don't agree with the zealots who claim that the command line is king, and shell scripts keep the world spinning. It's a pain to remember the myriad of switches, and to remember the differences in those switches between platforms (BSD find requires a pathname, GNU find does not), etc. Maybe my distaste of the command line is why my primary computer is a Mac.
In any case, I was rooting around in the Android source code today, looking for examples involving the NotificationManager. I managed to whip up the following pipeline, of which I am proud.
grep -rl --include=*.java NotificationManager . | xargs grep -l "\.clear" | xargs mate
To break that down,
To summarize, this pipeline opens a text editor with every .java file in the android source code that contains both of the strings "NotificationManager" and ".clear". In my case, I was looking for all invocations of NotificationManager.clear(). Since the Android source code seems to be pretty consistent about explicitly importing all classes used, this scheme works pretty well.
If anybody knows of any command-line tools for searching a code base for Java-aware constructs (such as method definition, method invocation, etc.), please let me know! Something like that would be really, really handy. Eclipse provides all that, but it doesn't look trivial to get all of the Android source code into Eclipse projects.
Tuesday, November 11, 2008
AnyCut's "Make Your Own" Demystified
I installed AnyCut on my G1 a little while ago. AnyCut is a small app that allows you to create shortcuts to, well, almost anything. It has a mysterious "Make Your Own" option that isn't really documented at all. I started to play with it a bit, and it's not as bad as you would think.
The Make Your Own screen has three fields: Action, Data, and Type. I believe that these line up with the constructor parameters of public Intent(String action, Uri uri, Context packageContext, Class<?> cls). The Action parameter is one of the string consts in the Intent class (such as android.intent.action.VIEW, not Intent.ACTION_VIEW), and the Data parameter should really be called Uri, because it includes the Uri of the item upon which you want to act. See also the list of common intents. I imagine that the Type parameter is a fully-qualified class name, but it can be left blank for most uses. Finally, I suspect that the packageContext parameter is supplied by AnyCut itself.
I haven't yet had a chance to verify any of this against the source code (which I came across while writing this post), but it might be worth a look.
Thursday, October 30, 2008
2 Days with Google Gears
I had a chance to play with Google Gears on a mockup project recently. I was surprised to learn that my understanding of Gears was not the same as the reality of Gears. I had expected it to be a JS library to facilitate rich HTML applications to handle spotty network connections. It turned out that Gears is a browser plugin that adds useful tools that any rich web app developer would find useful, though they are all aligned to handle an app losing its network connection. In the two days that I spent playing with Gears, I was pretty much blown away by the power and simplicity of it.
Besides understanding what Gears is, it's important to also understand what Gears is not. Gears doesn't try to be a UI library, or a general "glue" library (see JQuery, Prototype, MochiKit, MooTools, or any other Javascript framework). It doesn't really force you to code in any particular way (this is a bit of a lie, but more on that later). Just as a sampling, Gears includes:
- A cross-browser compatible XMLHttpRequest
- Local database storage
- A web resource cache, so that items can still be fetched even if the network connection goes down. This is nearly completely transparent to the developer, and works for resources loaded by Gears or by the browser itself.
- A mechanism to run scripts in the background (for real).
In our little demo, we have a set of checkboxes that can be checked. Initially, these would perform an asynchronous post to the server, where they would update some server-side state. However, if the app goes offline, nothing will ever reach the server. We modified this to enqueue changes into a local database, with a background script pulling items out of the database and sending them to the server. If the server ever goes down, that thread simply stops pulling items out of the database. In addition, we set our app up so that its resources (HTML, Javascript, CSS, and images) were initially cached when the app is first loaded. A neat feature of Gears seems to be that it will monitor the apps that it knows about and will automatically update its cache if the cache ever gets stale. Unfortunately, it's not perfect. It depends on the developer updating a version string, which causes Gears to update its cache from the source.
One problem that we had is that the HTML that we served up would include information about what items were checked. That is to say, when you would load the page, we would serve up some <input type="checkbox" /> and <input type="checkbox" checked="checked" /> elements. This makes total sense in a traditional web app. The client requests the page, and you serve it, and everybody is happy. Every time the page is served, it is reconstructed with the current state of the data. As you might imagine, this caused all kinds of problems for us. Concretely, we noticed that every time the page was reloaded (whether the network connection is up or down), the browser would display the state of the page as it was when the cache first acquired it. In a real application, that could mean that you are seeing data that is several months out of date. Now you see how I lied earlier. Gears does influence the way you code your application, but its requirements are about the same as those of any Javascript-heavy web app. As long as you separate your application presentation from your data, you should be fine.
Another thing that surprised and greatly pleased me was Gears' WorkerPool implementation. As everybody knows, it is impossible to run Javascript in the background in a normal web browser. I think that's because multi-threaded programming is hard, and Javascript can be pretty hairy as it is. I think that the browser designers have held off on implementing a threading solution out of fear that multithreaded Javascript would cause the apocalypse. As it turns out, though, Gears' implementation is both simple and powerful. Gears uses a message-passing mechanism for communication, with absolutely no shared state. This is great news. As far as I can tell, just as your main JS code has an event loop, each worker also has an event loop. Whenever a message is sent from the main JS code to a worker, that message is copied and onMessage is invoked on by that worker's event loop. Likewise, when a worker sends a message back to the main JS, the message is copied and onMessage is invoked on the main event loop. This has some interesting implications. For one, none of the workers have access to the DOM, or to global variables defined on the page, and cannot participate in closures with mainline Javascript code. By placing a concrete wall between your page and your workers, Gears forces you to think about the interactions that the page and the worker will have, and that's a Good Thing. I'm sure that it's still possible for threading to ruin you, it's just a lot harder with a scheme like this.
And that's it. There's more to Gears that what I described (though not much more). It also includes some geolocation bits (presumably for Android, and maybe Safari Mobile, integration), desktop integration stuff, a standards-compliant timer, a file multi-chooser (yay!), and a binary data type (as opposed to String, which is for textual content). It's a shame that Gears is still in beta. I would really like to see some sites that use it. Of course, since I just recently installed Gears, there might be some sites that do and I never realized it.
Wednesday, October 29, 2008
User-Visible Permissions in Android
I picked up a T-Mobile G1 (danger: Flash-heavy site) at the local T-Mobile store. For those that don't know, the G1 is the first device to run Google's Android platform. So far I like it a lot, and I'll probably post a lot more about it in the near future.
Like the iPhone, Android has its own app store. Unlike the iPhone, nobody moderates apps submitted to the Android app store. If an app tries to do anything of consequence (i.e. anything that a user might want to know about), it must explicitly request that permission. When you start to download an app from the marketplace, it tells you what permissions that app will require. Most apps are well behaved, but some ask for way too much.
For example, I wanted a weather app. I saw that there is a Weather Channel app. When I went to download it, however, I was very surprised. Here is a list of the permissions that it requested.
| Network communication | full Internet access |
| Your location | coarse (network-based) location, fine (GPS) location |
| System tools | change network communication, change your UI settings, modify global system settings |
| Your messages | edit SMS or MMS |
| Services that cost you money | send SMS messages |
| Your personal information | read contact data |
What? Why does this app need access to my contacts, or to send text messages? I hope that this was just a lazy developer who requested more permissions that he actually needed, but I'm suspicious. It's entirely possible that The Weather Channel intends to compile a list of all my contacts. Not cool. Especially since it makes no mention of that.
I think it's great that Android provides some ability for the end user to judge the software that they might install on their phone. I'll wait until The Weather Channel updates their app.
Tuesday, October 14, 2008
Scala's Model of Functions
I was a little dismayed to learn that Scala models functions with different numbers of parameters as instances of distinct function trait definitions. A practical upshot of this is that you can't really work with functions that take more than 22 parameters.
def crazy(a:Int, b:Int, c:Int, d:Int, e:Int, f:Int, g:Int, h:Int, i:Int, j:Int,
k:Int, l:Int, m:Int, n:Int, o:Int, p:Int, q:Int, r:Int, s:Int, t:Int,
u:Int, v:Int) = 0
(crazy _).curry : (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) =>
(Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) => (Int) =>
(Int) => (Int) => Int = <function>
def crazier(a:Int, b:Int, c:Int, d:Int, e:Int, f:Int, g:Int, h:Int, i:Int, j:Int,
k:Int, l:Int, m:Int, n:Int, o:Int, p:Int, q:Int, r:Int, s:Int, t:Int,
u:Int, v:Int, w:Int) = 0
(crazier _).curry : <error>
The scala runtime apparently has traits Function0 through Function22 defined. I guess this is so that they can have call methods that take a statically known list of parameters (rather than, say, an array). That's all well and good, and probably necesary for proper Java interop, but it's still a little sad. Still, I don't expect to run into that limit any time soon. Oh wait, I have already worked on projects with functions that take more than 20 parameters. Maybe this was added just for me. Now I'm sad.