Tuesday, April 19, 2011

Thoughts on Windows Phone 7

A few weeks ago, I was contacted by a friend from Microsoft about going to a get-together that Microsoft was having. The reason for the meetup was Windows Phone 7. It was going to be at Alexander's Steakhouse, which is one of the best places to eat in the Bay Area -- at least in my carnivorous opinion. So I said that I was interested, even though I had done no development for WP7. He took that as an opportunity to hook me up with an LG Quantum running the latest and greatest version of WP7 and a Programming Windows Phone 7 book. I figured that since MS was being so kind to invite me to such a nice place, I should at least kick the wheels on WP7. Here's my take.

First, here's my impression of WP7 and the LG Quantum. I will give MS props for trying out some new user experience patterns. However, I am not a fan. I do not like the left-to-right organization of apps. Often I finding myself scrolling down a page trying to read something and accidentally scrolling to the next page on the right. This would just be a minor inconvenience if scrolling back to what I was interested in was quick and easy, but unfortunately the app starts loading another screen (the page on the right) and when I go back to the left one, it has to reload. Not only does this take awhile, but it almost always loses my context of what I was reading on the left page. It really sucks.

The other side effect of this way of organization screens in an application is that each screen feels narrow. Worse, most screens seem to use a small font. This seems to be true of all of the apps, from the built-in ones by Microsoft to the big-name ones like Facebook, Netflix, Foursquare, and Twitter. I have a much harder time reading text on these apps than I do on their Android or iPhone cousins. I think WP7 is to blame here, these apps are consistent with the platform and that's why they make me squint.

That last paragraph is clearly influenced by my experience with writing code for WP7. However, I would say that the development situation on WP7 is generally pretty good. The worst part is the "getting started". For me this involved installing Windows 7 on my MBP. I already had Parallels on there fortunately, but not Win7. Once I had Win7 running under Parallels, I followed the WP7 getting started guide. I was a little annoyed to see this involved a three-step download/install process. First download the WP7 developer tools. Then install the WP7 developer tools January 2011 update. And then install the WP7 developer tools fix! Really? Why in this not all one download? Why does that third download even (the "tools fix") even exist?

I've always thought that the Android tools installation process left a lot to be desired. But at least they had a reasonable excuse that IDE support was optional. So you could just install the SDK, but you had additional steps if you wanted to use either Eclipse or IDEA (and you got options here, which is nice.) Things are much better on iOS, but there are a lot less options there. WP7 is the worst of all worlds, as there are no options, but you have three installs including a "fix". Oh wait there are options, but they are for using Visual Basic which also requires that you use the "Pro" version of the tools. I'm not a big fan of an up-sale when it comes to developer tools. Do you want me to build for your platform? Make it easy and make it free until I want to publish something.

So there's my big gripe with the tools. Otherwise they are very good. If you've ever used Visual Studio, you know that it has a lot of nice features. The book mentioned earlier is a good companion too. Of course when you tie development so closely to a tool, then a book gets old fast, but for now it works. I wrote a neat little program that downloaded and parsed some XML and then used data binding to show the results in a list. Tapping on items in the list could bring up more information or open an external browser link. It was sweet and the tools made the development go by fast. I think this (along with the tightly integrated designer tools) may be WP7's biggest asset. There is no doubt in my mind that if you want to build some very "standard" looking apps, you can do it much faster on WP7 than on Android or iOS. It's not even close.

However the tale of the tools does not have a happy ending. I got my little app to run on the emulator, and I was pleased that the emulator loaded quickly and was responsive. However I don't trust emulators (and you should not either), so I was eager to run the app on the LG Quantum. However when I tried, I got an error saying "Zune software is not installed." Lucky for me that developing for WP7 was just a hobby, so I could laugh at this WTF error.

I have one last critique of WP7, and actually this came from Matt Trunnell. He's a bad-ass WP7/Silverlight developer who works for Netflix and wrote their WP7 app. We met at the MS event I mentioned at the beginning and shared with me some of his perspectives on WP7. I stated that I thought that MS seemed to be trying to "out Apple, Apple". What I meant was that they had followed Apple's lead on most issues, from how the OS ran, to what developers could do, etc. However Matt made me realize that I was wrong about this. He pointed out that MS had really done a lot of "triangulation" where they had tried to find middle ground between how Apple and Google had done things. An example of this is the multitasking in WP7 (well coming this fall to WP7.) MS adopted the pseudo-multitasking (fast app switching) of the iPhone, but also included "Live Agents" that could run in the background, but only in a limited way that is beyond the developer's control.

I think I have become immersed in the Android world so much that Microsoft's triangulation seemed like being very Apple-ish to me. But Matt was right on. MS has very consistently tried to "learn" from Apple and Google and come up with a best-of-both worlds approach. There are some very good things about this kind of strategy (you *should* learn from your competitors) but ultimately it is frustrating. Everything always seems second-rate.

Tuesday, April 05, 2011

Fragmentation? What fragmentation?

Fragmentation is a fun word to use in the mobile space. The devotees of Apple and the iPhone delight in the term because it makes Android aficionados cringe. Heck even the executives at Apple use the term at every opportunity. Some of the folks on the Android team deny it exists. However in a recently published study, most Android developers say it is a real problem. So what's the deal?

As with so many other contentious things in this world, a lot comes down to how you define something. If you write an Android application, you will have to test it on multiple devices. So I will use this as my definition of fragmentation. So obviously Android suffers from fragmentation. Here is a simple example of it:

HTC Thunderbolt winning

This is a screenshot of an app running on the HTC Thunderbolt. According to some folks, it is selling quite well. What's the point of the screenshot? Well take a look at the text field right below the "Your phone number" prompt. Here is the code for it:

<EditText
	android:layout_height="wrap_content"
	android:layout_width="fill_parent"
	android:id="@+id/entry_phone"
	android:textStyle="bold"
	android:inputType="phone"
	android:imeOptions="actionNext"
/>

See the problem? WTF is up with those zeros in the field? They clearly should not be there. This was the only phone I could find that produced this problem, but I will have to add code just to deal with this annoyance. This is fragmentation. Code has to be tested on many devices, and you may have to put in some device-specific things to get the app to work the same.

Now don't be fooled, fragmentation exists on all mobile platforms. Yes, even iOS. There is less of it, but it is not insignificant. Fragmentation is quite prominent on almost all application platforms. Do not get any web developer started about IE specific CSS for example.

So it is a huge problem on Android? My answer to that question is irrelevant, as the perception that it is a problem is all that does matter. I think this perception is completely reasonable. Many Android developers were programming for the iPhone in the past, and were used to testing on a single iPhone and nothing else. Thus Android seems arduous.

Friday, March 18, 2011

My Last Day at eBay

This is The End

Today is my last day at eBay. I have been there for nearly four years and it has been a remarkable experience. When I joined eBay, I had come from a startup called Ludi Labs. One thing I realized while at Ludi Labs was that "scalability" was largely a hypothetical term to me. I thought I understood the keys to making an application function at web scale, but it unfortunately it was very theoretical knowledge. None of the startups I had worked at had ever really hit that kind of scale. Hence my interest in working a large scale web company, like eBay.

Four years later and I realize how very limited my theoretical knowledge of scalability really was. Sure I understood the basic principles, but there are definitely many subtleties involved in implementing these principles. I won't now claim to be a scalability expert, but I have certainly learned some real world lessons.

When I first joined eBay, I worked with the infrastructure team on eBay's homegrown presentation technology. A lot of this technology was based on what works at scale: high volume web pages, working in dozens of different languages, running on servers spread across multiple data centers, and built by hundreds of engineers around the globe. I went on to help many of the different teams at eBay adopt and optimize their use of eBay's presentation technology. As such I got opportunities to work on many of the major pages of eBay: home page, search results, view item, my eBay, just to name a few. Often my experience was limited to helping the team solve some site speed issues, but I still got a chance to understand how each of these highly complex web pages could function at massive scale.

Of course the last couple of years of my career at eBay was dominated by mobile. It's been an exciting time, as our mobile team saw massive growth both in terms of users and their usage (measured using the best possible metric: money) as well as in terms of the team behind the technology. It's had some great moments as well, such as seeing eBay named by Fast Company as the #2 most innovative company in mobile.

This leads to the obvious question of why I am leaving eBay. The future for mobile at eBay is very bright. However it's one of those cases where the change is not about where I'm coming from, but about where I'm going. In this case that's Bump Technologies. I'm very excited about the opportunity at Bump. They already have a great product that they've built in just two years. However, I think that two years from now the current product will look very limited in comparison. It's going to be an exciting time.

Wednesday, March 02, 2011

Honeycomb Drag and Drop Basics

If you are thinking about developing an Android tablet app, one of the most exciting things has got to be the drag and drop capabilities that were added to Android as part of Honeycomb. No wait a minute, aren't there a lot more interesting features than drag and drop in Honeycomb? There are definitely a lot of great features, but drag and drop is one of the most interesting in my opinion. It's a perfect fit for tablets, where you can have this nice big graphical objects to drag and drop. I think it really challenges mobile designers and developers to rethink our interaction models. If you read through that tutorial I just linked to, you will learn about many of the intricacies of drag and drop Android style. I thought I'd provide an even simpler example for those of you who prefer the Cliff Notes versions of things.

