Mobile Webkit CSS Sizing Bug: Hardware Acceleration Edition

It’s a well-known “secret” that you can force webkit engines into hardware accelerated rendering by applying what should be non-effectual[link] css3[link] transforms[link]. The reason you care is though HTML5 mobile apps are great, they still require effort to get that native feeling for simple tasks like scrolling[link to momentum scrolling post] and animations. As a result, if you google something like “momentum scrolling html5″ you’ll see posts that give you snippets like this:

*:not(html) {
     -webkit-transform: translateZ(0);
}

and variations thereof.

The main issue with css like this is that it can quickly crash your mobile app with an out of memory error by asking webkit to hardware accelerate every DOM element in the page, which it apparently wasn’t built to do. The other issue is that it’s just not obvious what else is affected when you switch on hardware acceleration all the way down the render tree.

Here’s a simple example where adding a transform modifies how webkit sizes an element:

What You Expected

Now With Extra Whitespace

And here’s the HTML/CSS to make it happen (you can see the same behavior in Chrome Mac 21.0.1180.89):

<!doctype html>
<html>

    <head>
        <style type="text/css">
            body {
                margin: 0;
            }
            #app {
                width: 100%;
                height: 100%;
                margin-left: -20px;
                background: #323232;
                -webkit-transform: translateZ(0);
            }
            .title-bar {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                height: 48px;
                text-align: center;
                background: #323232;
                color: #FFF;
            }
            .title-bar h2 {
                margin: 8px 0;
                font-size: 26px;
            }
        </style>
    </head>

    <body>
        <div id="app">
            <div class="title-bar">
                 <h2>App Title</h2>

            </div>
        </div>
    </body>

</html>

There are three ways to fix the issue:

  1. remove “margin-left: -20px” from #app
  2. remove “width: 100%” from #app
  3. remove “-webkit-transform: translateZ(0)” from #app

Regardless of how you think this should render, the fact is that adding the webkit transform does change the sizing of the #app element in an unexpected (at least to me) way. Though easily diagnosed and fixed, it means I’ll have to spend more time scrutinizing the rendering layout leaving less time for building the actual functionality of an app, for now.

What? margin-left: -20px?

So how did I happen across this randomness? I was playing around with using Bootstrap and the built-in responsive design for mobile site development and it’s grid system uses negative margins as part of its column alignment. Hence, this post.

Six Tips on Defining WebService APIs

Frameworks such as PhoneGap or Sencha created a great promise of rapid development of fast and impressive apps across different platforms by focusing on client code reuse. We want to share a more holistic architecture across the server and client that let you go native on each client platform and still take advantage of code reuse.

The idea is simple: if you have control over both the server and the client design, you should not settle for a solution that only optimizes one.  If you “look at the whole board” and optimize the server for the clients, you won’t need to sacrifice the user experience for the sake of client code reuse.

Primary design goals for Personal Capital include:

  • Perfect balance between an feature-rich application and an intuitive navigation scheme
  • Creating the absolute best user experience; and
  • 100% accurate data presentation

With these design goals, we’re not satisfied with the defaults of each client platform, let alone defaults of shared code across multiple client platforms! At Personal Capital we have customized every component and every interaction in the pursuit of user happiness and achieving UX nirvana: a wowed and happy user each time that she uses our service.

Our Architecture

Our approach is simple: Go Native but optimize the server’s Web Services APIs for the client by following six simple tips to gain the time and flexibility we need to make our app stand out, on each platform, in its own way. We started experimenting with these rules two years ago when we created our Second Generation APIs, and optimized them as much as possible for the clients. These six principles allow us to streamline design and QA, and free up our client developers to spend the majority of their time on what they do best: making amazing user experiences.

Tip #1 Let Your Client Developers Write the Server API Definitions

API definitions are normally dictated by the server engineers, and REST enthusiasts and typical server-driven development paradigms have made it uncommon for client developers to be more than tangentially involved in server API definition before coding starts. We flipped this model on its head and relied on our client developers to drive the API definition, and as a result the server became much more attuned to how the clients expect the data to be structured, and minimized re-work later by maximizing communication early on.

Tip #2 Let Your Server Developers Take As Much Logic Out of Client Code as Possible

