Archive for September, 2010

Mobile Monday: Best Practices for Mobile Design (September 20, 2010)

Tuesday, September 21st, 2010

Mobile Monday panel left to right: Wesley Yun (RIM), Jared Benson (Punchcut), Anne Sullivan (Microsoft/Tellme Networks), Chris Nesladek (Google), Sue Booker (Nokia) (taken with my iPhone 3GS)

I just came back from Mobile Monday Silicon Valley: Best Practices for Mobile Design at the Computer History Museum in Mountain View. This was a panel discussion with representatives from Google, Microsoft, Nokia, RIM, and Punchcut. There were quite a few little nuggets of wisdom which I tried to write down in bullet form:

Sue Booker, UED (Nokia)

  • 1 trillion revenue worldwide from disabled users. 60m disabled users in the US.
  • assume the user is multitasking
  • apps will be used in totally unexpected ways
  • not just physical disabilities.. also people in different situations or environmental limitations (no voice, no audio, limited bandwidth, etc)
  • introduce new complicated functionality gradually. It’s easy to tell if it’s a new user or a repeat user, so slowly give repeat users more info.
  • final takeaway: think of all types of users

Chris Nesladek, Commerce UI Lead (Google)

  • 1. keep it simple
  • 2. content is king
  • 3. make it fun
  • 4. make it fast
  • 5. do one thing as an experiment
  • new UI challenge in the future: flexible screens?
  • discoverability of new features… for an Android feature: link to video demo on vimeo
  • final takeaway: designers, make friends with developers, because that’s how the best products get made

Anne Sullivan, UI Designer (Microsoft/Tellme Networks)

  • her focus: designing for speech on mobile
  • problem: discoverability of speech
  • understand the capabilities and limitations of speech
  • graceful degradation for speech: what happens when a voice command isn’t recognized?
  • be transparent about what happens about processing in the background. For instance, geolocation. Allow the user to change or override this info.
  • paper prototypes are very helpful
  • discoverability of voice command activation is hard.. have to test on device itself (i.e. to find the right button placement, etc.)
  • final takeaway: forget powerpoint! do presentations on the phone itself

Jared Benson, Design (Punchcut)

  • iterate quickly
  • no substitute for device itself
  • final takeaway: involve designers from the beginning

Wesley Yun, UX (RIM)

  • don’t make assumptions about touch interfaces (common gestures). The touchscreen is still pretty new, so not everyone is used to this yet
  • don’t be too clever for your users. Think of users first, and do what makes sense.
  • prototype and fail quickly. If you’re not failing, you’re not innovating
  • make sure unusual new interaction isn’t a core functionality (for instance, four-fingered scroll)
  • if you make something redundant, you’ve failed as a designer
  • final takeaway: make it obvious to users

Server side console.log

Wednesday, September 15th, 2010

The problem

On the desktop we’re quite privileged to have nice debugging tools such as Firebug and Web Inspector in Webkit-based browsers. But when it comes to mobile, debugging JavaScript with console.log isn’t quite as easy.

Probably the best available tool on mobile at the moment is mobile Safari’s console, which looks like the following when enabled (Settings -> Safari -> Developer -> Debug Console):

Mobile Safari's debug console

On the left you can see the debug console displayed above the document itself, and on the right is an example of what you might see after outputting an object or a string of text to console.log. It’s the best debugging tool on mobile, but it’s not without its issues.

The first issue is that the debug console is taking up space in the screen and interfering with how an actual user would view the website. I could image this could become particularly annoying when trying to develop a web app in the style of the new YouTube mobile, which doesn’t function like a traditional webpage at all, and relies on the screen being a certain height in order to display its content.

The second issue is that you can’t see the contents of JavaScript Objects. We’re a bit spoiled being able to see a tree view of objects on the latest browsers with the latest debugging tools, and therefore it makes the experience on mobile Safari less than adequate. When we type console.log(navigator) all we can see on mobile Safari is [object Navigator], which leaves something to be desired.

So what about Android? Google offers something called Android Debug Bridge, which is a client-server debugging solution that can be used either for web or application development. As such, when you view the messages the devices sends to the server, the vast majority of messages will be messages about low-level operations, stuff we usually don’t care much about when developing with JavaScript. The workaround for this is to grep for “console” on the command line, which will only display the messages we’re interested in.

The solution: server side console.log!

Why not just send the contents of your console message to a server, and have it log it? The concept is pretty simple:

  1. Create a log function that sends an XHR to a server.
  2. Have the server process the request and log the message to a file.
  3. Tail the end of the file on the command line to see the latest messages.

The implementation is pretty simple. In JavaScript we have this code:

(function(){

// define console if not already defined
console || (console = {});

// new toFile method
console.toFile = function(log) {
  // variable declarations
  var http, url, params;

  // might as well use the traditional console.log() as well
  console.log(log);

  // ajax request
  http = new XMLHttpRequest();
  url = "//example.com/log.php";
  params = "log=" + Date.now() + ' ' + escape(sanitize(log));
  http.open("POST", url, true);
  http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  http.send(params);
}

// do something special if txt is an object
var sanitize = function(txt) {
  var output, x;

  if(typeof txt == 'object') {
    // create a new object to get around circular references
    output = {};
    for(x in txt) {
        // type conversion of each element to a string
        output[x] = txt[x] + '';
    }
    output = JSON.stringify(output, null, 2);
  } else {
    output = txt;
  }

  return output;
}

})();