First we will start with a simple UI, a 2x2 grid with a cute little image that we will drag and drop around this grid. Here is what it looks like:

DnD UI

I used a simple TableLayout for this, along with some basic border background Drawables. Here's the XML for it:

<TableLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <TableRow>
    <LinearLayout android:layout_width="640px"
        android:layout_height="345px"
        android:id="@+id/topLeft"
        android:background="@drawable/border">
        <ImageView android:id="@+id/droid"
            android:src="@drawable/bugdroid"
            android:layout_width="150px"
            android:layout_height="150px"
         />
    </LinearLayout>
    <LinearLayout android:layout_width="640px"
        android:layout_height="345px"
        android:id="@+id/topRight"
        android:background="@drawable/border2"
    />    
  </TableRow>
  <TableRow>
    <LinearLayout android:layout_width="640px"
        android:layout_height="345px"
        android:id="@+id/bottomLeft"
        android:background="@drawable/border2"
    />
    <LinearLayout android:layout_width="640px"
        android:layout_height="345px"
        android:id="@+id/bottomRight"
        android:background="@drawable/border"
    />    
  </TableRow>  
</TableLayout>

Nothing special so far. All of the magic happens in the code. Here's the basics of the Activity that uses this XML.

public class DndActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.grid);
  View droid = findViewById(R.id.droid);
  droid.setOnLongClickListener(new OnLongClickListener(){
   @Override
   public boolean onLongClick(View v) {
    ClipData data = ClipData.newPlainText("foo","bar");
    DragShadowBuilder shadowBuilder = new DragShadowBuilder();
    v.startDrag(data, shadowBuilder, v, 0);
    return true;
   }
  });
  findViewById(R.id.topLeft).setOnDragListener(new BoxDragListener());
  findViewById(R.id.bottomLeft).setOnDragListener(new BoxDragListener());
  findViewById(R.id.topRight).setOnDragListener(new BoxDragListener());
  findViewById(R.id.bottomRight).setOnDragListener(new BoxDragListener());
 }
}

Here we just set the contentView, then we get a handle on the droid image. We set its onLongClickListener. I think the long click will become the de facto way to initiate drag and drop in Android apps. You could use some other event of course, but long click feels right. The key thing we need to do to initiate drag and drop is invoke the startDrag method. To do that, we have to create a ClipData object and DragShadowBuilder. You can use the ClipData to put all kinds of interesting data/metadata that will be passed around to the drop zones (Views) in your app. In this case I didn't need anything fancy, so I put something minimal and arbitrary. For the DragShadowBuilder, you might want to do something fancy to make the dragging look cool. I used a default one and it doesn't do much at all. You also need to set a "localData" object. This can be anything. Since my local data is the image itself, I chose to pass the ImageView that will be passed in to the onLongClick method. Now you can call startDrag. Finally, make sure you return true to let the OS know that drag and drop is a go.

Next in the code you will see that for each of the cells in my table, I have set an OnDragListener object. I've set this to a new instance of BoxDragListener for each of the cells. This is an inner class of DndActivity:

class BoxDragListener implements OnDragListener{
 boolean insideOfMe = false;
 Drawable border = null;
 Drawable redBorder = getResources().getDrawable(R.drawable.border3);
 @Override
 public boolean onDrag(View self, DragEvent event) {
  if (event.getAction() == DragEvent.ACTION_DRAG_STARTED){
   border = self.getBackground();
   self.setBackgroundDrawable(redBorder);
  } else if (event.getAction() == DragEvent.ACTION_DRAG_ENTERED){ 
   insideOfMe = true;
  } else if (event.getAction() == DragEvent.ACTION_DRAG_EXITED){
   insideOfMe = false;
  } else if (event.getAction() == DragEvent.ACTION_DROP){
   if (insideOfMe){
    View view = (View) event.getLocalState();
    ViewGroup owner = (ViewGroup) view.getParent();
    owner.removeView(view);
    LinearLayout container = (LinearLayout) self;
    container.addView(view);
   }
  } else if (event.getAction() == DragEvent.ACTION_DRAG_ENDED){
   self.setBackgroundDrawable(border);     
  }
  return true;
 }
}

This guy will get a stream of DragEvents fired at its onDrag method. You can determine what kind of DragEvent it is by calling getAction on the event. The first one you will get is an ACTION_DRAG_STARTED event. For this we want to change the border of our cell to red to let the user know that they can drop the image in this cell. Here's what that looks like:

Enter the red zone

Next we want to keep track if the user's finger has entered into a drop zone. So we look for the ACTION_DRAG_ENTERED and toggle a local boolean. Similarly, we look for ACTION_DRAG_EXITED in case the user changed their mind and picked a different zone to drop the image into. Next we look for the ACTION_DROP. If the object is inside our drop zone, then we update the UI by removing it from its previous parent and adding it to the drop zone. Finally, we listen for ACTION_DRAG_ENDED to know when the drag and dropping is finished. We then restore the borders to their original color. That's it!

Update: The code above will not draw a shadow when you drag the image around the screen. There is a very easy way to get a shadow and that is to pass the View to it the DragShadowBuilder constructor, i.e. new DragShadowBuilder(v); in the above code. That will cause the image in the sample app to be used as the shadow. Be careful using this technique though. If the View that you are dragging is big/complex, then you might take a performance hit (UI becomes sluggish.) In that case you might want to subclass DragShadowBuilder and override its onDragShadow method to draw something simpler for the shadow. I've been playing around with this and StackViews however, and it has worked great with no need to subclass DragShadowBuilder. Be sure to set the android:hardwareAccelerated="true" attribute in your AndroidManifest.xml either on the Activity or the whole Application.

Friday, February 18, 2011

Why I Won't be Voting for President Obama in 2012

I voted for President Obama in 2008. My reasons were a little different than most. Given that and one look at this chart, it should be no surprise that he won't be getting my vote in 2012.

Money Spent on War

Seriously, if McCain had won do you really think this chart would look a lot different? The withdrawal of US troops from Iraq was widely hailed, but it has been made up for by increasing troops in Afghanistan and using more private military companies (mercenaries) in both Iraq and Afghanistan. Fool me once, shame on you; fool me twice...

Ginger Honey Ice Cream Mess

A few nights ago I was working at the Silicon Valley Android Meetup. eBay was hosting the meetup, and I had volunteered to help with the registration table. One of my co-workers was talking about how very few people had brought business cards with them to the event (there was a raffle and you could use your business card to enter it), and I commented that business cards were antiquated. I mentioned Bump as one of many more sophisticated alternatives. She quickly downloaded Bump to her Android phone, and we attempted to ... well ... Bump. We had a hard time mainly because the accelerometer on her phone was not very sensitive.

She remarked: "I really need a new phone."

I asked: "Yeah what's that thing running, like Android 1.6?"

She replied: "I wish, it's actually 1.5."

Now I was actually kind of amazed that Bump even worked on a 1.5 phone. But before I could make some witty comment about her phone...

She asked: "What is the latest version anyways?"

I replied immediately: "2.3"

She gasped is disbelief: "Holy crap, I've only had the phone for a year or so. Do they release a new version of Android every month or something?"

Who can blame her for her dismay at the velocity of Android? She went on to curse the phone maker (Samsung) and network (Sprint) for not putting out an update (though I think they did, but not OTA? Anyways, you should be able to guess the model now.) Of course who can blame handset makers and carriers for being slow to put out updates, again given the pace of Android. As soon as you get done getting one version ready to ship, another one comes out.

Of course that's part of the fun from a developer standpoint. And part of the pain -- a big part. However the mach speed evolution of Android in the past is starting to look downright soothing compared to the thinny before us. Let's recap briefly

In December 2010, Google announced Android 2.3 a.k.a. Gingerbread. This seemed all well and good at the time. Android 2.2 (Froyo) came out half a year earlier, so this seemed like a reasonable amount of time between releases. Of course we would later learn that the Android team was not pacing themselves, the long time between releases was a fluke. Anyways, the timing still seemed a little odd, as it was right before the holidays. The Nexus S was simultaneously released and it was running 2.3. Still there was no way any other Gingerbread running devices would be out in stores for the holiday season. Also, there seemed to be a lot of oft-rumored stuff missing from Gingerbread.

In early January (a month later), Android 3.0 a.k.a. Honeycomb was previewed at CES. Videos of Honeycomb in action were posted to YouTube. Three weeks later, a preview version of the SDK was made available to developers. It had a lot of the new UI features that had been rumored for Gingerbread. However, it didn't just bolt on new features or refine existing APIs. It added some very core fundamental things. There were Fragments: a new (better?) way to organize your application code. There was the app bar: a persistent UI element at the top of the screen where contextual extras could be placed. The app bar is what the menu should have been (nobody uses the menu.) There was also the system bar at the bottom of the screen. This is not directly accessible to developers, however it is where Honeycomb's new more powerful notifications originate from. Android already had the best notification system out there (sorry webOS and your new imitator, Windows Phone ... and iOS is not even in the conversation), but now you get notifications that the use can interact with without interrupting what they were doing. Anyways, 3.0 is a release unlike any other in Android's history, but mostly in a good way. However it was billed as being just for tablets, leaving us with two different "latest" versions of Android.

In February (just this week) we get comments from exiting CEO Eric Schmidt that Gingerbread and Honeycomb were merging together in the "I" release of Android. This was release has been "known" to be Ice Cream Sandwich for awhile. Would it be Android 2.4? Would it come out at Google IO?