Avoid replicating code across many clients that you support and move as much logic as possible to the server. Having business logic in the client code is analogous to hard coding a configuration value. The pivotal point for us was realizing it’s better to have simple, thin, and pretty clients than complex, thick ones that have duplicated and hard coded business logic. Smart clients are a burden. Now each of the discussions between client and server developers is about “how can the server make the client’s code simpler?”

Tip #3 Don’t Be Afraid of Specialized APIs

Let’s just say this: it’s OK to serve the same data from more than one API. Why? Because when clients get data in the format they need, directly from the server, they can get it on screen faster by skipping complex transformations. And when the data format changes on the server, those changes are transparent to the clients. This has the added benefit of also not needing to care how the data is being used elsewhere in the client, making your client more loosely coupled and modular.

Tip #4 Let the Server Enforce Uniformity Across Clients

When it comes time to support multiple clients, the more you push responsibilities like rounding of amounts, calculation, and string formatting up to the server, the more time you will save your development and QA teams. You won’t need to spend time re-writing the same formatting and calculation rules on each client and fixing the same bugs on each platform. If it’s correct coming from the server, it will be correct everywhere.

Tip #5 No Workflow State Machines on the Clients

Likewise, when dealing with multiple clients, the more you push the complex state machines that deal with business logics into the server, the faster you will be able to iterate. For example instead of having a logic on the client that says “if user is in state x, and this is the first time that she is attempting to do y, show message z” just tell the client to show message z. All that logic can be encapsulated on the server and the API can just tell the client what to do. The time to market gained between each client writing and testing a complex flow versus each client simply responding to server flags is huge. It’s the difference between crazy nested ifs and a simple switch statement. Keep the complex state machines tucked safely in an API. Let your clients focus on display logic, and not managing business state.

Tip #6 Fast, Rich and Flexible APIs

If you follow all these tips, the payoff is huge: shorter time to market, simpler client code, less bugs. But if you want to pull this off, you must:

  • Make calling an API fast, really fast. Round-trip time of a request has to be as short as possible. This means server-side caching, is a must.
  • Create rich APIs that can deliver a lot of data in one call; this is especially important for mobile applications where the network overhead is much greater.
  • Add enough controls in the API definition to allow the client to ask for the right amount of data based on their flow. E.g. iPhone may not show transaction details and would just need the summary, but iPad and web do want to show these data. Give the clients the control to request the right data amount.
  • Gzip your responses as much as possible. The performance lift you get on mobile and web apps from this simple change are amazing!
  • Client-side caching of the API responses is just as important and reduces reliance on network stability to a great deal.

Go Native!

With loosely coupled client modules that receive pre-formatted data, and client developers that don’t need to implement tons of complex business logic, you can focus your client developers on what they do best. You’ve successfully freed up enough cycles that you can afford the extra spit and polish that will make your app stand out from the rest.

Last month we held a Meetup that we discussed these principles and how through this architecture you can reduce your client code base by not sharing client code, but rather sharing server code. You can watch the video here.

Get Your Feet Wet with Android Development Tools

Last week, Personal Capital released its Android app to the Google Play store. You can read more about it here. Developing quality apps that perform well requires more than just writing code. The Android SDK comes with a number of excellent tools for debugging and testing apps. While simple to use, they can expose some of the harder-to-find bugs and reveal opportunities for improving your code. Here are some highlights of the things we get lots of mileage from:

Eclipse

While not specifically an Android tool, Eclipse is a valuable one nonetheless. Android apps can be run with the standard Java debugger just like any Java project, and Eclipse’s debugger is no slouch with conditional breakpoints, exception breakpoints, drop to frame, and other neat features. Most of the SDK tools integrate into Eclipse as well, so all of your tools are in one place.

Logcat

Logs are especially useful when trying to reproduce a bug, both to give you a starting point for your investigation and to confirm that you’ve accurately reproduced an issue. Even when you’re not looking for anything specific there, watching the device log can be surprisingly instructive.

Reading the Logcat can be done with the Android Device Monitor tool in the Android SDK. You can start it from a command line by running <android_sdk_path>/tools/monitor. Alternatively, you can open the Eclipse perspective called DDMS to access the same features.

Select any connected device or running emulator from the Devices tab, then switch over to the Logcat tab to see the logs. There will probably be lots of messages flying by, so put part of your application’s package name in the filter bar to increase your signal-to-noise ratio. You can also filter out messages below a certain priority level by selecting from the dropdown menu. The save button in the upper right of the pane will export selected lines to a file.

