Hey Samsung: It’s the Software

Samsung is an amazing hardware company. My TV, refrigerator, electric razor and dvd player are all made by Samsung. They also make two of my favorite smartphones: the Nexus S, and the Galaxy Nexus. They also make 3 of my least favorite devices: The Galaxy S2, Galaxy S3, and Epic 4G. But what separates my favorite phones from my least favorite phones is the software.

Epic 4G

This phone has great hardware. It’s light, comfortable, built quite solidly, and has slide out keyboard with a very nice feel to it. But it’s the software that makes this my least favorite phone. Aside from being glacially slow with Android OS updates (6-9 months behind), these updates failed to fix my biggest complaints. They made some awful UX decisions that are just unacceptable. The worst may be their decision to decide how I use my battery: when the battery reaches 20%, they shut down the camera and video camera. This does not help me conserve battery, this just makes my (already short) battery life even shorter. I’d like to decide how I use the last 20% of my battery life. To me, taking pictures of my daughter is more important to me than making calls.

Galaxy Nexus

Like I hinted at, this is the best phone I have ever owned. Both the hardware and software blow away any competitor. This phone has cutting edge hardware AND cutting edge software. What’s the difference? Samsung did not make the software. The best phone ever made had hardware made by a great hardware engineering company (Samsung) and software made by a great software engineering company (Google).

Galaxy S2

This is a beautiful phone, with a beautiful screen, fast CPU, etc. etc. Again, cutting edge hardware (or, was cutting edge when it was released). In fact, its specs are very similar to the Galaxy Nexus. So what makes the Galaxy Nexus the best phone ever made, and the Galaxy S2 one of my least favorite phones? Not to beat you over the head, but it’s the software.

It’s the Software

As an Android developer, the second most time consuming part of my job (after internationalization) is dealing with software problems created by hardware manufacturers (not just Samsung; I’m pointing the finger at HTC, LG, and so on, too).

So, why does Andie Graph not work on the Samsung Galaxy S2? It’s the software. Samsung’s (and HTC’s) OS firmware is not compatible with every app, and Andie Graph is one of those. If you want to run Andie Graph on the Samsung Galaxy S2, it will happily run on non-Samsung firmware (try CyanogenMod, or an AOSP-based ROM).

Why does Andie Graph not work on the Samsung Galaxy S3? It’s the software.

Stop it!

Here is my plea to hardware companies: please concentrate on what you do best. Please make your great hardware even more great! Please make it fast, light, beautiful, long-lasting, amazing. Distinguish yourself by making your hardware the best. Leave the software design to the software engineers.

*By the way, Apple falls into the same category: they make great hardware (even, the best hardware). But other than OSX, they don’t make a single piece of software that I like to use.

Phone Number Formatter

When writing apps, you often re-use your code, improving it along the way. One function I’ve used in at least 4 apps (iDialer, web, Phone.com Android app, and another unannounced app) and implemented in 3 languages (Java, Javascript, C) is a phone number formatter.

My requirements for this seemingly simple function:

  1. It must use an easy to configure “dial plan” for formatting.
  2. It must be able to format a “partial” phone number, i.e. one you’re typing in right now, or a complete phone number
  3. It must be able to emulate the behavior of the very excellent iPhone dialer.

Javascript:

To see an older iteration of the function in Javascript, look at my iDialer config page, click on the dialplan “advanced” link.

C:

For an even older iteration, look at my iDialer source code.

Java:

Here is my most current solution, in JAVA:


	/**
	 * A semicolon separated list of formatting strings to format. "N"
	 * represents any single digit. [1-9()-] represents an exact digit. The
	 * underscore "_" represents a SPACE (not an underscore). These rules will
	 * be followed sequentially until one is matched.
	 */
	private static final String DIALPLAN = "+1_NNN_NNN_NNNN;1_(NNN)_NNN-NNNN;NNN-NNNN;(NNN)_NNN-NNNN";

	/**
	 * Formats a phone number according to the rules defined in
	 * {@link #DIALPLAN}.
	 * 
	 * @param number
	 *            the non-formatted number
	 * @param isPartialOk
	 *            true if the number passed in "number" are just the first few
	 *            digits of the formatted number. This might be the case on a
	 *            dialpad where the number is being inputted right now
	 * @return
	 */
	public static String formatDialplanNumber(String number, boolean isPartialOk) {
		StringBuilder output = new StringBuilder(32);

		/*
		 * k = index of "number" that we're trying to match d = index of
		 * "DIALPLAN" that we're trying to match cd = character of "DIALPLAN" at
		 * index "d" cn = character of "number" at index "k" ln = length of
		 * "number" match = does it match so far
		 */
		int k = 0;
		boolean match = true;
		int ln = number.length();
		for (int d = 0; d < DIALPLAN.length(); d++) {

			char cd = DIALPLAN.charAt(d);
			char cn = k < ln ? number.charAt(k) : 0;

			// move on to the next rule
			if (cd == ';') {
				if (match && k == ln)
					break;

				k = 0;
				match = true;
				if (output.length() > 0)
					output.delete(0, output.length());
				continue;
			}

			if (!match)
				continue;

			// next character in "number" must match exactly
			if (cd == '+' || cd == '#' || cd == '*' || cd >= '0' && cd <= '9') {
				if (k < ln && cn == cd) {
					output.append(cd);
					k++;
				} else {
					match = false;
				}
			}

			// next character in "number" must be a digit
			else if (cd == 'N') {
				if (k == ln) {
					if (isPartialOk)
						output.append(' ');
					else
						match = false;
				} else if (cn >= '0' && cn <= '9') {
					output.append(cn);
					k++;
				} else {
					match = false;
				}
			}

			// just add space to the output
			else if (cd == '_') {
				output.append(' ');
			}

			// just add the literal character to the output
			else if (cd == '(' || cd == ')' || cd == '-' || cd == '.') {
				output.append(cd);
			}
		}

		if (!match || k != ln) {
			// Didn't match anything... just rely on built-in phone number
			// formatter
			return PhoneNumberUtils.formatNumber(number);
		}

		// Remove non-numbers from the end of the string
		int end = output.length();

		int i = output.indexOf("( ");
		if (i > -1)
			end = i;

		while (end > 0
				&& (output.charAt(end - 1) == ' ' || output.charAt(end - 1) == '-')) {
			end--;
		}

		String formatted = output.substring(0, end);
		return formatted;
	}

Antennagate

Certainly you’ve heard of “Antennagate” by now. It’s all the hype surrounding the fatal flaw in the iPhone 4′s genius new antenna design that causes it to lose quite a bit of signal strength when you hold the phone. I haven’t tried it myself, but I have tried holding a couple of my other phones in a way that would consistently make them lose signal strength.

Interesting fact #1: No matter what I do, I cannot get the iPhone 3GS to lose signal strenth. Even if I completely surround the phone with both of my hands.

Interesting fact #2: I can cause my HTC EVO 4G to lose signal strength consistently, by holding it in a way that I would never actually hold it. Holding it in this position also disables the camera. Good thing there’s a backup camera up front :)