But wait, it gets better. Apparently Android 2.4 will be released before Google IO, and it will not be Ice Cream Sandwich. We will have to wait for the sandwich until later in the year apparently.

So what the hell is going on? First let me say this. I have been using a Nexus S for about a month now. When it works (which is most of the time), it is fantastic, easily the best phone I've ever used. However, it is also the buggiest phone I have ever used. I've never had the reported spontaneous reboot happen to me during a call (by the way the call quality is excellent, the best I've ever had in a smartphone.) However, I often have to reboot it myself because it just hangs during a call. Or it will suddenly lose its network connection and never get it back until ... I reboot it. Or it will stop receiving email (service probably crashing and the OS putting it out of its memory I'm guessing) until ... I reboot it. Since this phone is very similar to the Galaxy S in terms of hardware, I am guessing that this is mostly a software issue. And since this baby is running "stock" Android, that makes it a Gingerbread issue. Maybe this explains why 2.3 has not been released to any phone? Maybe this explains the need for yet another major release before the Ice Cream Merge?

Besides the 2.3 issues, most of the rest of the craziness comes from the need to go after tablets in a big way. That's why a lot of in-flux, potentially undercooked code is being pushed out so quickly. That's why we all get to see git repo being forked and merged in such a public manner. Software development is scary and messy more often than not.

So back to the scorecard. It makes sense that 2.4 will not be Ice Cream Sandwich. It can't include the Honeycomb features and yet have a lower release number, right? Perhaps Ice Cream Sandwich will be 3.1, later this summer. Or maybe it will be 3.2, as I would not be surprised if there were a massive bug fix release after 3.0, given its obviously rushed nature. So maybe we can go 2.3, 2.4. 3.0, 3.1, 3.2 all in the span of what, 6 or 9 months? Yee haw!!

Sunday, February 13, 2011

Wither the Dashboard Pattern

Recently I barely managed to register for this year's Google IO conference. One of my favorite sessions from last year's conference was on UI patterns in Android.

It's a great video, you should definitely watch it. The first pattern that they talk about is the Dashboard. You can see their example of a dashboard in the video, but there was an even more concrete example: Twitter for Android. The Twitter app was released just before IO, and it was developed jointly by Google and Twitter. It showcased the UI patterns that Google wanted designers and developers to start using to help create some expectations for users. Here's the Twitter dashboard:

Ye olde Twitter with dashboard

The idea is simple. The home screen of your app provides shortcuts to all of the major components of the app. The combination of using this pattern in a popular app (Twitter has 5M+ downloads) and evangelizing it at the IO conference certainly had the desired results. Many other apps adopted the pattern, including every platform's most popular app, Facebook:

Facebook's dashboard

The pattern has been a hit with note-taking/organizer apps like Evernote:

Evernote's dashboard

Evernote's more recent competitor Springpad also uses a dashboard:

Springpad's dashboard

Evernote and Springpad are both popular apps, with more than 1.5M downloads between them. Another very popular app that uses the dashboard is Yelp:

Yelp's dashboard

Google's Yelp/Foursquare compettitor Places also uses the dashboard pattern:

Places' dashboard

Finally, there's my favorite Android music player MixZing:

MixZing's dashboard

MixZing shows that you can be a little creative with the dashboard pattern. So the pattern's been a big success, right? Users are familiar with it and developers have embraced it. So it was a little surprising to me to see that Twitter has now decided that the dashboard is not so good after all:

New Twitter, sans dashboard

There's no more dashboard in the 2.0 version of Twitter's app. The release notes allude to the major problem with the dashboard pattern: it forces the user to constantly go to the dashboard if they want to navigate to a different part of the app. It makes everything at least two taps away. Of course it makes it easy for the user to find things, since they can just go to the dashboard to find a shortcut to whatever they are looking for. For example, how do you think you find what's trending on the Twitter app now (go to search) or view your profile (gotta use the dreaded Android menu)? Maybe Twitter has found that their users rarely use these features, so the new design will be more effective for the vast majority of their users.

Speaking of the new design, it obviously uses a tab layout. This is a more common UI pattern in Android and has its own set of APIs to make it easy to use for developers. There are a lot of examples of tab layouts out there, such as Foursquare:

Foursquare likes tabs

Another example is one of my favorite apps, Bump:

Bump likes tabs

I won't bore you with more examples, as there are a lot. I think it's often very comfortable for a web app going native to use a tab design. It often mimics their website. That's why I picked Foursquare and Bump, two apps that are what I would consider mobile-first. Most people's first interaction with either company is through their mobile apps, not through their desktop web browser.

The other common pattern worth mentioning briefly is what I call Listomania. You start off with lists, and keep going from there like traversing a tree. Here's Google Reader:

Google Reader likes lists

And here's Kayak's listomania:

Kayak likes lists

Personally I don't find the Listomania format very user friendly. I think it is often a by-product of porting an iPhone app that makes heavy use of UINavigationControllers (in all fairness, many of the tab-using Android apps are the products of porting iPhone apps that used a UITabBarController). I think the dashboard usually solves the same kind of problem (lots of features, hierarchy) in a nicer way. The tab alternative is more of the Pareto principle, putting all of the focus on the most commonly used features. Anyways, it will be interesting to see if the dashboard pattern becomes less common now that it's poster-child has ditched it.

Friday, February 11, 2011

Android Notifications, C2DM, and The Way to Succeed and the Way to Suck Eggs

When it comes to Android Cloud-to-Device Messaging, I've found many new and exciting ways to fail and fail hard. So y'know, learn from my failure and stuff:

State: To Have or Not To Have, That is The Question

There are a lot of cool things you can do with C2DM, but of course notifications are one of the most common and most important things. Now remember that unlike on other inferior platforms, you get total control of what happens when a message is pushed to your application via C2DM. So you don't have to show a notification at all. In case you do though, the first thing you need to decide is if your notifications will be stateful or stateless.

What's the difference? Glad you asked. Let's take a simple scenario. A message is pushed to your app via C2DM, and you display a notification to the user. Now Android notifications do not force the user to either open or dismiss the notification. In my opinion that is a very good thing, and I think most folks agree. You might really be interested in a particular notification, but sometimes you've just gotta finish that game of Meteor Blitz or finish posting a crazy picture to picplz. That's not a problem on Android. The sound will go off, the ticker text will scroll across the status bar, and then a simple icon will appear up there and the user can deal with the notification at their convenience. However, let's say that a few minutes later that another message is pushed to your app via C2DM and once again you need to notify the user of this. If you choose a stateless system, then you will simply replace the current notification about message #1 with a new one about message #2. Alternatively you could post a new notification about message #2 that would sit along side the notification about message #1. However if you do this, then you are a schmuck. You've just created an application that can potentially flood the status bar with your notifications. Your app would have be to all kinds of awesome for me to keep it on my phone, especially if I can't turn off your notifications. So don't do that. So really there's only one option if you want to go stateless: most recent notification always wins and anything older goes to the trash.

Don't like that approach? Me neither. That first notification might have nothing to do with the second, and it might be more important. So that means we need to go stateful. With a stateful system, we can remember that we received message #1, and then replace it with a notification that indicates that we have received message #1 and message #2. How you do that will be very specific to your application of course, but you can figure something out. The point is that you persisted the state, that you had received message #1 and it has not been viewed yet, and you use this knowledge to provide a better experience for the user when message #2 rolls in. Of course now the real fun begins.

Watch out for the Clear Button

You need to not only keep track of the messages that you have received via C2DM, but also their state. Has the user seen them or not? What constitutes "seen" is again specific to your application, but it just means that at various places in your application you will need "mark as seen" for certain messages. There is gotcha here and that is the "Clear" button on the status bar. That should have the effect of marking all messages as seen. However, how do you know when the user taps this button? I thought that maybe there was an Intent fired and that I could receive this with a BroadcastReceiver with the proper action/Intent filter. I searched the docs and found no such action, but I still thought that this was probably the case and it was just not documented (there are a lot of such Intent/actions!) I was so stumped that I posted a question on StackOverflow and offered a 50 reputation point bounty. Turns out there is a very simple answer: the deleteIntent field on the Notification object. Talk about face-palm... Anyways you can set a PendingIntent here, and that PendingIntent can start a Service that does the "mark all as read" work for you.

Badging

Android provides a really easy way to badge your notification icons in the status bar. If you just set the number field on the Notification object, you get badging for free. However, badging looks a little ugly, and if you only have one message then you probably don't want it. In that case just don't set the number field and you are good to go. Then the next time a new message comes in, set the number field to 2. Try this out and rut it on your phone. Unless you have a Nexus S, you will notice a problem. The badging will not show up when you set the number 2 (or 3 or 4 or whatever.) This appears to be a bug with Android that was fixed in 2.3. That's why it works correctly on a Nexus S, but not on anything else (the NS is the only phone with 2.3 as of the time I wrote this.) So what do you do? Badge with a 1? Ugly. Don't badge at all? Less informative. The correct answer is workaround.