Logcat with filtered messages

Logcat with filtered messages

Suppose you get a crash while running your app and you aren’t connected to a computer, or you don’t have Device Monitor running. Is there any way to retrieve those logs? Indeed there is: in your <android_sdk_path>/platform-tools/ directory is a tool called ADB. Connect your device and run the following command to dump all the log messages to a file:

$ adb logcat -d > log.txt

Of course those log messages won’t last forever, so grab them before they get pushed out of the log buffer.

Screen Capture

Yo dawg, we heard you like screenshots…

Yo dawg, we heard you like screenshots…

In case your device doesn’t have screenshot capabilities, or to spare yourself having to transfer screenshots form your device to your computer, Android Device Monitor has a screen capture utility built in.

In Device Monitor (or DDMS in Eclipse), select a device or emulator from the Devices tab and click the icon near the top. A window opens up showing a preview of the device screen, which you can save as a PNG. The preview does not update when you interact with the device; you have to click the Refresh button to reload the preview.

Hierarchy Viewer

Speaking of UI, occasionally you get some layout params wrong and a View (or, you know, half the View tree) mysteriously vanishes into nothingness. The last time this happened to me, it was in a part of the view hierarchy I certainly didn’t expect, and I never would have found it without this tool.

Hierarchy Viewer is included in Device Monitor, or you can open it as a perspective in Eclipse. In the Windows tab, select the window corresponding to the application you are debugging (the active window will be bolded). Once the View tree loads, clicking an individual View will show you a preview of its appearance on screen. Where that View is positioned on screen can be seen in the Layout View tab, and you can inspect various attributes in the View Properties tab.

A View tree in Hierarchy Viewer

If you’ve seen our app, can you guess which screen this is?

If a View that should be on screen is not visible and you do find it in the View tree, check the layout and measurement properties and see if its width or height is inadvertently being set to zero. This can happen for a number of reasons, some potentially obscure, like using the wrong anchor in a RelativeLayout or not setting the alignWithParentIfMissing attribute.

TraceView

TraceView is a profiling tool to help you determine areas of code that are performance bottlenecks. It can also alert you to operations on the UI thread that should be moved elsewhere. Due to technical limitations and to the latency it adds, method tracing is not something you would leave running for the duration of testing. Instead, you should start tracing just before performing some action of interest, and then stop tracing just after.

The easiest way to use TraceView is through Android Device Monitor (or DDMS in Eclipse). While your app is running, select the process in the Devices tab. Click the  icon at the top of the pane to start tracing, interact with the app for a bit, and click the icon again to stop tracing. TraceView will open the trace data for you to inspect.

TraceView at a glance

TraceView at a glance

The top pane will show a timeline of thread activity, while the bottom shows profile information for all method calls that took place. In the timeline, you can zoom in and out with your mouse scroll wheel, or click and drag a horizontal region to zoom in. Pay particular attention to the Main (or UI) thread; any unusually long gaps in the timeline could indicate something making your app unresponsive.

The bottom pane shows all the method calls and reports data regarding execution time (real time or percent of total), both exclusive and inclusive. Exclusive time is only the time the method was executing instructions; inclusive time also counts calls to other methods. You can drill down through method calls and sort them by any column. Sorting by exclusive real time, for instance, could help find particular methods that are taking the most time to process.

Drilling down in method profile

Drilling down in method profile

Wrap Up

Sometimes the simplest thing—screenshots, exported logs, etc.—vastly improves our ability to turn around a bug posted to our issue tracker. Other times, you need comprehensive measuring tools to pinpoint a critical flaw. Whatever platform you are building for, tools like those packaged in the Android SDK are invaluable. Even for non-developers, these tools can be leveraged to help understand the behavior of the app and provide better feedback for developers.

If you are already using these tools in your development process, great! Consider introducing all of your engineers to them as well. Empower others to explore, get their hands dirty, and perhaps engage in the feedback part of your development loop; they’ll probably appreciate the knowledge you’ve shared. And don’t count out your client base either—believe it or not, even some of our end users send us logcat output on occasion.

Personal Capital Launches Android Mobile App

Personal Capital Engineers have ambitious vision, and as a friend put it, we’re always pregnant with more projects than we have engineers for. Our latest delivery is Personal Capital Android App.

