Tablets and Fragments on Android
We just released Evernote for Android optimized for tablets. The same APK runs on the phone and tablet, we’ve just customized the look and feel based on the device. This post will explain the process we went through to convert our app to a tablet form factor. I hope some of our experiences will be helpful to you if you find yourself moving your app from the phone to the tablet.
Requirements for Evernote App
- Same APK has to run on both phones and tablets
- Same APK has to support Android devices with version 1.6 and above
- Don’t lose any of the current phone features
- Use screen real estate wisely
- Visually appealing
- Feel Responsive
Like the Android phone design, the new Evernote for Android tablets is a design created by our Chief Designer Gabe Campodonico. He spent a lot of time designing the app to be both visually appealing and usable on the tablet’s larger screen. You’ll notice that the look and feel is quite a departure from the phone version and much of the theme should eventually make its way back to the phone version.
Fragments Static Library
The first step was to download the jar file and source code for the Fragments static library from Google. We have to use the static library to be able to support pre-Honeycomb devices. The source code was very valuable because I was able to fix some bugs in the first version of the library that otherwise would have caused problems and would be difficult to work around. Activity results were broken so the results never made it back to the calling Fragment. (Thank you Google for releasing the source)
Converting current Activities to Fragments and FragmentActivities
The next step was to take a couple of activities that I knew would end up being displayed in the dual pane format and convert them to fragments. This didn’t involve the tablet, I just changed the current phone activities to use a shell activity and moved all the functionality into a fragments. Doing so allowed me to become familiar with the basics of fragments and start to seeing some issues that needed to be addressed.
- If I were to use full screen dialogs in the same way our app currently used them, I would have to create unique IDs for all of the dialogs and have a way to find out which fragment a dialog belonged to. This is because the Fragment would ask to create the dialog, which would bubble up to the parent Activity. When the parent Activity’s onCreateDialog was called and there was more than one Fragment in the Activity it had to know which Fragment’s onCreateDialog to call to actually construct the dialog. There were similar routing issues to options menu items where item selection needed to be routed to the correct Fragment for handling.
- I needed to separate our UI initialization from our Intent handling in these new fragments. So much of our intent handling was in the onCreate methods of our Activities, mixed in with the UI initialization, and this just wouldn’t work with fragments where the intent isn’t even initially available. I changed the Fragments so that they could handle the cases where the intent is available during initialization, and also where it wasn’t available until later.
Now that I had our notebook list Activity and our note list Activity converted to Fragments, I combined them into the beginning of the main tablet Activity. This went pretty smoothly and it was nice to see something that looked more like a tablet app when I launched it on the tablet. The tablet activity itself didn’t do much more than house the fragments and in the end would handle swapping them in and out as different note browsing tabs were chosen.
List fragments such as Notebooks, Shared Notebooks and Tags need to handle static selection, allowing an item selected on the left to remain highlighted when a user switches between tabs. To do this, I also needed to persist the highlight information so, when the app gets cleaned up or when the user switches between main tabs the highlight can be restored.
In the end because of the Fragments static library at least 95% of the code is shared between the phone and tablet versions, and the main differences are handled in the resource folder.
Unique UI Widgets
With larger screens we wanted make better use of the screen so we designed horizontally scrolling snippets. For example, the note list that is included in the Note View and the Maps View both contain horizontally scrolling snippet views. To accomplish this, I created a GridView that can be configured either through xml or dynamically to scroll different directions based on screen orientation.
We also incorporated transparent overlays and bubbles to give a pop-over visual effect such as the search pop-up. This was accomplished by theming activities instead of having the pop-up layouts stacked on top of the current activity. This kept the logic almost identical between the phone and the tablet, despite having a full screen activity on the phone.
You’ll probably notice on the tablet app that our left bar and top bar are different from the now-standard tablet ActionBar. This is because, in our design, we really wanted to optimize it for the landscape orientation. We didn’t want to have two title bars at the top. Our design allows us to have buttons on the right and left that are clearly related to those panes and their context. Also, on any screen that had more than one UI pane, we moved away from using the options menu at the bottom because we felt it was confusing. What we didn’t realize (because of using API 10 as our target) was that the options menu was removed completely in API 11 unless you are using Android’s ActionBar. Be aware of this, so even if you think you have a better design than the standard ActionBar, you should find a way to make the ActionBar work, unless you are okay getting rid of the options menu, or building your own handling of it. Now we’ll be forced to change those navigation elements to a design that incorporates Android’s ActionBar.
After getting the main portions of the app working and even a lot of the UI polish done, it was obvious that performance had become a huge issue on the 10 inch tablets. Having a screen full of thumbnails in the new snippet note list, required loading of a lot of different image files off the sd card and this caused everything to be very slow. I dug into the issue and came to the conclusion that the only way to load the images quickly was to store the images together in large memory mapped files and to copy the pixels directly from a ByteBuffer to the bitmap object. To do this, I started with the Krati datastore project shared by LinkedIn engineers and then made a lot of changes to make it fit what we needed. The result was very fast loading of the thumbnails. This is also used on the phone version. Try flinging that note list of snippets on the phone and watch the images fly by. This is done with no preloading whatsoever, but does use a very small cache once they are loaded.
We hope you enjoy the new Evernote for Android Tablets because we certainly enjoyed making it. Let us know what you think in the comments, if you are a lucky Android tablet owner.