Monthly Archives: March 2014

Such Little Things

After many Android app versions with perfectly-good icons, it came time to replace them: new launcher icons, new store listing graphic, new action bar icons, and in some cases, removing the icon from the action bar altogether.

For the latter, I preferred an easily-customized manifest entry:

android:icon=”@color/transparent”

This worked nicely for local and ad-hoc installs. So I was surprised when publishing to the Google Play store failed with the obscure yet common error:

Your APK cannot be analyzed using ‘aapt dump badging’.  Error output:

Failed to run aapt dump badging: Error getting ‘android:icon’ attribute: attribute is not a string value

You wouldn’t know it from the message nor from any online suggestions, but that @color/transparent trick was the root cause. So instead I created a 1×1 transparent PNG (ic_empty.png) and used it instead:

android:icon=”@drawable/ic_empty”

BTW, when it’s “icon update” time, I’ve found the quickest way to get scaled icons is to create the 512×512 web version, and point the New Android Application wizard at it.  It’ll create the mdpi, hdpi, xdpi, and xxhdpi sizes for you.

22.6.2, Maybe?

The recent 22.6 Android Developer Tools (ADT) update broke quite a few things: AVD creation and editing, ProGuard, performance, etc.  Rather than revert to 22.3 like many folks, I decided to muddle through with some work-arounds and hold out for the fixes in 22.6.1.

Well, 22.6.1 has arrived and at least fixed the AVD issues, but ProGuard still fails with:

Error: Unable to access jarfile ..\lib\proguard.jar

Fortunately, working around that bug is easy: simply edit proguard.bat and provide an absolute path to the JAR.

Surprise!

Like others before it, this week’s final release of iOS 7.1 brought the rush to grab the latest and greatest. Time to upgrade Xcode (5.1) and the SDK (7.1). Time to load the final iOS 7.1 on devices. Time to repackage and test.

Also like recent updates, this one carried an unwelcome surprise: for over-the-air (OTA) distribution, the plist must now be served over https with a valid (and CA-signed) SSL certificate. I discovered this one the hard way, when ad-hoc OTA installs of my apps failed with “Cannot install applications because the certificate for … is not valid.”  This change was in the 7.1 betas, but I didn’t use OTA distribution for betas.

While I’m sure Apple meant well, this change has real impacts on those of us in the real world who use test servers for deployment, and yet don’t want the security risks that come with proliferating SSL certs. Fortunately, the work-around is easy: serve the plist (and only the plist) via SSL and serve the link and IPA over vanilla http.

Goto Fail

Now that the media frenzy over Apple’s SSL (goto fail) MitM vulnerability has calmed and our iPhones and Macs have been updated, folks are starting to reflect. That’s a good thing. Among other things, this event has pushed issues of code quality, review, testing, patching/updates, version blocking and user notification up the management chain to, hopefully, get more focus and funding.

This had something for everyone and the net is now flooded with commentary on it. I’m certainly not going to repeat that, but consider:

  • Some static analyzers (like Coverity and clang with -Wunreachable-code) would have caught this.
  • Peer code review likely would have caught this.
  • The bug was in the open source community for anyone to find.
  • Vendors everywhere were asking how they could help notify their users and ensure they upgrade.

This one-liner joins the ranks of the most apt and pithy software bugs. It’s right up there with the misplaced break that broke the AT&T network on my 25th birthday. BTW, if your birthday call to me didn’t get through that day, there’s still time; call or message me. But please upgrade your iPhone first.

Back Up

Enabling Up (ancestral) navigation in Android apps is straightforward for the typical case: just specify parent activities in the manifest and send setDisplayHomeAsUpEnabled(true). But non-typical cases (like dynamic parents) require extra steps.

Today I implemented some non-typical cases and experimented with overriding action bar callbacks, tweaking the back stack, etc. But in most cases I simply wanted up navigation to behave like back navigation whenever there was no fixed parent defined. For that, I developed a simple recipe:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId()) {
		case android.R.id.home:
			if (NavUtils.getParentActivityName(getActivity()) != null) {
				NavUtils.navigateUpFromSameTask(getActivity());
			} else {
				getActivity().onBackPressed();
			}
			return true;
		default:
			return super.onOptionsItemSelected(item);
	}
}