Actually you might get lucky and do it the "right" way to begin with. What I did was create a Notification with the same ID as the existing Notification, and then simply call notify on the NotificationManager service. That should replace the existing Notification with the new one, and you should get the right badging. This is the case on my Nexus S, so I'm guessing it's the case on Android 2.3+. This is not the case on previous versions of Android. Everything about the old Notification is replaced except for the badging. The work around is to remove the old Notification (using the cancel method on NotificationManager) and then create the new one using notify. That will work on all versions of Android.

Collapse Key

If you read the C2DM documentation, one of the seemingly innocuous things that it mentions is the collapse key. It says this is "An arbitrary string that is used to collapse a group of like messages when the device is offline, so that only the last message gets sent to the client. This is intended to avoid sending too many messages to the phone when it comes back online." Doesn't this sound like this is for the C2DM servers, so they can throttle the messages being sent to your app? Maybe so, but I found that it come in handy on the app as well, as C2DM passes it on to the app. The reason is simple. You may get the same message from C2DM twice. Well I suppose it might even come more than twice, but what's the difference? Regardless you should expect that dupes might be sent, and so you should de-dupe. The collapse key is perfect for this. A good way to keep track of these is to use a static HashMap (depending on how you implement the Service that processes the C2DM messages, you may not be guaranteed that there will only be one instance of that Service, hence a static HashMap) with soft keys, so that if it grows too large the GC will toss old collapse keys that you don't need anymore.

The Static Starter Pattern