Like our iOS app, the Android app is filled with interactive custom components and visualizations, from the rotating pie chart for cash management to the asset allocation tree map. Our philosophy in both design and implementation is to create custom native components tuned to the each device’s unique attributes to allow for an intuitive design and controlled behavior across varying device resolutions

In our Android app, we use many of the design concepts and lessons learned from our earlier development of our iOS app. For example, we implemented the same unique navigation system in Android that we use in iOS – it employs the concept of live views to speed up wayfinding for the user. We will be talking about some of these “shared clients that don’t share codes” concepts in our meetup as well.

If you haven’t downloaded the app yet, you can do so here: https://play.google.com/store/apps/details?id=com.personalcapital.pcapandroid

Watch this blog for more posts around our experience with Android Development.

Tips on UI Automation of iOS Applications

Automation support for iOS apps is still a relatively new technology and like all other technologies that are still quite not mature it has a lot of challenges. Below I would like to discuss one of such challenges, identifying and accessing individual custom cells inside a UITableView

Let’s say we create a new phone book application and let’s say that the 3 pieces of information that this application stores are: the last and the first name of the contact along with the type of contact that this person is (family, friend, work). The contact type would be displayed in a non-text form (an icon for instance). Let’s also assume that there would be a screen that lists all the contacts that we have in our phone book and that is the screen that we are going to test.

As of right now every table cell is identified via all the text field values augmented inside of them. For example, a cell for John Smith can be accessed via the following statement:

target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["John Smith"];

The problem with this identification scheme is that potentially it lacks uniqueness. if we have 2 John Smiths we would not be able to distinguish between the two cells. Moreover, what if one John Smith is classified as family while the other one is a friend, we cannot query how these contacts are classified since these values are non textual

This is when accessibilityLabel property comes to our rescue. In our example, we want to encode 2 non-textual values in the accessibilityLabel. By using the following formula to generate accessibilityLabel for {record unique id},{contact type description} not only do we generate unique identifiers for the table cells but we can now query the contact type of the corresponding record for the cell. In our example the two accessibilityLabel values for the 2 John Smiths (assuming their unique record ids are 1 and 2 respectively) could be accessed via the following statements:

   target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["1,family"]; 
   target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["2,friend"];

The native code for creation of cells would look something like this

-(UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSindexPath *) indexPath  
{ 
   UITableViewCell * res = … 
   Contact * c = … 

   //initialize an instance of UITableViewCell 
   //get an instance of Contact that corresponds to the indexPath 
   NSMutableString * accessibilityLabel = [[NSMutableString alloc] init]; 
   [accessibilityLabel appendFormat:@"%d", c.contactId]; 
   if(c.contactType == ContactTypeFriend) 
   { 
      [accessibilityLabel appendString:@",friend"]; 
      res.imageView.image  = [UIImage imageNamed:@"friendsIcon"]; 
   } 
   else if(c.contactType == ContactTypeFamily) 
   { 
     [accessibilityLabel appendString:@",family"]; 
     res.imageView.image  = [UIImage imageNamed:@"familyIcon"]; 
   } 
   else 
   { 
     [accessibilityLabel appendString:@",work"]; 
     res.imageView.image  = [UIImage imageNamed:@"workIcon"]; 
   } 
   res.acessibilityLabel  = accessibilityLabel; 
   [accessibilityLabel release]; 

   return res; 
}

If we want to access a cell for a contact with a known record id but unknown status we would need to write some additional JavaScript code

function findCellByRecordId(recordId)
{
   var cells = target.frontMostApp().mainWindow().tableViews()["Empty list"].cells();
   for(var i=0; i &lt; cells.length; i++) 
   { 
      var cell = cells[i]; 

      //parse the name and check the first part 
      var cellNameParts = cell.name().split(","); 
      if(cellNameParts[0] == ("" + recordId)) 
      { 
         return cell; 
      } 
   } 

   //at this point we did not find anything 
   return null; 
}

Now we have means to locate cells based on contact unique record id, we would want to have an ability to see query what kind of contact type this cell shows

function getRecordTypeFromCell(cell)
{
   return cell.name().parts[1];
}

Now that you can access cells based on the unique record id of the contact that these cells represent as well as the ability to query the status of the contact, you can start writing automated tests for this screen. Happy unit testing!

Note: download sample Phone Book project