Friday, May 28, 2010

Phone Number Fixer for Android

One of the curses of working with computers is that you often become The IT person for friends and family. In fact, I should get a commission from Apple for all of the business I've sent their way by getting family members to switch to Mac computers. Ditto for the Firefox browser. I can't make people switch to Mac, after all that's often an expensive proposition, but it's long been a condition of my help that you never even think about using IE. For some of my less computer savvy relatives, I've learned to make IE disappear. This just made my life a lot easier (less things to fix) especially back in the heady days of weekly IE6/ActiveX exploits. Anyways... These days most folks, including friends and family, mostly use web applications and since I've had them on Firefox for a long time now, there aren't too many problems. However, recently I got an unusual request for help from a high school friend Maria.

She had just switched to a Nexus One -- a phone that she seemed to be extremely happy with. She had imported several contacts from her SIM card that had been in her old phone. The only problem was that for these contacts, their phone number was classified as "Other." That would not be a big deal, but when she would try to send a text to a number, Android's auto-complete would not include these "Other" phone numbers as part of its search domain. So she would have to completely type out the number to send the text to -- which kind of defeats the purpose of having an address book on your phone. She could manually change each of these phone numbers to be of type "Mobile", and this would solve the problem for that number. However as you might guess, she had a lot of numbers and changing each manually would be painful to say the least. And that's where I come in...

This sounded like an easy enough problem to solve. Find all of the numbers that were of type "Other" and change them to "Mobile." That might not work for everyone -- there might be some people who really want to classify some phone numbers as "Other" -- but it certainly worked for Maria (and I would guess most people, too.) So I cooked up a quick little app. First, I wanted to display all of the numbers that this was going to affect:
ContentResolver resolver = getContentResolver();
String[] fields = new String[]{People._ID, People.NAME};
Cursor cursor = resolver.query(People.CONTENT_URI, fields, null, null, People.NAME);
LinkedHashMap<Integer, String> people = new LinkedHashMap<Integer,String>();
int id = cursor.getColumnIndex(People._ID);
int nameCol = cursor.getColumnIndex(People.NAME);
if (cursor.moveToFirst()){
 do{
  people.put(cursor.getInt(id), cursor.getString(nameCol));
 }while (cursor.moveToNext());
}
cursor.close();
This gives you a LinkedHashMap whose keys are the IDs of each contact, and whose values are the names of the contacts. Why did I bother with these two bits of info? Well, we need the contacts to query the phones, and I wanted something friendly to display to Maria so she knew which numbers were about to get "fixed". Anyways, now it was easy to query the phones:
ArrayList<String> data = new ArrayList&kt;String>();
StringBuilder sb = new StringBuilder();
String[] projection = new String[]{Phones.DISPLAY_NAME, Phones.NUMBER, Phones._ID};
Uri personUri = null;
Uri phonesUri = null;
int displayName = 0;
int number = 1;
int phoneIdCol = 2;
int phoneId = -1;
int cnt = 0;
for (int personId : people.keySet()){
 personUri = ContentUris.withAppendedId(People.CONTENT_URI, personId);
 phonesUri = Uri.withAppendedPath(personUri, 
            People.Phones.CONTENT_DIRECTORY);
 cursor = resolver.query(phonesUri, projection, 
            Phones.TYPE + "=" + Phones.TYPE_OTHER, null, null);
 displayName = cursor.getColumnIndex(Phones.DISPLAY_NAME);
 number = cursor.getColumnIndex(Phones.NUMBER);
 phoneIdCol = cursor.getColumnIndex(Phones._ID);
 if (cursor.moveToFirst()){
  do {
   sb.setLength(0);
   sb.append(people.get(personId));
   sb.append(": ");
   sb.append(cursor.getString(displayName));
   sb.append('|');
   sb.append(cursor.getString(number));
   data.add(sb.toString());
   phoneId = cursor.getInt(phoneIdCol);
   cnt += updateContact(phoneId);
  } while (cursor.moveToNext());
 }
 cursor.close();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.phone, data);