In summary, the above code adds a new method to the console object called toFile, which simply takes the inputted data and sends it to the specified URL. The only bit of trickery here is the function sanitize, which detects if the message being passed in is an object. If it is, it copies it to a new object containing only strings (which gets around JSON “circular reference” errors) and runs JSON.stringify() on it, which lets us peek into its contents one level deep.

The server side PHP code to make this work is even simpler:

// log.php
<?php

// take advantage of error_log to log the message to the file console.log
@error_log($_POST['log'] . "\n", 3, 'console.log');

?>

On the server, we log in with terminal, navigate to the directory containing the file console.log, and simply tail the end of the file, which shows live updates as new messages are added to the end of the file:

tail -f console.log

Example

Once we have the above code in place, using the console is very simple:

console.toFile('hello world!');
console.toFile(navigator);

After running this code, you should see this pop up on your terminal:

1284574866900 hello world!
1284575008914 {
  "geolocation": "[object Geolocation]",
  "standalone": "false",
  "cookieEnabled": "true",
  "language": "en-us",
  "productSub": "20030107",
  "product": "Gecko",
  "appCodeName": "Mozilla",
  "mimeTypes": "[object MimeTypeArray]",
  "vendorSub": "",
  "vendor": "Apple Computer, Inc.",
  "platform": "iPhone",
  "appName": "Netscape",
  "appVersion": "5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7",
  "userAgent": "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7",
  "plugins": "[object PluginArray]",
  "onLine": "true",
  "javaEnabled": "function javaEnabled() {\n    [native code]\n}",
  "getStorageUpdates": "function getStorageUpdates() {\n    [native code]\n}",
  "registerProtocolHandler": "function registerProtocolHandler() {\n    [native code]\n}",
  "registerContentHandler": "function registerContentHandler() {\n    [native code]\n}"
}

Sweet! Now we can easily see console messages from actual devices. You can potentially use this code to log Events as they occur (on click or touch interactions) and view the actual x/y coordinate values as they’re being detected on the device!

Related

Alex Kessinger implemented a similar concept with node.js running locally

Update

It turns out that Joe Hewitt did this before me with his “Firebug for iPhone”. I have no idea why it took me so long to find this!

Optimizing based on connection speed: using navigator.connection on Android 2.2+

Tuesday, September 14th, 2010

Introduction

A little while back this post made the rounds, which took us on a journey through some of the new features introduced in the browser in Android 2.2 Froyo. Among the most overlooked features are the file upload functionality (you can upload photos from your browser now! But we’re still waiting on iPhone to support this…) and a little-known JavaScript addition to the Browser Object Model (BOM) in the form of navigator.connection. Let’s take a peek at its contents:

// contents of navigator.connection object
{
  "type": "3",
  "UNKNOWN": "0",
  "ETHERNET": "1",
  "WIFI": "2",
  "CELL_2G": "3",
  "CELL_3G": "4"
}

This is data taken from a Nexus One running on a 2G network, so you can see that the type is set to 3, which corresponds with “CELL_2G”. In other words, this phone runs on a slower network, so from a performance perspective, you probably want to consider delivering a lower-bandwidth experience.

So how exactly do we target this?

The code

The purpose of this code is to first find the connection speed, and then add a class to the html element based on this connection. The goal is to be able to target these connections with CSS, so the right content is delivered to the right connection:

.highbandwidth .logo   { background-image:url('logo-high.jpg'); }
.mediumbandwidth .logo { background-image:url('logo-medium.jpg'); }
.lowbandwidth .logo    { background-image:url('logo-low.jpg'); }

And here’s the JavaScript:

var connection, connectionSpeed, htmlNode, htmlClass;

// create a custom object if navigator.connection isn't available
connection = navigator.connection || {'type':'0'};

// set connectionSpeed
switch(connection.type) {
  case connection.CELL_3G:
    // 3G
    connectionSpeed = 'mediumbandwidth';
  break;
  case connection.CELL_2G:
    // 2G
    connectionSpeed = 'lowbandwidth';
  break;
  default:
    // WIFI, ETHERNET, UNKNOWN
    connectionSpeed = 'highbandwidth';
}

// set the connection speed on the html element, i.e. <html class="lowbandwidth">
htmlNode = document.body.parentNode;
htmlClass = htmlNode.getAttribute('class') || '';
htmlNode.setAttribute('class', htmlClass + ' ' + connectionSpeed);

Give the user control!

Just as it’s a good practice to give the user a link to the full desktop version of the website, if you’re going to deliver different content based on different connection speeds, then it’s highly advisable to give the user full control.

So give them control! You can provide something like the following:

Mobile | Desktop

Bandwidth: High | Medium | Low

Basic HTML5 template

Wednesday, September 8th, 2010

Introduction

Often times I end up creating short pages for testing short pieces of code, and I only need a very basic HTML template to write in. Short of using HTML5 Boilerplate, I just use a quick piece of code like the following. (note: yes, this has issues in IE, so you may want to use HTML5 Shiv/Shim)

The code

<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title></title>

  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
  <link rel="stylesheet" href=""/>
</head>

<body>
  <header>
  </header>

  <div>
  </div>

  <footer>
  </footer>

  <script src=""></script>
</body>

</html>

Edit: Self-closed tags for compatibility.
Edit2: removed type=”text/css” from the link tag