Mark L. Murphy's Blog, page 61
November 21, 2013
libhoudini: What It Means for Developers
At AnDevCon last week, I found out about libhoudini, so while it is a bit of tech that has been around for a while, I suspect that other developers may have missed out on it as well.
libhoudini is a proprietary ARM translation layer for x86-powered Android devices. It allows an app that has NDK binaries for ARM, but not x86, to still run on x86 hardware, albeit not as quickly as it would with native x86 binaries.
Given ARM’s near-stranglehold on the Android ecosystem, libhoudini is hugely useful for Intel and hardware vendors interested in using Intel’s mobile CPUs. Without it, only apps that ship x86 NDK binaries would be compatible with x86-powered devices like the Samsung Galaxy Tab 3 10.1” tablet. Some developers probably skip x86 NDK binaries, because they are not aware of popular x86-powered devices, or lack one for testing, or are concerned over APK size. The Play Store for x86 would shrink substantially from the million-plus apps available to ARM devices, to those that do not use the NDK or happen to ship x86 binaries. libhoudini makes ARM-only NDK binaries usable on x86, giving x86-powered Android devices access to more of the Play Store catalog.
However, it is slower.
As an experiment, I ran the test suite for SQLCipher for Android on an ASUS MeMO Pad FHD 10, both with the x86 binaries and without. After all, some developers are nervous about using SQLCipher for Android for encrypted data stores due to the size of the library. Supporting x86 in addition to ARM adds another 5MB to the app, on top of the 6.5MB spent for ARM and the platform-neutral pieces. Being able to use SQLCipher for Android without the x86 binaries might be useful, particularly for apps bumping up against APK size limits, like the 50MB limit on the Play Store.
The good news is that SQLCipher for Android runs nicely on libhoudini-equipped x86 hardware, without the x86 binaries.
The bad news is that the test suite takes about three times as long.
Now, the test suite is not geared towards performance testing, nor is is necessarily indicative of the performance you would see in production code. Hence, you may wish to do your own testing. Testing is easy enough: just temporarily move the x86/ directory from libs/ somewhere else, then recompile and test on libhoudini-equipped hardware. If you do not have your own libhoudini-equipped hardware, you may be able to take advantage of services like Samsung’s Remote Test Lab, which recently added the Galaxy Tab 3 10.1 to its lineup.
If you have the space for it, include the x86 binaries for your NDK-compiled libraries. This will give you maximum speed for little incremental engineering cost. However, if space is at a premium, libhoudini may allow you to reach many of the same x86 devices, but be sure that your app will run acceptably given the performance overhead.
November 20, 2013
Have API, Won't Travel
Vision Mobile has a blog post outlining the progression of APIs from Android into Google Play Services.
Been there, blogged that. :-)
Of course, Google isn’t the only one pursuing proprietary lock-in. Samsung’s mobile SDK is similarly proprietary, with licensing terms that can be best described as #epicfail. Amazon has theirs, and so on.
The key to any vendor offering an alternative to a leading proprietary solution is to convince developers to code to their alternative API. Unfortunately, so far, this seems to be matter of vendors taking the approach of “build an alternative API, and the world’s developers will beat a path to your door”.
This has not been a strong approach, historically.
On the whole, developers obey the laws of physics. One of Newton’s laws is that objects at rest remain at rest; similarly, developers at rest (with respect to a particular API caetgory) tend to remain at rest. Providing an alternative (say, Amazon’s maps instead of Google’s maps) on its own typically is insufficient.
Market share can help. Samsung will have an easier time convincing developers to code to Samsung-specific APIs than will, say, ARCHOS.
But if vendors want to offer a serious alternative to someone’s proprietary API, they need to make it easy for developers. Not only offer the carrot of market share, but remove the stick of “oy, that’s a lot of work”.
Face it: if developers need to write their own wrappers to work with N vendor-specific APIs for, say, in-app purchases, many developers will elect to set N=1 and only code to one such API (e.g., Google’s). If, however, developers can code to a single API and gain compatibility with N vendors’ worth of devices and market share, that will be more compelling.
The One Platform Foundation is trying this with Open In-App Billing. To a lesser extent, Amazon’s Simple Notification Service (SNS) can support Google’s GCM as well as their own equivalent, Apple’s solution, and others besides. And, of course, there are various ad network wrappers designed to isolate developers from network-specific integration woes.
But that sort of cross-vendor collaboration is going to be needed in general if vendors wish to break the stranglehold that popular proprietary APIs hold. We need the single mapping API, the Amazon SNS equivalent that can work beyond the Kindle Fire series, the single active stylus API (supporting Samsung’s S-Pen and anyone else going the active-stylus route), the local networking API (wrapping Samsung’s Chord, perhaps using Qualcomm’s AllJoyn or ZeroMQ as an alternative), etc.
Just because you have an API does not mean that developers will use it. It needs to be easy to use and worth the effort. The maximum possible “easy to use” and “worth the effort” is a cross-vendor solution that becomes the ecosystem’s default approach to solving the problem. Perhaps more vendors will pursue this path over time, or maybe some open source developers will “scratch their itch” and create some.
Anyone who wants a more open Android should want more open API options.
November 18, 2013
The Busy Coder's Guide to Android Development Version 5.3 Released
Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 5.3, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!
NOTE: The book production process was overhauled in this release. I am more aggressively compressing the images, to try to keep the PDF under 50MB. Also, I have rebuilt the EPUB generation, which in turn affects the APK and MOBI/Kindle formats. If you encounter any problems with these new editions, contact wares@commonsware.com for assistance.
This update adds over a bit shy of 70 pages and contains:
Another chapter on Gradle, focusing on the Gradle for Android plugin and the new project structure, covering build types and product flavors along the way.
Compatibility-related pointers for Android 4.4.
An update of the coverage of SQLCipher for Android to version 3.0.0 of that library.
Additions to the coverage of drawables (ColorDrawable and my gif2animdraw script), secondary screen support (reviewing the PresentationSlidesDemo that I used at Samsung DevCon), SQLite (covering ROWID), video recording (with a sample for recording via startActivity() and a camera app), HTTP clients (with a new section on Ion), SearchView, and action modes (covering starting an action mode via a long-click).
Miscellaneous updates and errata fixes.
The next update is not planned until mid-January, barring something really unusual happening in the Android app development ecosystem between now and then. That update will contain yet more Gradle coverage, deeper dives into new Android 4.4 capabilities, more chapters on wearables, and more.
NOTE: Version 5.3 is the last version that will contain a chapter on Maps V1, as by the time Version 5.4 comes out in January, Maps V1 will have been deprecated for over a year. If you are still using Maps V1, make sure that you hold onto your copies of Version 5.3 of the book, in addition to downloading Version 5.4 when it comes out.
November 15, 2013
Linkify and autoLink Need a Custom URLSpan
Many of you use android:autoLink in TextView widgets to convert URLs, email addresses, phone numbers, and the like into clickable items. Each launches an activity to handle the request, via an ACTION_VIEW Intent on a suitable Uri.
Under the covers, this is handled via Linkify, and many of you use Linkify directly, as it gives you a bit more control over what gets converted into links and how.
The problem is in the class that implements the links themselves: URLSpan.
URLSpan is a CharacterStyle, used to format text in a TextView. As with other styles, like ForegroundColorSpan, it applies a visual effect to a range of characters inside of a CharSequence, specifically something that implements the Spanned interface. As the name suggests, URLSpan is used for formatting links to URLs.
URLSpan is also a ClickableSpan, one that can be clicked upon by the user to perform some action. The URLSpan is called with onClick(), much like an OnClickListener does.
The problem lies in its onClick() implementation: it just blindly calls startActivity() on the Intent that it creates.
Nowadays, startActivity() is a riskier operation than it had been before. It is very possible that there will be no activity to handle a particular URL structure, particularly on Android 4.3+ devices for users running in a restricted profile. But URLSpan does not catch the ActivityNotFoundException that could be thrown by startActivity(), and there is no standard place where you could introduce your own try/catch block to handle places where onClick() fails.
The solution is to create your own span, one that handles the ActivityNotFoundException in a manner that fits your application, and apply it to the SpannedString that comes out of the autoLink/Linkify process.
private static class DefensiveURLSpan extends URLSpan {
public DefensiveURLSpan(String url) {
super(url);
}
@Override
public void onClick(View widget) {
try {
android.util.Log.d(getClass().getSimpleName(), "Got here!");
super.onClick(widget);
}
catch (ActivityNotFoundException e) {
// do something useful here
}
}
}
You can apply that by finding all the current URLSpan instances and replacing them with your own class:
private void fixTextView(TextView tv) {
SpannableString current=(SpannableString)tv.getText();
URLSpan[] spans=
current.getSpans(0, current.length(), URLSpan.class);
for (URLSpan span : spans) {
int start=current.getSpanStart(span);
int end=current.getSpanEnd(span);
current.removeSpan(span);
current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
0);
}
}
Note that you do not want to call setText() on the TextView, thinking that you would be replacing the text with the modified version. You are modifying the TextView’s text in place in this fixTextView() method, and therefore setText() is not necessary. Worse, if you are using android:autoLink, setText() would cause Android go back through and add URLSpans again.
You may also wish to keep tabs on this issue, which is tracking a requested change to URLSpan to handle this scenario better.
Introducing CWAC-MasterDetail
Now that I have delivered my “Mastering the Master-Detail Pattern” presentation three times in the past month or so, it’s about time I actually release some related code.
Hence, I’d like to introduce you to CWAC-MasterDetail.
This library is designed to bundle up a number of recommended Android design patterns into a single reusable implementation. Today, it supports:
the master-detail UI pattern…
…with a ViewPager for the detail on screens too small to show both the master and the detail at once…
…with support for multiple-choice on the master ListView and an action mode (a.k.a, contextual action bar) for operations to be performed against the chosen items
Over time, I plan to add support for:
more options for full screen and immersive modes
support for the undo bar pattern for destructive operations
and a variety of other things not directly covered in the Android design guidelines
The library is specifically designed to work as a JAR, not an Android library project, as I am finding that developers often get confused as to how to use an Android library project. That will be dramatically improved as the new build system rolls out and we can standardize on AAR packaging for Android library projects, but in the near term, you can use it as a JAR if desired.
These are very early days for this library, but it should mature fairly nicely over the next couple of months, as I will be using it for some specific projects.
As with the other active CWAC libraries, this one is licensed under the Apache License 2.0, for fairly friendly use in open source and commercial projects.
November 7, 2013
The Troubling Tale of android:priority
About six weeks ago, I warned about the possibility of man-in-the-middle (MITM) attacks on exported services. In there, I wrote:
…what happens if there are two (or more) services installed on the device that claim to support the same <intent-filter>, but have different package names? You might think that this would fail on install, as happens with providers with duplicate authorities. Alas, it does not. Instead the first one in “wins”.
The last bit, about installation order, is true… assuming that both services have the same android:priority value in the <intent-filter>.
If you read the documentation for android:priority, you will notice that it only covers activities and ordered broadcasts. Worse, the activities documentation seems to be in error – AFAICT, only a system app can take precedence over other apps’ activities using android:priority. Ordered broadcasts are where most Android developers encounter android:priority.
The documentation does not mention services. Silly me thought that android:priority played no role with services.
The key word in that previous sentence was “silly”.
Dominik Schürmann’s work on uncovering the bugs in Google Play’s in-app billing pointed out that android:priority does play a role with services. If two or more services are installed, each exporting the same basic <intent-filter> structure (e.g., same <action>), the one with the highest android:priority will silently take precedence. Only if there is a tie – such as with no android:priority at all – will installation order determine which one “wins”.
This makes the MITM attack that much easier to execute, as installation order no longer matters quite so much.
As I wrote previously, if you want to make sure that you are talking to the right third-party app, by any IPC mechanism, you will need to compare the public keys. The public key that signed an app is part of the APK; only apps signed by the same private key should contain the same public key. I will point you to that previous blog post for some discussion of how to check the public key. Note that this material is also covered in the current update of my book, and I will be augmenting that coverage to mention the android:priority aspect of the problem in the next book update.
November 6, 2013
Android 4.4 Permission Regressions
Edison Wang tweeted a change in the behavior of ACTION_MEDIA_MOUNTED.
From the SDK standpoint, this was a broadcast that developers were meant to consume, by having a BroadcastReceiver listening for it. However, many blog posts, StackOverflow answers, and the like advocated having apps send that broadcast, as it triggered a complete re-scan of external storage, for the purposes of MediaStore.
Sending such a broadcast would trigger warnings in LogCat in Android 4.3, but now, as of Android 4.4, I can confirm that your app will crash with a SecurityException for trying to send it. Instead, use MediaScannerConnection or ACTION_MEDIA_SCANNER_SCAN_FILE to request indexing of new files.
Also, Sven Knispel reported that the BATTERY_STATS permission is now system|signature. This should impact relatively few applications, as I am not aware that BATTERY_STATS was used for anything that is part of the Android SDK. However, if you were breaking past the boundaries of the SDK and poking at some battery details by one means or another, note that this may no longer work.
November 4, 2013
New Meta-Data Tag for Maps V2
If, when trying to use the new Google Play Services SDK, you encounter an error message like:
Caused by: java.lang.IllegalStateException: The meta-data tag in
your app's AndroidManifest.xml does not have the right value. Expected
4030500 but found 0. You must have the following declaration within the
element: <meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
follow the instructions and add the following <meta-data> tag to your manifest, alongside the existing <meta-data> tag for your API key:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
For whatever reason, this does not appear to be covered in the current documentation, or the release notes.
Note that I have not tried any anything else from the new Play Services SDK yet, so it is entirely possible that this is also required for other facets of that SDK (GCM, LocationClient, etc.).
Many thanks to StackOverflow user Benoit for pointing this out and helping to spread the word!
November 1, 2013
Quick Musings on Android 4.4
Based on a quick review of the documented changes for Android 4.4, here are some preliminary thoughts regarding areas of potential incompatibility with your app, beyond the SMS changes that I blogged about previously, and of particular relevance to readers of my book:
If you are using WebView, start testing your app on Android 4.4 immediately. The WebView implementation is now overhauled, with Chromium at its core. While in theory your app should not change if your android:targetSdkVersion is less than 19, you will want to double-check that as soon as possible. When you do start considering migrating to android:targetSdkVersion of 19, please read the migration guide closely, as a lot has changed. Also, please note that you should be switching from loadUrl("javascript:...") to evaluateJavascript(), as ” Apps targetting KITKAT or later that load a JS URL will have the result of that URL replace the content of the current page”.
If you have not added the READ_EXTERNAL_STORAGE permission to your app yet (or WRITE_EXTERNAL_STORAGE), and you are accepting Uri values from third-party apps, add the READ_EXTERNAL_STORAGE permission now. Otherwise, you may not be able to access the content at those Uri values, if they point to external storage.
The exception to the above rule is that getExternalFilesDir(), getExternalCacheDir(), and their new plural equivalents (e.g., getExternalFilesDirs()), do not require READ_EXTERNAL_STORAGE. Basically, if you stick to your own application specific location(s), you do not need the permission, but you do if you write anywhere else on external storage.
The first crack in the “one external storage only” policy has occurred, as now there are getExternalFilesDirs() and getExternalCacheDirs() methods on Context. These can return multiple values, representing locations on multiple forms of external storage (e.g., on-board flash partition and a removable card). Of course, it requires a manufacturer to actually support this. And, since no Nexus device has removable card support, the only near-term way we might see how this behaves will be via USB OTG accessing a thumb drive or something, and that’s no sure thing. And, there is no plural equivalent for the classic methods on Environment (e.g., getExternalStorageDirectory()), so while this is a “tip o’ the cap” in the direction of multiple forms of external storage, it is unlikely to completely solve developers’ problems in this area.
The release notes indicate that Android 4.4 will “now more aggressively protect system memory from apps consuming large amounts of RAM”. The only concrete explanation of what that might mean probably is misstated. The release notes say “When multiple services start at once — such as when network connectivity changes — Android now launches the services serially, in small groups, to avoid peak memory demands”. However, services cannot respond directly to things like “network connectivity changes” and not be running already — such changes are handled via listeners (requiring an already-running service) or a broadcast Intent (which does not necessarily imply anything about a service). Hence, at least at the moment, I am interpreting “services” as “processes” in those release notes, as that would make a bit more sense. It does mean, though, that apps relying upon rapid response to system broadcasts may encounter unexpected delays.
Once you target API Level 19 or higher, you will need to override isValidFragment() in your PreferenceActivity, to validate that the supplied fragment class name is indeed something that should be displayed. Off the cuff, this feels like some hack to deal with a security flaw.
Note that there is a new density, known as DENSITY_400 in DisplayMetrics. You should only really need to worry about this if you are working with density buckets directly in Java code or are seriously anal about pixel perfection with your drawable resources.
A ContentProvider can now have an <intent-filter>, in support of the new document provider framework. It is unclear what this will mean for other providers, if anything.
Those of you using AlarmManager will need to bear in mind that set() and setRepeating() will start becoming inexact once you target API Level 19. Sync adapters will similarly “flex” their scheduling. Both of these are in the interests of saving power.
App Ops seems to be making a comeback, but since I do not see KitKat source code available, I am reserving further judgement until I get my hands on some Android 4.4 hardware.
Only having an ARM emulator makes $BABY_DEITY cry.
There are likely plenty of other areas of compatibility concern, in areas beyond the scope of my book (e.g., media changes). You should review the KITKAT version details to learn more about changes that will occur when you change your android:targetSdkVersion to 19 or higher, in addition to the release notes, the other release notes, and the API differences report.
October 29, 2013
Secondary Display Support: Presentation and Errata
Yesterday, at the Samsung Developer Conference, I delivered a presentation on supporting secondary displays from your Android app, so you can push custom content to a TV, projector, or monitor. I have uploaded the slides to this presentation… but I have a couple of errata to report.
First, the way I referenced SlimPort in the slides was inappropriate. I had forgotten about SlimPort when I was working on the presentation originally, as few devices support SlimPort. When I remembered it, I basically went to the first slide where I mentioned MHL and added SlimPort to the same bullet… not noticing that the bullet I was adding it to was defining the MHL abbreviation (“Mobile High-Definition Link”). While SlimPort serves a similar role as does MHL, SlimPort is not MHL, and I apologize for creating a slide that suggested it.
Second, I implied, in the slides and my delivery, that the way to connect MHL devices to displays involves an MHL->HDMI cable or adapter. While this works, it turns out that there are some TVs and monitors that offer native MHL ports, so a direct MHL->MHL cable can work with those. Examples include the Dell P2314T monitor and the LG 50LN5400 TV. More displays are expected to include native MHL ports as time progresses, and you can monitor the MHL site for a list of displays offering MHL support. Note, though, that not all of these displays may be sold in your area.
Finally, I indicated that the simulated secondary displays worked with hardware but not the x86 emulator. It turns out that the latest x86 4.2 emulator image does support simulated secondary displays, via the Developer Options portion of Settings. Alas, the 4.3 x86 emulator image suffers from the same problems as I had seen previously with the 4.2 image, where the overlay appears but is black, rather than showing a mirror of the primary display or the Presentation that you are trying to show.
Many thanks to Michael Bergen (MHL) and Eric Mantion (Intel) for helping me with these errors.