setListAdapter(adapter);
Toast.makeText(this, cnt + " phone numbers updated", Toast.LENGTH_LONG).show();
This code just loops over the contacts we got from the first query. For each of those contacts it queries to see if the contact has any phones that are of type "Other" (Phones.TYPE_OTHER). If it does, it creates a string that shows the contact's name, the phone's display name, and the phone number. This string is added to an ArrayList. Once all of the queries complete, an ArrayAdapter is created using the ArrayList of contact name/phone strings and used to populate a ListView.
You might have also noticed that a there is a counter variable being incremented, and an updateContact method. This is actually the method that fixes the phone number. I probably should have just kept track of the phoneIds and then gave the user a button to initiate the fixes, but I was lazy. Here is the code for updateContact.
private int updateContact(int phoneId){
 ContentValues values = new ContentValues();
 values.put(Phones.TYPE, Phones.TYPE_MOBILE);
 ContentResolver resolver = getContentResolver();
 Uri phoneUri = ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId);
 return resolver.update(phoneUri, values, null, null);
}
Too easy. Contacts are an example of a Content Provider in Android. Many people (including my Android in Practice co-author and author of Unlocking Android, Charlie Collins) have criticized Android for exposing too much of the database backing of Content Providers. As you can see from the examples above, you have to deal with cursors (moving, closing), queries, updates, and very thinly abstracted select and where-clauses. Maybe it would have been better to drop down directly to the SQL, or provide a more object oriented API. Now you can create your own Content Provider, and you don't have to use SQL database to back it -- but then implementing the Content Provider contract can be quite awkward.
Anyways, I found that the easiest way to get this little app to Maria was to simply put it on the Market. It's still on there if you happen to have a similar problem (maybe many people switching to Android might experience this?) If you are on your Android phone you can just select this link. If you are on your computer you can scan this QR code.

Wednesday, May 26, 2010

Mobile Zealotry

"You're either with me or against me!"
Does this feel like the rhetoric coming out of Google and Apple lately? Sometimes I wonder if Russell from Survivor is working for these guys. I was at Google I/O last week, and I have to admit that Vic Gundotra delivered a great keynote. It really got the troops excited.
"One man, one company, one device, one carrier would be our only choice ... Not the Future We Want"
Indeed. But before you go out and get an Android tattoo, and toss your iPhone off of the Golden Gate Bridge, take a deep breath and remember: You don't work for Google (unless you do, in which case I assume you've already got said tattoo.) You should not care who wins this jihad -- but make sure that you aren't collateral damage.

If you are a mobile developer, what you should most care about is delivering the best and most useful experience to your users. So first and foremost, you need to care about what kind of devices your users are using. If they are all iPhone users and you really want to build Android apps, well sorry. Further, if they are all Blackberry users, then you can just ignore the drama going on here in the Valley.

Of course the device of choice for your users today is quite possibly not what they will be using tomorrow. Former Android engineer Cedric Beust makes the point that the iPhone may well have peaked. Things look great when you're at your peak, especially if you don't realize that the descent has begun. So you might build a killer iPhone app this year, only to find that your users have moved on next year. Nobody ever said that this was an easy game.

Hedging your bets and investing in multiple platforms seems like the safe thing to do, if it's practical. But don't forget the other factor: delivering a great app. If you can't deliver a great app on Android, then don't bother. If you can't deliver on the iPhone, then don't bother. Both Apple and Google have gone out of their way to provide developers with fantastic tools and platforms for creating great apps, so this may be a moot point. There are definitely types of apps that are better suited for one platform than the other. For example, the iPhone seems to be superior for games. If you look at the success of consoles, you can see why that kind of environment where hardware and software are highly standardized, translates well to the iPhone. Similarly, the lack of background processing on the iPhone (and don't believe any hype about iPhone OS 4 changing this, it does not except in a few special cases) cripples the capabilities of many iPhone apps.

The most important thing to keep in mind in all of this is that it is in Apple and Google's best interests to be as divisive as possible. If they can convince you that they are "right" and that you should only develop for their platform, this is a huge win for them. So expect the rhetoric to only get worse. How many days until WWDC?

Saturday, May 15, 2010

Android Wish List

This Wednesday is the first day of Google I/O. Google has a lot of very interesting technologies and many of those will have some new features announced this week. However, it doesn't seem too presumptuous to say that I/O is going to be Android-centric this year -- maybe every year for awhile. Google has pitted itself firmly against Apple and its iPhone/iPad platform. So I/O is Google's WWDC, and in case you missed it WWDC 2010 is all about mobile. And so it is with I/O.

There is a lot of chatter about Froyo, or Android 2.2. It's browser will have an integrated Flash plugin. It's supposed to be insanely fast (courtesy of a JIT and lower RAM usage by the kernel). It will support USB tethering and it can turn any Android phone into a mobile hotspot. That's all great, but none of that really does much for us Android developers, except for the speed increase of course -- especially important for game developers. Speaking of game artistes, Froyo is supposed to bring a lot more OpenGL ES goodness into their hands. So maybe we'll start seeing killer games on Android. Anyways, back to developers. What's Froyo got for us? More importantly, what do you want out of the platform? Here's my list.


  1. Push Notifications. The iPhone has it. Blackberry has had it for what, a decade? The Windows Phone thing that's coming out at the end of the year is supposed to have them too. But what about Android? Background services and polling? Stop F'ing with me.
  2. Apps on SD Card. Yeah we've been asking for this for a long time, and Google has always shot it down. Why is it important? It removes the pressure to keep apps super small, a pressure that has some chilling side effects. On the iPhone, I wouldn't hesitate to use a 3rd party library in an app, even if it added an extra 500KB to the app size. Not so on Android. For me this is particularly acute when it comes to using other languages like Scala on Android. The runtime library size is prohibitive -- because the app can't be saved on to the SD card.
  3. More JDK. Wouldn't it be nice to have JAXB on Android? What about JAI? Yeah I know that sometimes they just wouldn't work because of performance reasons, but sometimes they would. Shouldn't be up to the developer to figure out when to use it or not?
  4. Android for pads/slates/tablets. Yeah I want the Android equivalent of iPhone OS 3.2. I want to see Android on these form factors. As a corollary, I want an end to ChromeOS and that potential distraction. Let's just have one tablet OS from Google, ok? Android: Tablet Edition will have the Mobile Chrome browser in Android, anyways right? Bonus points: A sexy device with the new OS running out given to all of the developers at I/O (I know they gave us Droids already, but I'm greedy.)