One of my favorite things about Android is that it is not another MVC framework. Now some people find this as a weakness, but not me. I think MVC has its faults. Still many people think of application in terms of MVC, and for them Android's Activity class is as close to a controller as you will get. Pretty much every "screen" or "page" in an Android application has a single Activity behind it (there are exceptions, I know, but bear with me.) Inevitably you need to transition between Activities, and this is one of the places where Android can seem a little weird. You need to create an Intent and then pass that to the startActivity method on a Context object (usually the Activity that you are transitioning from.) That's not too bad. However, it is often the case that a given Activity expects some data -- a model if you like -- that it will use to create the UI (the view if you like.) Let's take a concrete example from Android in Practice. The MediaMogul application (chapter 11) allows the user to create a slideshow by selecting pictures, music, and video from their SD card. Then there is an Activity that plays the slideshow called SlideshowActivity. Here is code from the Activity that starts the SlideshowActivity.
Intent intent = new Intent(this, SlideshowActivity.class);
intent.putExtra("videoUri", videoUri);
intent.putExtra("imageFileNames", images);
intent.putExtra("selectedSong", song);
startActivity(intent);
And here is code from SlideshowActivity to retrieve this data:
Intent intent = getIntent();
ArrayList<String> images = intent.getStringArrayListExtra("imageFileNames");
Song song = intent.getParcelableExtra("selectedSong"); // custom Parcelable class
Uri videoUri = intent.getParcelableExtra("videoUri");
There is an obviously ugly issue here. Both Activities need to know the keys (imageFileNames, selectedSong, videoUri) to use to put/get from the Intent's extras. This is such a common thing in Android, even in the framework, that there is a simple pattern for dealing with it. Just use public constants declared in the class that will use the Intent extras:
public class SlideshowActivity extends Activity{
public static final String EXTRA_IMAGE_FILE_NAMES = "imageFilesNames";
public static final String EXTRA_SELECTED_SONG = "selectedSong";
public static final String EXTRA_VIDEO_URI = "videoUri";
...
Intent intent = getIntent();
ArrayList<String> images = intent.getStringArrayListExtra(EXTRA_IMAGE_FILE_NAMES);
// etc.
And then of course in the calling class you would now have:
intent.putExtra(SlideshowActivity.EXTRA_IMAGE_FILES_NAMES, images):
// etc.
Problem solved, right? Well not exactly. You still don't know what the types of the extras should, and you do not know if a particular extra is required or optional. Documenting your code can help with this:
public class SlideshowActivity extends Activity{
  /**
   * An ArrayList of Strings. Required.
   */
  public static final String EXTRA_IMAGE_FILE_NAMES = "imageFileNames";
...
}
So we put the type information and wether the field is required or not as a comment. Wait, doesn't this feel more like Ruby or Python instead of Java? Isn't there some way to use the language syntax and compiler to state this information in a better way instead of relying on code comments? That's where the Static Starter Pattern kicks in:
public class SlideshowActivity extends Activity{
  public static void start(ArrayList<String> images, Song song, Uri videoUri, Context ctx){
    Intent intent = new Intent(ctx, SlideshowActivity.class);
    intent.putExtra(EXTRA_IMAGE_FILE_NAMES, images);
    intent.putExtra(EXTRA_SELECTED_SONG, song);
    intent.putExtra(EXTRA_VIDEO_URI, videoUri);
    ctx.startActivity(intent);
  }
...
}
From this method signature, I know the types of all of the extras and I know that they are all required. If I wanted to make one of them optional, then I could simply overload the start method with only two of the parameters, removing the optional parameter. Of course, somebody could bypass this and still use an Intent.
Now this is not the best pattern for every Activity. The most obvious example is if you want your Activity to be started by other applications. Another application won't be able to invoke a static method. You will have to use the action/Intent-filter path for this. Of course this is pretty rare, how many of your Activities are meant to be started by other apps? Even if this is the case, you can still use the pattern for use within your app.
This pattern is also not limited to Activities. You can do it with Services as well, especially IntentServices:
public class AwesomeService extends IntentService{
  public static void start(String someString, int someInt, Context ctx){
    Intent intent = new Intent(ctx, AwesomeService.class);
    intent.putExtra(EXTRA_SOME_STRING, someString);
    intent.putExtra(EXTRA_SOME_INT, someInt);
    ctx.startService(intent);
  }
}
If your IntentService handles multiple actions, this can be built into the pattern:
public class AwesomeService extends IntentService{
  public static startUploadFile(String someFileName, Context ctx){
    Intent intent = new Intent(ctx, AwesomeService.class);
    intent.setAction(ACTION_UPLOAD_FILE); // ACTION_UPLOAD_FILE is a constant
    intent.putExtra(EXTRA_SOME_FILE_NAME, someFileName);
    ctx.startService(intent);
  }
}
You get the idea. You could extend this to BroadcastReceivers as well. I discussed this pattern a bit with my Android in Practice co-author, Charlie Collins. He liked it too, and pointed out that others have used it as well. Personally, I'm not a fan of static methods or of passing around the Context like that, but the positives seem to outweigh the negatives. What do you think? Useful? Over-engineered?

Monday, February 07, 2011

Some More Nexus S Comparisons

My last post about buying a Nexus S led to some interesting comments ... on Google Buzz of all places. Actually it was retweeted, I mean rebuzzed? err reposted by my friend Robert Konigsberg at Google... Some of the points there were about comparing the NS and the N1. I argued that the NS had a much better processor (because of its integrated GPU) as well as having the best screen on the market right now. I also incorrectly stated that it had more RAM than the N1, but actually both of them have 512 MB. Here are a few more notable comparisons:

The NS has 1 GB of "internal storage", but this actually part of its non-removable 16 GB of storage. The N1 has 512 MB of internal storage. As many apps only allow you to install them on internal storage (especially any app that has a homescreen widget because of this bug), you have twice as much space for such apps on the NS. However, you cannot upgrade the 16 GB. The N1 has only 4 GB included, but you can upgrade it. In fact, I had already upgraded it to 16 GB.

The biggest thing that I forgot to mention is the reception (both voice and data) on the NS. To me, the N1 and the iPhone 4 both got similar reception -- and that is horrible. The iPhone 4's poor reception is well documented, but I think the N1 was just as bad. If you consider that T-Mobile's network is a step below AT&T's, you get a nasty combination. The NS has much better reception than either of these phones. For that matter, it is much better than any other iPhone I have used (3G/3GS). I'm talking about consistently getting two more bars than the N1, and much clearer and louder reception on the phone. It seems obvious that the use of metal in the outer casing is the key here. Both the iPhone 4 and N1 use metal to destroy your reception.

Some folks have also asked me about battery life. I would say that the NS is slightly worse than the N1, and about the same as an iPhone 3GS. That makes it definitely worse than the iPhone 4. The most obvious culprit here is the screen. Bigger screen = more juice. I came across this amusing blog about switching to the Nexus S from an iPhone. This included a complaint about using the power widget to turn off Bluetooth, Wi-Fi, and even GPS on the phone in order to save battery life. This was kind of shocking to me. As an iPhone user, I almost never turned on Wi-Fi and kept Bluetooth off except when in the car. I had to do this on the 3GS, or I would not make it through the day on a single charge. In fact one of the things that I love about Android is how much easier it is to do these two tasks than on iOS. In fact I always thought that this was a big miss by Apple, but I guess that most people actually leave that stuff on all of the time? I don't understand how anyone who uses their phone much, especially if they receive lots of push email, could get away with leaving all of that stuff on all of the time and not run out of juice by 3 PM. I never tried to do this with the iPhone 4 and its awesome battery, just because I was so used to managing the power on my device. Similarly, I can't imagine NOT charging my phone when I go to bed every night. Anyways, if I manage the Wi-Fi and Bluetooth and charge each night as usual, then the Nexus S makes it through the day easily for me. If I play a lot of games on it or use it as a mobile hotpost, that changes things noticeably.

Finally, some folks didn't like that the NS does not have the glowing trackball that the N1 did. I liked the trackball on the N1. The LED lights weren't that useful, since I get email constantly. Still if I got a blue light, I would know that I got something from Facebook. The trackball was especially useful when there were small parts of the screen that needed to be tapped on. However, I have not found myself missing this on the NS, partially because the screen is bigger, but mostly because the touch accuracy on the screen is very good. I always found the N1 to be slightly worse than the iPhone 4 (which I think is slightly worse than the iPhone 3GS) when it comes to touch sensitivity/accuracy. I think the NS is a little better than the iPhone 4, about as good as the iPhone 3GS.

Thursday, February 03, 2011

Moving on

Recently I was in Los Angeles and took a cab from the airport to my hotel. When I got out of the cab, I left my iPhone 4 in the car. I called the cab company, but they were of no use. I had lost my iPhone. And no, I didn't have the Find My iPhone feature enabled on my iPhone. It's actually a pain to do that, if you don't use MobileMe.

Fortunately being a mobile developer, I had another phone with me, my Nexus One. I've been carrying two phones for awhile. I only used apps on the N1, and mostly just phone features on the iPhone (not a good use of an iPhone, especially the iPhone 4.) I stuck with most of my app usage on the N1, since I thought it would make me a better Android developer. Now all I had was an Android phone.
I moved my phone number to the N1, which was on T-Mobile. Just so you know, I immediately got hit with the dreaded early termination fee. I didn't get an option to keep paying for the line of service.
So now I was in no-contract land, and I had a lot of options. I could buy another iPhone, even one on Verizon. I could wait until some of the new Android phones announced at CES were out. I was in no hurry because I had my N1. Instead of doing those things, I decided to buy a Nexus S. Here's why.

I think the Super AMOLED screen is by far the best out there. I had the iPhone 4 for six months, and I wasn't very impressed with the Retina Display. You can't make use of all of those pixels on such a small screen. Yes text looks great, but the colors are washed out and I definitely noticed that a lot more than the awesome text rendering.

I love that the Nexus S runs stock Android. No crap on it. I dislike SenseUI. I can tolerate TouchWiz, but I'm no fan. There are also no carrier crap, like the NASCAR app on Sprint 's phones. The only disadvantage of stock Android is the camera app. In comparison, I think the camera app on the Galaxy S and Galaxy Tab is excellent. But hey it's Android, I can always customize.

I thought about getting a 4G phone. However I don't think it's worth it. Especially since I get to use the Nexus S's wireless hotspot feature for free. Plus I think all phones suffer when they transition from 3G to edge, and I think that problem would be much worse with 4G which will be spotty on any network for awhile.

Obviously the Nexus S is ideal for a developer as well. So the Nexus S it is! In fact, I wrote this blog post on it.

Saturday, December 11, 2010

The Tablet Wars Have Begun

A few weeks ago I picked up a Samsung Galaxy Tab. Being an Android developer, I thought it was a good idea to see how my apps as well as other apps function on the Tab. After all, it’s hard not to remember what it was like for iPhone developers when the iPad came out. iPhone apps run on the iPad, but they are virtually unusable. They either look ridiculously small, or you can “2x” them and they look like crap. So there was (and is) a lot of pressure on iPhone developers to port their apps to the iPad. Would the same thing hold true for Android developers and the Tab?







I am pleased to say that this is not the case for the Galaxy Tab. Most Android applications look good on the Tab. In fact, I would say that most of them look great. The extra real estate only adds to things. Now there are cases where the apps could make better use of space, or maybe their buttons look a little too big on the Tab. However these are minor issues compared to what it is like to run an iPhone app on an iPad.

That being said, there are some apps that suffer on the Galaxy Tab. Notably some popular weather apps (The Weather Channel’s app, Weather Bug) looked bad on the Tab. However in subsequent weeks these apps have released updates that now look good on the Tab. During that time ESPN’s Scorecenter app also released an update. The previous version of the app looked fine on the Tab, since it relied heavily on ESPN’s mobile website. The update brought a more native UI with less reliance on mobile web. However, it has some serious layout issues and looks bad on the Tab.

So why is it that most apps look good on the Tab, but a few do not? Is it something inherent to Android vs. iOS? Well, yes and no. It is not really anything inherent to Android the OS or Android the SDK. However, Android is designed to work on different sized screens and always has been. As a developer, you are given many choices for creating the layout of your UI, but you are encouraged to use relative/flow-based layouts. These are fluid and resize beautifully on different sized screens. So you take those apps and drop them on to a tablet, and they look just as good.

Of course you don’t have to use these kinds of layouts. You can use layouts that are more fixed and absolute -- which is the norm for iOS developers. However, then you run into Weather Bug and ESPN style problems. Their developers can make adjustments to make their apps look good on tablets, but they may find themselves doing this again when ten-inch tablets start showing up.

I think the fact that most Android apps run seamlessly on the Tab is a significant selling point of the device. If you have 200 iPhone apps, chances are that either many of them will not have been ported to the iPad, or if they were, then it will be as a different app (Blah blah blah HD!) that you will have to purchase. If you have 200 Android apps, then you are good to go on the Tab.

The Tab has a few other advantages over the iPad. The one most people talk about is that it is more portable. This is not a small advantage. I just got back from a trip to Portland. When I’m there, I often like to go to the Starbucks near Pioneer Square to get tea and a scone for breakfast. One time I took my iPad with me, because I wanted to read blogs or news, catch up on Twitter and Facebook, etc. while I ate my scone. However I didn’t like having to carry it, and it was especially inconvenient once I got my tea and scone (3 items, 2 hands.) So I took it with me one time and never again. Instead I would just use either my iPhone or Nexus One. However this time I had my Tab and I always took it. Even with it raining, I could just put it in the inside pocket of my jacket and it was no trouble at all.

Then there is the related issue of weight. I have often read books (via the Kindle app) on my iPad while on airplanes, or at a café, or just around my house. The iPad always makes my wrist very tired, and I find myself switching hands or trying to awkwardly prop it up on something. The Tab is so much lighter that this is never a problem. I am currently reading Stephen King’s The Waste Lands on the Tab (also via the Kindle app) and have had no problems with my wrist tiring out.

I would say that the above three things are the major advantages of the Galaxy Tab over the iPad. Android apps work much better on it than iPhone apps work on the iPad; it is portable; it is much lighter. There are some other things too, like it having two cameras instead of zero, or being available on Verizon, T-Mobile, etc. Just to be fair though, the iPad still has some significant advantages over the Tab.

The bigger screen is obviously the biggest advantage. This really opens up the iPad for a lot of experiences that aren’t possible on the Tab, or would suffer. Also, it makes using non-mobile optimized websites much better on the iPad. For example, ebay.com is pretty usable on the iPad. On the Tab, it is ok in landscape mode, but definitely not in portrait. So I would not really consider using it on the Galaxy Tab, but would on the iPad. Of course there is still a decent chance that a non-mobile optimized site is going to have problems on the iPad still.

The bigger size of the iPad also leads to a larger battery. To me the battery life of the iPad is amazing. I do not use my iPad that much, so often it will go many days on standby. It blows me away how little battery is drained from say five days of standby. I have the non-3G iPad, so that makes a big difference, but still you just cannot beat the battery life of the iPad.

Big screen and big battery are big advantages. However if you want to watch TV & movies on your tablet-of-choice, then the iPad has an even more bigger advantage: iTunes. There is no good way to download a movie and watch it on your Galaxy Tab. I think we will see Netflix on Android and thus the Tab in the next few months. That will help, but Netflix’s streaming selection is still very limited. However, iTunes has an excellent selection. I would guess that we will also see Amazon’s Video-on-Demand on Android, since it is on the Android-based GoogleTV. That will help with selection as well, but still it will fall well short of what’s on iTunes. Plus any streaming solution is more limited than iTunes buy/rent model. Not to mention that there is already a Netflix iPad app, and it would be shocking if Amazon didn’t have a VOD app for the iPad sometime next year as well. If you want to watch TV shows or movies on your tablet, the iPad is definitely the way to go for the foreseeable future.

Based on the above, if a friend/family member asked me if they should buy a Galaxy Tab or an iPad I would ask them three questions:
1.) Do you plan on using it primarily at home/office, or do you want to take it with you when you are out or traveling?
2.) Do you use a lot of apps on your phone?
3.) Do you want to watch TV shows or movies on it?

Regardless of how they answered these questions, I think that a tablet like the Galaxy Tab or the iPad can replace a laptop for most people, but not everyone. If you are a heavy user of office-apps (word processing, spreadsheet, presentation software), then a tablet cannot be your primary device. I think the new MacBook Air is perfect for such folks. This is also a space where the ChromeOS netbooks have a chance to compete, as well as traditional Windows-based netbooks. If you do more “creative” activities, like graphical design, photography, and of course programming, then you need a real machine with serious RAM & CPU. That’s why my MacBook Pro will remain my primary machine for a long time. A tablet will always be complementary for folks like me. That’s why I think the portability and lightness of the Galaxy Tab outweighs the bigger screen and battery of the iPad for people who really need a laptop or even a netbook.

Friday, November 12, 2010

C2DM on older versions of Android

Back in May, I made my Android Wish List. The #1 item on my list was push notifications. The Android team delivered in spades with Cloud to Device Messaging. C2DM is much better than push notifications as they exist in the iOS world, because the user does not have to see the message being pushed. Instead your app can have a background service process the message and decide if a notification should be shown or not. That allows apps to receive many more types of events from the cloud, since they don't have to worry about bothering the user (or the user just ignoring the event.)