So there's my list. What's yours?

Update: I remembered one more thing for my wish list, though this is not directly part of Android. I want Android 2.1 (or 2.2) to be available on all Android devices. I want it running on the G1, for example. There are definitely some SDK features I'd like to take more advantage of, and that's hard to do with 1.5 and 1.6 still on the majority of devices. The Mobile Chrome browser in 2.0+ is infinitely better than what's in 1.6 and lower because it uses HTML5 standards for storage, offline, geolocation, etc. instead of the now defunct Google Gears. So I really want those 1.5 and 1.6 browsers to go away, it's like having to support an ActiveX control for Ajax...

Friday, May 14, 2010

Awesome Android Presentation

... by my "Android in Practice" co-author, Charlie Collins:

Sunday, May 02, 2010

Apple, Flash, and The Truth

I'm sure by now you've read "Steve Jobs"'s Thoughts on Flash. Did it convince you? Do you think it was truthful? Not me. Sure it has some valid points, especially about Flash being buggy on OSX. As someone who has developed Flash applications using a Mac, I am especially aware of this bugginess, and part of me can't help but get a perverse sense of satisfaction that this bugginess is now coming back to haunt Adobe. However, this doesn't change the fact that Jobs's epistle is far from the truth. It is corporate slander, designed to make Adobe look as bad as possible. Why? So that when devices from competitor's ship with full support for Flash, this technological advantage can be discredited in the eyes of consumers. In other words, this well thought out post by Apple is not some intellectual/technical analysis, it is just marketing designed to boost Apple's profits.

The most dishonest thing about the post is what Apple says is "the most important reason" to ban Flash from their devices: that it will result in sub-standard apps and hurt their iPhone/iPad OS platform. This is complete bullshit. It's not like developers would suddenly only be able to create iPhone apps using Flash. It's not like they could no longer use all of the tools they use today. The difference is that they would have a choice. They could choose to use Flash. Or they could choose to use Objective-C/Cocoa/XCode.

But don't forget, that not only would developers have a choice, but so would consumers. If for some strange reason, some developers started choosing to use Flash,  it's not like consumers would be forced to buy those Flash-authored apps. No, they could still choose other, traditional apps. In fact, if, as Apple claims, Flash-authored apps would be of such low quality, then one would expect that few consumers would choose to purchase those apps.

So if Apple allowed developers to use whatever tools and technology they wanted to use, to create apps for the iPhone and iPad, what might happen? Well if Apple's claims are right, then there would be bad apps that nobody would buy (aren't there already a lot of such apps on the App Store?). Consumers aren't idiots, and they won't buy crappy apps when there will be better alternatives. So those Flash-authored apps will lose money. Developers aren't idiots, and they won't keep using technology that produces software that nobody wants. So they would abandon Flash and go back to Cocoa. So Apple's "concerns" would be unwarranted.