Of course there was one obvious downside to C2DM: it required Android 2.2. This is obvious, but is a bummer since it meant that developers needed to wait until 2.2 adoption became very high before they could start using C2DM. Here we are six months later, and only about half of all Android phones in use are running 2.2 (for the US, this is lower in other countries.) Who wants to ship an app that can only reach half of the universe of users, or update an existing app if half of your loyal users will be left in the cold?

This is definitely one of the places where you have to envy the iPhone. When iPhoneOS 3.0 came out, the adoption curve was pretty fast, even though users had to hook up their phone to iTunes. The reason for this was simple: OS 3.0 was available on all iDevices, and it was immediately available to everyone via iTunes. On Android, updates are pushed out over-the-air, which is great. However, it is up to vendors to do this. Plus a specific flavor of Android must be made for each Android device (this is true of iOS as well, but there are a lot less devices), and sometimes an update is not made for some devices for whatever reasons. For example, there are a large number of devices out there running Android 1.6 that will never be updated to Android 2.x.

Don't get so down though. The point of this blog post is that all is not lost with regards to C2DM. It is actually entirely possible to add C2DM to your application, even if your application is compiled at API level 4 (Android 1.6.) Actually, it would probably work against API level 3 (Android 1.5), but there aren't too many of those devices out there. The key is that the way that you communicate with C2DM is through Intents, no 2.2-specific APIs needed. Let's take a look.

First things first, you still need the proper permissions and receivers setup in your manifest. In particular you need a BroadcastReceiver that receives Intents with an action of com.google.android.c2dm.intent.RECEIVE or com.google.android.c2dm.intent.REGISTRATION. The names of actions are not constrained in the manifest schema, so that you can use custom/application actions. Thus this causes no problems on devices not running Android 2.2. Check out the official docs for all of the gory manifest details.

Next, your application needs to check if the device is running Android 2.2+ or something older. If it is, then you can register for C2DM. Here's how you check:

if (Build.VERSION.SDK_INT >= 8){
    registerForC2dm();
} else {
    // continue to use your pre-C2DM solution here
}

The only thing hacky here is that normally if you compare Build.VERSION.SDK_INT to something, it would be a defined constant like Build.VERSION_CODES.FROYO. However that constant is not available in Android 1.6, so instead we use its value of 8. I sure hope that constant doesn't change in future versions of Android!

Finally, you need to handle the registration and message Intents that C2DM will send you. Again, you are just specifying a string for the actions on these Intents, so no API dependency. That's it! No reflection, no compile against API level 8, but declare you only need level 4 hack (as is commonly done to enable an app to be installed on the SD card.) I've tested this approach on a device running Android 2.2 and on a device running Android 2.1. The 2.2 device gets C2DM messages, just as you'd hope, while the 2.1 device simply ignores the C2DM code and is unaffected.

Tuesday, September 07, 2010

Android Love

My colleague David Beach recently penned a great post about developing apps for Android. If you haven't read it, go read it now. Seriously. I know a lot of you will see that he's a product manager and stop right there, but get your lazy ass back over there and read it anyways. Look, even TechCrunch picked up his post. Ok I know that might actually be a disincentive for some of you, but still...

Anyways, I want to make a retort of sort to Beach and talk about why I love Android. However, I have to start by making a confession. My go-to phone is my iPhone 4. So why would I, an Android fanboy and somebody who is writing a book about Android development, use an iPhone 4? The answer is really quite simple. The apps are better.

My secondary device is a Nexus One, and I use it a lot. I would say I use it about 30-40% of the time. Many of the apps that I use a lot are available on both: eBay, PayPal, Facebook, Twitter, Foursquare, Yelp, Urban Spoon, Bank of America, Bump. However, in almost all cases, the iPhone app is just a lot better. This is definitely the case for the eBay app. It is most obviously the case for Facebook, which often dumps you off to their mobile web site to do things that you can't do in the app, even though you can do them on the iPhone app. The one app that I would say more than holds its own is the Twitter app, but even there I miss the conversations feature on the Twitter app for iPhone.

It's understandable that the apps on the iPhone are better. In many/most cases, these apps have been out 1+ year longer than their Android equivalents. So they have more features, less bugs, and are more refined in general. Further, most companies have a lot more iPhone users than Android (this is obviously changing), so they are going to invest more heavily in iPhone development. You probably want your best developer working on your iPhone app. Then again, Joe frickin' Hewitt is doing Android development now, so the developers have arrived.

I went off on this little tangent because it actually brings us back to the original topic. I use an iPhone still because its apps are better. I claim that the apps being better is mostly because of the head start that the iPhone is still enjoying. However, you could definitely infer from Beach's writeup (you did read it, right?) that it is easier to develop a great app for the iPhone than it is for Android. Heck, of the apps I listed earlier, the one that holds it own is the Twitter app. This is an app that was largely developed by Google -- who has to scratch their Android itch by developing 3rd party apps, because they largely focus on mobile web apps instead of native apps despite their ownership of the Android platform. Maybe all of us 3rd party developers have no chance of developing a great Android app because it is just too hard?

Obviously I do not think this is the case. The challenges that Beach lays out are absolutely spot on. For designers, there is no HIG, it is very much a free-for-all. I would add that the default controls and themes are also poor. You simply must do some significant styling to your app or it will look like ass. I think some/all of this will be addressed with the Gingerbread release. It is fair to say that Apple would have never gone this route, i.e. wait until the 3.0 version of their software to focus on user experience. That is fair, and since we haven't seen Gingerbread yet, maybe it will continue to fall short. Even if you can't rely on the OS+SDK to make your app look spiffy, you can still do it yourself. It's not that hard. I mean, it's not like you have to re-invent the button or something. It just takes some experience and knowledge of what is possible with Android.

Once you get past the eye candy, many things about Android development are actually quite nice. The development environment is excellent. Yes, there will be people who just don't like Eclipse and thus ADT, just as there are people who just don't like XCode. However, ADT's capabilities are quite advanced. One common complaint I have heard is about the amount of time that it takes to start an Android emulator image. This is contrast to the iPhone simulator, which starts up rapidly. However, if you consider that the Android emulator is an actual virtual machine being booted up, and not a shell that is simply relying on the underlying computer, then this is understandable. The advantages are obvious. Most apps run slower on the Android emulator than on a real device. The only advantage they may have over a real device is the network speed, but even this can be easily throttled to emulate edge or 3G conditions. If your app runs fast on the emulator, it is going to run great on a real device. You just can't say this about iPhones apps running on the simulator.

Going beyond the tools, Android is a more advanced operating system, at least from an application developer's standpoint. It lets you do things that are just not possible on the iPhone. The obvious thing here is multitasking. With Android's background services, you can always have the latest data from a remote server and never have to wait for it when your application launches. Imagine if you had an up-to-the-second Twitter stream always waiting for you before you launch the Twitter app. It is possible on Android. It is not possible on the iPhone.

It doesn't stop there. Communication between apps is formally supported on Android (though it could be improved) and can only be hacked on the iPhone. How many apps do you have that have some kind of "post it to Facebook" feature? Wouldn't it be great if you could just use the Facebook app to handle this -- thus no need to re-enter your Facebook name/password? It is possible on Android. It could sort of be hacked in a limited way on the iPhone, but it is not going to be pretty or seamless.

These are just a couple of examples. My point is that even though the UI/UX issues on Android are significant, they are not insurmountable. Once you get past them, the other advantages of Android are even more significant. As Android apps mature and Android developers mature, we should see the day where Android apps are better than iPhone apps. I don't think that day is too far off. Now would that counter-balance the arrival of the iPhone on Verizon and other carriers? I think so.

I will conclude on a more personal note once again. I work with all of the mobile teams here at eBay, including our iPhone teams. I've had a much more involved role on our Android app for awhile now, and I want it to be one of the first examples of an Android app that is significantly better than the iPhone equivalent. That's not because I'm an iPhone hater (though I'm sure we'd all agree that competition is a very good thing)  or something, it's just because I think that by fully tapping the capabilities of the Android platform, we can deliver something incredibly useful to our users. Mobile software development is an amazing experience. Our users get to connect with our software in a much more personal way. Our software literally runs in the palm of their hands. That's a remarkable place to be. Right now I think Android is the platform that can deliver the most in that place, and I'm going to put my money where my mouth is.

Saturday, July 24, 2010

Phone Number Fixer: The Glory and The Shame

A couple of months ago, I wrote a little Android app called Phone Number Fixer. I wrote this for my friend Maria, but decided to put it on the Android Market for free. Since then it has a decent number of downloads, around 1000, and had several good reviews. However, recently not only did its number of downloads jump up, but it started getting some poor reviews. The reason? The Samsung Galaxy S.

I have to admit that I had not been impressed with Samsung's previous efforts in the Android world. They seemed like decent "second-tier" phones. They were not in the same class with the Droid, Nexus One, or the MyTouch. Now the Galaxy S has come out, along with several other notable Android phones like the Evo, Droid X, and soon the Droid 2. I must admit to paying more attention to those phones than to the Galaxy S. However, it looks like Samsung has a winner on their hands.

The Galaxy S is available on both AT&T and T-Mobile. On AT&T it is known as the Captivate, and on T-Mobile it is known as the Vibrant. I think this is the first time that AT&T has carried a top-of-the-line Android phone, i.e. a phone that is a significant competitor to the iPhone. Of course we all know that the iPhone is coming to Verizon, so this should be no surprise (Big Red is getting the Galaxy S too, as is Sprint. Hey isn't that everybody in the US?)

Anyways, it seems like there are a lot of existing AT&T or T-Mobile users who are buying the Galaxy S. Of course they just want to take their SIM card from their existing phone (maybe even from their old iPhone?) and plop it into their new Android phone. That's when they run across the contacts-imported-from-SIM card problem that my little app can help fix. However, apparently there is something different about the Galaxy S. Not only is the phone immune to the power of the Phone Number Fixer, it even causes the app to hang and crash.

Unfortunately I do not have a Galaxy S of any sort, so I cannot test against it. I know the Fixer works fine with a Nexus One, Evo, G1, and a Droid, and I did not get any negative reviews until the Galaxy S. So I think there is something unique about this device. Once I get my hands on one, I will fix the problem. I am really curious to see what the cause of the problem is.

Wednesday, July 14, 2010

A Tale of Two Mice

For a couple of years now, I have used a Logitech V470 mouse. It is a laser mouse that uses bluetooth. I've used it with a black MacBook and two MacBook Pros and it has always worked perfectly. The only negative I could ever give it is that it is a little small for my hand (but I have large hands, I wear x-large gloves.) However, years of heavy use have taken their toll on the mouse, and I decided it was time to replace it.

This picture shows the V470 in the front, and its replacement a Targus AMB09US which they call "Comfort Laser Mouse." Why did I pick the Targus? Well it is also a laser mouse that uses bluetooth. I read many a rave review, so I figured it was just as good of a mouse as my V470. It is a bigger mouse, as manufacturers have started realizing that just because I want a bluetooth mouse does not mean that I want a "travel" (small) mouse. However, after several weeks of use, here is what my desk looks like:


Yep, the old V470 is back, despite being chipped and have plastic peeling off of it. The Targus mouse is just not as good for several reasons. Its interaction with my MacBook Pro is buggy. Often the cursor on the screen does not change as it should (imagine web pages where you don't get the little hand to indicate a link). The sensitivity of its sensitivity is way too high. What I mean is that a slight adjustment in sensitivity has huge effects. It is either sluggish or spastic. I've tried adding a mousepad to the mix, but it only helped a little. Finally, it does weird things when interacting with OSX. I hide my Dock on the left of the screen. If I put the cursor over there, then the Dock appears as it should. However, if I roll over items in the Dock, they are not magnified as they should be. I can still click on them, but this messes with me and makes me think too much when I just want to launch something from the Dock. Also, I actually missed horizontal scrolling with the V470. Its wheel could move left/right to allow for horizontal scrolling. The Targus mouse does not have this feature, and I didn't think I'd miss it. However, I did not realize how often I actually used this, especially in Aperture and OmniGraffle.

Now I know that many/most of these problems may have as much to do with OSX as with the Targus mouse. But I don't care. I'm not going to switch operating systems. Instead I will switch mice. I'd really like to get a larger version of the V470, which is why I have not just bought a new V470 and continue to use my old beat-up one. At some point I will probably give in and just buy a new V470.

Friday, July 09, 2010

LBJ, Cleveland, and Miami

I was one of the millions who watched Lebron James announce that he would play for the Miami Heat next year. I have to say that the aftermath of this has been one of the most entertaining non-sports things in sports I have ever experienced. Where to start...

1.) To all of the people complaining about what an egotistical p.o.s. Lebron is for having the TV special: take a look in the mirror. Did you watch it? If the answer is yes, then shut up. You created the market for his ego, and he was simply smart enough to milk it for what it's worth. Good for him. So why are you bitter? Maybe it's because you didn't like The Decision (and I'm not talking about the TV special.)

2.) To Dan Gilbert, owner of the Cavaliers: thanks for playing! I want to tell you to grow up and stop acting like a fool, but that would be dumb. No, you've made this whole thing so much more enjoyable with your childish antics. Please continue.

3.) To the Cavaliers fans: I'm sorry, but what did you really expect? Your team has bumbled this whole thing. The kind of overpaid, underperforming players that your team has continuously brought in to try to Win Now has been predictable and pathetic. The Cavaliers as an organization is weak, and has been for years. The only reason they got Lebron seven years ago was because they lost a lot of games in the right season. Yay. They've needed a coach who could get the most out of Lebron's unprecedented talents, and that has not happened. Instead everything has been done to appease Lebron, and you see how that works out. If the Cavs had had a coach who moved Lebron to point-forward (preferably playing the four-spot), posted him up on 2/3 of the plays, and told him never to take a 3-pointer unless it was to beat the shot clock, would Lebron have stayed in Cleveland? Who knows, but I think the Cavs would have won more games, especially more playoff games. That might have lead to a championship, and that probably would have made it harder for him to leave... All that being said, I still feel sorry for Cavs fans just because of the TV show. I think that would have made me physically ill.

4.) To the Bulls, Knicks, and Nets fans: just shut up. The Cavs fans have legit gripe, but you guys don't. So you didn't win the lottery. Boo-frickin'-hoo.

5.) To Kobe Bryant: congratulations. You are no longer the most disliked player in the NBA, a position you have held at least since you kicked Shaq out of L.A. Your style of egotism just became slightly less appalling to people outside of southern California. One interesting piece of analysis I've read is that there is no way Kobe would have gone to Miami, if he would have been in Lebron's position. The reason is that he would never want to have a decreased role so that he could play alongside Dwayne Wade. This is probably true, but I have a hard time seeing this as a negative about Lebron. Imagine if Lebron had got on TV last night and said he was playing for the Knicks or Bulls next year because he not only wanted to win a championship, he wanted to be The Undisputed Man on said championship team. That's the Kobe Bryant brand of egotism, and is that really more appealing? Maybe to some people, but not to me.

6.) To Kevin Durant: your time has come. You have a very legit chance to become the most popular player in the NBA next year, and you seem to deserve it. He's an unbelievably good player. He seems to have a Kobe-like work ethic. He also seems to be unbelievably humble. He's also 21 years old. He has to be on the short list for possible MVPs next year (Lebron's stats will take a big tumble in Miami.) His team looks like it will be very good for many years to come. It would not be surprising if a year from now Durant is sporting an MVP trophy, and coming off an exciting run deep in the playoffs. The only thing that might limit his commercial/endorsement potential is his own desire to stay focussed on basketball. Can you honestly say that about any other NBA player?

7.) To my home state of Florida: basketball just became king. Between the Orlando Magic and Miami Heat, my home state has three of the top five players in the NBA, two teams that will be expected to win ~60 games per year for the foreseeable future and meet each year in the Eastern Conference Finals. The only teams that could possibly stand in their way in the East are the aging Celtics and ... Maybe the Bulls if Derrick Rose becomes a top 10 player next year (which he definitely could do.) Seriously, there are going to be a lot of Florida Turnpike Series over the next five years.

8.) To Pat Riley: you are the man. You've got your work cut out for you, filling out that roster, but I'm not about to start doubting you at this point. In fact I would not be surprised if Wade, Bosh, and James all wind up taking considerably less than max contracts, all in the pursuit of a championship roster. As an Orlando Magic fan, I really hope this is not the case, but I'm too scared of Riley to think otherwise. I'm also impressed with his willingness to part with Michael Beasley, a very high and hyped draft pick. Personally I think Beasley may still turn out to be a very good NBA player, but I don't think most GMs would be willing to so quickly admit a mistake.

9.) To the pundits: let's see how long your memory is. A lot of people are saying that Lebron is taking the easy way out (even though many of those same people also think that having two All-NBA and one all-star player does not guarantee much in terms of championships.) It's Wade's team still, they say. Lebron can't be considered one of the game's greats now. That's all ridiculous to me. If Lebron continues to play the high level he's played at, and the Heat win multiple championships, none of this will matter. Nobody will care that it wasn't Lebron's team. Magic Johnson was never the "give me the ball at clutch time and get out of the way" kind of player, but nobody doubts his greatness. Lebron is much more cut in his mold than he is Michael Jordan's, and frankly it would be pleasing to see Lebron accept this. I think his stats will suffer, but mostly just scoring. I don't think his assists will necessarily suffer, especially if the Heat play an uptempo game (which they should.) His rebounding will go up if he plays in the paint more, and again if the Heat play uptempo. Imagine if he had a three year stretch averaging 20 points, 12 assists, 12 rebounds per game, while shooting 55% from the field? Throw in a couple of titles, and you're telling me he's not one of the top five players of all time? Nobody will care if Wade has the ball in his hands at crunch time.

Wednesday, June 09, 2010

iOS Multitasking

By now you’ve seen the ads. Anyone who works in mobile totally saw it coming. It’s the supposed revolutionary way to do multitasking in iOS, the new name for the iPhone OS. It’s complete bullshit, and here’s why.

It’s Not Revolutionary
Personally, I don’t really care about this point. However, it must be noted that the multitasking on the iPhone is strictly speaking a proper subset of the multitasking architecture used by Android and Palm’s webOS. Does it really matter? No, not really, but it is certainly annoying to hear Apple talk about how they didn’t do multitasking in the past because they hadn’t figured it out yet. The notion that what they ‘came up with’ is some brilliant solution that it took four years to figure out is insulting to the intelligence of developers. Not that that matters...