Or perhaps what would happen is that some developers would produce good apps using Flash that consumers bought for their iPhones. Certainly developers would continue to use Flash. However, in this scenario, Apple's "concerns" are proven to be false -- Flash produces some good apps. But wait, what about Flash holding back innovation on the platform? Apple would still be free to add new features to their OS, and make them available to developers through new APIs in the iPhone SDK. Who knows how long it would take Adobe to expose those features through the Flash authoring tools, but who cares? If those features greatly improve apps, and they aren't available in Flash authoring, then what happens? The power of choice wins again. Developers can still choose to use Cocoa, tap into these innovations, and user's can choose to purchase the apps that take advantage of these innovations. If these features are so great, one might expect that Adobe would try to bring them to Flash authoring as quickly as possible. Either way, the notion that the Flash platform would be held back makes no sense.

So Apple's self-described most important point is so false that it is laughable. Some of their other parts are equally false. For example, the notion of touch and Flash. Yes, many things in Flash are designed for users interacting with a mouse, not a finger. Such things don't work well on touch devices. However, this is not just true for Flash. It is equally true for HTML and JavaScript. If you've done a lot of surfing on your iPhone or iPad, you have surely experienced the "rollover" issues described in Apple's post. Want more examples? Check out this clever little video on HTML 5 and the iPad:


So why all the bullshit? As I said earlier, the reason for the post is to discredit any competitor that provides Flash support on their devices. First and foremost on that list is Android, which will support Flash in Android OS 2.2. That doesn't explain why Apple doesn't want to allow developers to use Flash to develop for the iPhone? The answer to that is simple. They want complete control of their platform. If you want to make money off of the iPhone, you have to be in bed with Apple. They saw how the web has hurt Microsoft, and they will not let this happen on the iPhone or iPad.

Now wait a minute, isn't Apple investing heavily in the web, namely HTML 5? Doesn't that demonstrate that they are willing to give up control of their platform? Yes, and no. Yes, Apple has invested into WebKit, a technology that in various forms implements a decent chunk of the HTML 5 standard. But you see, the key word here is "standard." This is how Apple fools you into thinking that they are providing an "open" alternative to their proprietary system.

It's easy to get fooled into thinking that any company that implements and open standard is innovative, but just the opposite is true. We think standards=innovation for browsers because of Microsoft IE 6. That browser dominated the world for a long while being completely stagnant. It was both non-standard and non-innovative, but this is an exceptional. It is rare that such technology can flourish. It took the unique nature of Windows, IE, and Microsoft's legal troubles to produce this situation.

Adopting a standard just means that you either change an existing feature of your technology to comply with the standard, or you copy a feature from others in the space. It is anti-innovation. When it comes to web standards, they are introduced post-hoc. XMLHttpRequest, the key technology behind Ajax, was proprietary Microsoft technology for many years before it became a standard. Many of the features of HTML 5 were introduced by various plugin technologies like Flash or Google Gears before they became part of the HTML 5 spec. You cannot innovate while waiting for some super slow moving corporate committee to vote on a new standard.

Going back to the iPhone/iPad, Apple is saying: pick either Cocoa and go through the App Store, or stick to the web, but only the "open standards" part of the web. They have given you a choice, but only the weakest, most impotent choice possible. You see this is where the other part of their Flash ban comes into affect. Not only have they recently banned compiling a Flash authored application into a native iPhone application, they have always banned Flash running in the browser. Why? Because with browser plugin technologies like Flash, Silverlight, and yes even Java, you can create user experience's on par with desktop applications. If they allowed Flash in the browser on the iPhone, then developers could create web applications that might rival the native iPhone applications. And we wouldn't want that, now would we? So Apple give you a single alternative to using Cocoa/XCode/AppStore, and then they horribly cripple it, by removing the most innovative parts and tying a design-by-committee-technology weight around its neck. Apple's endorsement of HTML 5 is one of the greatest marketing ruses ever. They stifle innovation, limit choice, and line their own pockets while getting everyone to believe they are being developer friendly and innovative.

After all of the above, you might think that I am very anti-Apple, anti-iPhone, anti-iPad. I'm not at all. I am anti-bullshit though. I don't like being lied to and treated like a lemming. Apple has every right to keep Flash off of their devices. It's their OS after all. They have very right to ban apps that were authored with Flash from their AppStore. It's their AppStore after all. Just don't lie to me about this stuff. Don't say it's better for developers or better for consumers, when it's actually worse for both. Just tell the truth: it's just better for Apple.