It’s Not Multitasking
Even Apple is pretty honest about this ... to developers. For us they say “it’s actually something We call Fast App Switching, and it’s all most of you people need.” This is the feature that was done by Android and webOS for the last couple of years. On iOS, when a user switches apps or hits the home button, your app has a brief time when it “runs in the background.” Then it becomes suspended. In its suspended state, it is still in memory, but gets no CPU cycles. If the user re-opens it or switches back to it, then it picks up right where it was before. Assuming that it is like Android (and everything else about Fast App Switching is very similar), then as a developer you might need to save some transient data, like if there is a form that is half-filled by the user. However, often you will not need to do anything to take advantage of this, just recompile with iOS 4.0 as your target.
But wait, there’s more. You should not count on your app staying suspended indefinitely. In fact, there’s a very good chance it will be terminated (that’s the official word.) This is exactly what happens when you go to the home screen on previous versions of iPhone OS, your app no longer takes up any memory. Now the user can still ‘switch’ back to your app (or re-open of course), but now it will be a re-launch of the app. In other words, it is just like closing your app, then re-opening it on iPhone OS 3.x.
This can obviously lead to inconsistent app behavior. Sometimes the user might switch away from your app, then switch back and be back at the same screen in your app that they were at before. Other times, they could do the same thing, but instead they are back to the opening sequence of your app. Apple wants you to change your app to remove this potential inconsistency. They’ve kind of given you a way to do this. First, when your app goes from being active to suspended, a new event is fired to your application’s delegate. All you have to do is add this new method (applicationDidEnterBackground:) to your delegate. In that method, you can save the state of your application. However, you might not have enough time. You can wrap your code with a start/end task completion calls, and then get up to ten minutes to finish saving your state. Alternatively, you can incrementally save state. Now truth be told, many apps (especially games) already do this, so that when you restart your app, it always picks up right where the user left off. Apple has essentially taken this pattern that other apps have adopted, promoted it to a best practice, and give you some extra tools to make it a little easier to implement.
There is one other thing that you might want to do right before your app gets suspended. You can decrease the probability of your app getting terminated by freeing up as much memory as you can. The iOS Terminator is going to kill apps that use more memory first. So free up as much memory as possible, and maybe it won’t kill your app. There’s no guarantees though. If the user launches an app that needs a lot of memory (and don’t they all?) then it doesn’t matter how little memory your app takes up. Everything is getting terminated. Hence Apple’s desire for you to always save state and never rely on being suspended when the user switches back to your app. However, if you do that, then is there any point to freeing up memory? Well theoretically it should be quicker to switch to a suspended app than a terminated one, so by freeing up memory you will be increasing the probability that your users will get a slightly better experience.

What is Real Multitasking?
Well strictly speaking, true multitasking would be to allow any given application to continue running as  normal when it is no longer in the foreground. This is what happens on desktop computers, and that sort of sets the expectation for smartphones. I think this is actually how Blackberry works (or it used, it has been many years since I bought a new Blackberry.) It’s not how Android works, and it’s obviously not how iOS 4 works. The major problem with this on more limited devices is that it causes those devices to run out of memory and use virtual memory. This makes everything on the device run sluggishly, as everything becomes gated by the swapping between real and virtual memory. Those non-foreground apps can also consume CPU and network. The CPU consumption might be an issue if you tried to run multiple games simultaneously -- just like it would on your desktop computer. Apple claims the CPU/network access real kill your battery. We’ll examine that later. Regardless, once you decide that a background app can lose its right to memory, it can’t function anyways. CPU/network becomes a moot point. Both Android and iOS terminate background apps to free up memory, something no desktop OS will do.
So iOS and Android both use similar pseudo-multitasking to make it seem like multitasking to the user. To prevent memory from running out and hosing the system, they terminate background apps at will. Both operating systems give you a way around this, a way for you to continue to execute a program in the background. That is where the similarities end.
On Android, you can create your own background service. That service can be in its own process, i.e. it gets its own block of memory allocated to it. That way if your application gets terminated, the service lives on. However, a service can be terminated just like an app. So you cannot rely on the service always running, instead the service should be there to enhance your application. Further, Android gives you ways to get your service restarted/pinged on a regular basis to do work.
On iOS, there are just a couple of types of applications that are allowed to run as a background service. Even then, they do not get their own memory. Instead they stay suspended and the OS sends them events periodically that allows them to run in the background again while they do something. Apple says they do not want to provide the Android style background services, because they (Apple) decided that the great majority of apps would not benefit from this anyways. Further, they think that such an architecture would lead to many background services running, killing the device’s battery. So instead they picked the types of apps that they say will benefit from background processing: music players, navigation, and voice-over-IP. The most ironic part of this is that the enabled a class of app, navigation, that has the most harmful effects to your battery (well maybe games are worse.)
I’ll talk about battery life in a second. First I want to address this notion that Apple has determined which apps would benefit from background processing, and which would not. As both a developer and a user, this is offensive. Apple has little knowledge of how my app works, or of how my users interact with the app. Further, they are obviously wrong. I can give you three examples of apps that use background services on Android to greatly enhance user experience: eBay, Facebook, and Twitter. You’re probably not surprised that I cited my company’s app, but maybe the other two did surprise you. All three use a background service to periodically download time sensitive data (current price of items, friend requests, status updates, tweets, etc.) So when you launch the apps or switch to them, you do not wait for all of this data to be downloaded -- like you do on all three companies’ apps on the iPhone. Instead you are presented with some fresh data (maybe a few minutes old), while the absolute freshest data is being downloaded in the background. You get to immediately interact with the apps. On iOS it might be possible to allow immediate interaction, but the data can only be as fresh as the last time you ran the app. This will usually be hours old, which makes it virtually useless for these apps.
There is no question in my mind that user experience can be better on Android than on iOS for these apps, and I don’t think they are unique. I mean c’mon, we’re talking about eBay, Facebook, and Twitter. Perhaps you’ve heard of these companies? It seems obvious that any kind of real-time/interactive/social based website is going to benefit from background processing for their apps. That’s a pretty broad class of apps, but I doubt it’s exhaustive. I’m not smart enough to figure out all of the apps that would benefit from background processing -- and neither is Apple.

Battery Life FUD
Ok, but what about the last plank in Apple’s argument: battery life. Well, as I pointed out earlier, they enabled a class of application that is devastating on battery life: navigation. These apps require constant high precision GPS information, which is very expensive. So their argument is not consistent with their behavior, still that doesn’t make their argument wrong.
The apps that I mentioned earlier all are guilty of something that is supposedly deadly to battery life: they periodically use the network to download data. How bad is this? Well obviously it depends on how often, and how many network calls are made, along with how much data is being sent back and forth. I’ve done some experimenting on this -- hey I work on one of the apps on that list of naughty apps. In my experiment I had an app that downloaded 100K+ data every two minutes. The effect on battery life was less than 3%. That’s right. You could let such an app run in the background for days and days, and your phone would still have plenty of battery.
Now wait a minute, I know what you’re thinking. You can’t even go one day without recharging your phone, and you’ve got an iPhone that doesn’t have anything running in the background (by the way this is not true, Apple’s apps have been able to run in the background since the very first iPhone.) Further, you don’t even use it to make phone calls, yet it’s got maybe 12 hours of battery life. What gives? The answer is surprisingly simple, the screen. The screen on your beautiful phone is what drains your battery the most. So anything that involves the screen being on -- which is every kind of app on the iPhone currently -- will significantly drain your battery. Everything else they do has little noticeable effect on battery life, with two exceptions. Anything that rapidly changes that pretty screen will consume your battery even faster. That’s why many games will hammer your battery. I’ve had times where I played Civ on my iPhone for maybe twenty minutes, and it lopped off a third of my battery. That game doesn’t even have that much eye candy. The other battery blaster is the aforementioned GPS, for obvious reasons. All of those Android users with eBay, Facebook, and Twitter installed are doing just fine.

But You're Gonna Love It!
So with all of that being said... users will really appreciate Fast App Switching in iOS 4. Why am I sure of this? Because Android users have always loved it. It’s one of those things where iPhone users don’t know what they are missing. Thus it will be delightful for them, and they will think Apple is full of geniuses. Actually I think it will put some serious pressure on Apple to update the iPad to iOS 4 (or maybe 4.1? Will we ever run the exact same OS on the iPhone and iPad?) People will get used to having Fast App Switching on their iPhone, and they will be so annoyed that they don’t have it on their iPad. I hope we’ll eventually see the same thing with regards to general purpose background processing. Maybe one day this will be part of iOS, and then it will be annoying to use older versions on the OS that don’t have this feature.

Update: You can add Instapaper to the list of apps whose developer would like it to be able to run in the background, so that it can improve user experience. Marco has an interesting proposal to tweak iOS to suit the needs of his app, and no doubt many others. It's better than the current situation, but I still think it's foolish to try to figure out all of the types of apps that need background processing, and add special APIs for each such app. While at WWDC, I talked to developers who work on some very popular sports and weather apps, and they too were incredibly disappointed by iOS. One of them proposed a new type of remote push notification that would not be displayed and only processed in the background.