Mark L. Murphy's Blog, page 58
April 8, 2014
The Storage Situation: External Storage
There is a lot of confusion regarding Android’s storage model. That confusion has only increased with Android 4.4’s changes to that storage model. There are countless StackOverflow questions and the like where they clearly do not quite grok the various pieces of Android’s storage model.
This is the second post in a five-part series covering this storage model, to help clarify what is going on. Today, we will look at “external storage”… including its various definitions.
What Your Users Think “External Storage” Means
Many Android device users will have no idea what “external storage” means. There is nothing in the device UI that will necessarily use that term.
Users who visit Settings > Storage may see only “Internal Storage”:
   
Or, they may see both “Internal Storage” and “SD Card”:
   
Hence, at best, your users will think that an SD card is external storage. That’s not quite right. Except on Android 4.4+, in which case it is only sorta right.
(yes, this is all rather confusing)
What Google Thinks “External Storage” Means
The Android SDK documentation has this to say in terms of a definition of “external storage”:
Every Android-compatible device supports a shared “external storage” that you can use to save files. This can be a removable storage media (such as an SD card) or an internal (non-removable) storage. Files saved to the external storage are world-readable and can be modified by the user when they enable USB mass storage to transfer files on a computer.
The vast majority of what has been written so far, in the documentation and elsewhere, about external storage was for the pre-4.4 world. In those halcyon days of yesteryear, there was a single volume known as “external storage”, and it was effectively defined as “the stuff that shows up when the user plugs their device into a computer using a USB cable”. Even that wasn’t completely accurate, as some manufacturers would also allow access to their devices’ removable media via the USB cable as well. And Android 4.4 has added yet more wrinkles in terms of removable media… which is why removable media gets its own blog post tomorrow.
For the purposes of this blog post – and to line up with what most other written material will refer to – “external storage” is defined as the directory tree returned by Environment.getExternalStorageDirectory()).
The Many Places Where External Storage Is Stored
External storage, like a tumbleweed, goes where the wind blows it.
In Android 1.x and most 2.x devices, external storage was generally some form of removable media, typically a micro SD card. More importantly, for all Android 1.x and 2.x devices, external storage was a separate partition with a separate filesystem. While a few Android 2.3 devices elected to use on-board flash for external storage, that was still a separate partition from the partition that held internal storage. As a result, we wound up with devices that might advertise having several GB worth of storage, but that storage tended to be mostly for external storage, as the partitions could not be resized by ordinary users.
Android 3.0 changed this around, allowing internal and external storage to each be on the same partition, just in separate directory trees. This provided a lot more flexibility for users, as now there was no artificial hard distinction between space for internal storage and space for external storage. Device manufacturers still could elect to have external storage be a separate partition, or even be on removable media, but typically they did not.
The Many Paths Under Which External Storage is Stored
For us as developers, the actual path under which this magical “external storage” was accessed varied over the years, from /sdcard, to locations under /storage, to eventually the current /mnt/shell/emulated/0. And just as secondary users of an Android 4.2+ tablet get their own internal storage, they get their own external storage, with its own root directory.
Hence, as I mentioned yesterday:
NEVER HARDCODE PATHS
Use various methods to get the base directory to work from… though this too has gotten more complicated over the years.
In the beginning, everyone used Environment.getExternalStorageDirectory(), which pointed to the root of external storage. This led to external storage being just a big basket of random content.
Later, Google offered more organization:
getExternalFilesDir() and getExternalCacheDir() on Context, pointing to an application-specific directory on external storage, one that would be deleted when the app is uninstalled
Environment.getExternalStoragePublicDirectory(), for centralized places to store well-known file types, like photos and movies
Note that there the Context methods have plural forms on Android 4.4+ (getExternalFilesDirs() and getExternalCacheDirs()), which ties into removable media, which we will get into more tomorrow.
External Storage and Permissions
Just as the location – physically and logically – of external storage keeps changing, so does our ability to work with it.
Originally, apps could do whatever they wanted.
Android 1.5 added the WRITE_EXTERNAL_STORAGE permission, which apps had to hold to be able to write files to external storage. That way, the user would be informed at install time that the app intended to modify external storage contents. Any app could still read from external storage, though.
Android 4.4 is now enforcing a READ_EXTERNAL_STORAGE permission, so you cannot even read from external storage if you do not hold some permission. Note that WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE, so you only need one of those, not both. And, for getExternalFilesDir() and getExternalCacheDir(), you do not need either of those permissions – you can read and write in those directories with impunity. Android now has an android:maxSdkVersion attribute on <uses-permission>, specifically so that you can drop WRITE_EXTERNAL_STORAGE if you no longer need it, because you are only working with getExternalFilesDir() and getExternalCacheDir().
Poking Around External Storage
As a developer, assuming that you can find where external storage really resides for your version of Android, you have unfettered access to it from DDMS, for both emulators and production devices.
You can also use a USB cable, much like your users will use. However, bear in mind that what is presented to the USB interface is not what is on external storage… but, instead, is what has been indexed on external storage in the MediaStore. Hence, unless you take steps to ensure that new files that you create get indexed, they may not be immediately visible.
Under the covers, Android is using the Media Transfer Protocol for its USB communications. This enables a lot more flexibility than does Mass Storage Mode (a.k.a., what thumb drives use) that Android used originally. However:
some MTP clients may cache directory listings, so even after you get your file indexed by MediaStore, an already-attached client may need to be refreshed
I eagerly await a decent MTP solution for Linux (while Ubuntu’s support is better than it used to be, I still get squirrelly results, particularly for advanced I/O operations like “delete”)
Frequently-Asked Questions
Here are some FAQs about what the SDK refers to as external storage:
How Do I Secure My Files on External Storage?
In general, you don’t. The user has complete access to external storage, and other apps can get to external storage if they hold the right permissions.
One thing that you can do is use something like Facebook’s Conceal. This encrypts your files on external storage, but uses a generated encryption key kept on internal storage. From a security standpoint, the net effect is to make external storage closer to internal storage in terms of read access. Note, though, that Conceal cannot prevent other apps, or the user, from deleting your files on external storage, or perhaps trying to write to them and corrupting the files as a result.
What About Apps-On-SD?
I mentioned yesterday that internal storage used to be as little as 70MB.
(and that’s still not a typo)
There was a hue and a cry to allow applications to be installed to external storage, as a way of providing more space for those apps. Android 2.2 added such a capability, via the android:installLocation attribute on the root <manifest> element in your manifest file.
However, once Android 3.0 shipped, this became less useful, because internal and external storage share a common partition.
My understanding is that you can only move an app to external storage nowadays if you have a device for which external storage is still a separate partition. Personally, out of the 50+ devices in my Secret Mountain Lair, I have zero that are on Android 3.0+ that have external storage as a separate partition, so I cannot confirm this behavior.
Now, of course, the hue and cry have moved to putting apps on removable media, as power users are running out of room on 32GB devices for all their apps. It is conceivable that Google will extend android:installLocation to support removable media, though I am not exactly holding my breath.
The Rest of the Posts
The entire blog post series will cover:
Internal storage, as defined by users and Google
External storage, as defined by users and Google
Removable storage, and where things have gone off the rails
Where Google went wrong with all of this
Where developers went wrong with all of this
April 7, 2014
The Storage Situation: Internal Storage
There is a lot of confusion regarding Android’s storage model. That confusion has only increased with Android 4.4’s changes to that storage model. There are countless StackOverflow questions and the like where they clearly do not quite grok the various pieces of Android’s storage model.
This is the first post in a five-part series covering this storage model, to help clarify what is going on. Today, we will look at “internal storage”… including its various definitions.
What Your Users Think “Internal Storage” Means
Your users will eventually wander into Settings > Storage on their device and see a screen that describes “Internal Storage”:
   
And that will be that. The user thinks that all of the on-board flash is “internal storage”.
What Google Thinks “Internal Storage” Means
Alas, that is not what the Android SDK thinks “internal storage” means, which is where some of the confusion lies.
If you read the Android documentation on internal storage, the description is… hand-wavy:
You can save files directly on the device’s internal storage. By default, files saved to the internal storage are private to your application and other applications cannot access them (nor can the user). When the user uninstalls your application, these files are removed.
In truth, the Android SDK’s definition of “internal storage” is a specific directory, unique to your app, where your app can place files. As suggested in the docs, those files by default are read-write for your app and deny-all for any other app.
(exception: users running file managers with superuser privileges on rooted devices can access anything)
There are a handful of base methods on Context that give you access to internal storage, including:
getCacheDir()
getDir()
getDatabasePath()
getFilesDir()
openFileInput()
openFileOutput()
Other methods will rely upon these, such as openOrCreateDatabase(). Other classes also will rely upon these, such as SQLiteOpenHelper and SharedPreferences.
Where Internal Storage Is Stored… Sometimes
If you look around various blog posts, StackOverflow answers, and books that came out in 2012 or earlier, you will be told that your app’s “internal storage” resides at:
/data/data/your.application.package.name
(where your.application.package.name is replaced by your application’s package name, as is declared in the manifest or modified via Gradle)
Inside of there will be some directories automatically created by Android as you use some of those Context methods. For example, getFilesDir() returns a File object that points to a files/ directory inside of your app’s internal storage.
Where Internal Storage Is Stored… The Rest of the Time
However, this is not always where your app’s internal storage resides. If there is one rule for developers that you should take away from this blog post series, it is:
NEVER HARDCODE PATHS
Every now and then, I will see developers do something like this:
File f=new File("/data/data/their.app.package.name/files/foo.txt&...
This is really really dumb.
First, it is more typing than using getFilesDir():
File f=new File(getFilesDir(), "foo.txt");
More importantly, internal storage is not always at the same place. Notably, on Android tablets, we have the notion of separate user profiles, starting in Android 4.2. Each user gets his or her own “internal storage” area. While the aforementioned directory is still used for the primary user, that is not guaranteed, and it will not be used for secondary accounts.
Poking Around Internal Storage
On an emulator, DDMS has the ability to browse all of internal storage, so you can access file from your app or any other app.
On a rooted device, there are recipes for allowing DDMS the same degree of freedom.
On ordinary (un-rooted) devices, DDMS has no ability to access internal storage. The piece of software on the device that DDMS talks to runs as an ordinary user account on hardware, whereas it runs with superuser privileges on an emulator. The ordinary user on hardware has no ability to get to your app’s files, any more than does any user account associated with any other app.
The recipe for getting at internal storage on hardware is to use the run-as option with adb at the command line. For example, to download a database from the primary user’s internal storage to your development machine, you might use:
adb shell 'run-as your.application.package.name cp /data/data/your.application.package.name/databas... /sdcard
Note that:
You will need to change the destination to wherever on your device external storage is mapped to (shown here as /sdcard/, which will not work on all devices)
You may need to use cat instead of cp on older devices
But, once you run the command, the database will be copied to external storage, which you can access via DDMS, or via any conventional way to get files on and off a device via USB cable (e.g., drive letter in Windows).
Limitations of Internal Storage
On Android 1.x and 2.x devices, internal storage was usually on a dedicated filesystem partition, and that partition was usually rather tiny. The HTC Dream (a.k.a., T-Mobile G1), the original Android device, had a whopping 70MB of internal storage for use by all apps.
(And, no, that’s not a typo. We measured storage in megabytes back then.)
By the time the 2.3 devices were rolling out, internal storage might be as big as 1GB.
Android 3.0 changed the storage model around, in such a fashion as internal storage got more space. Devices that advertise as having 4GB, 8GB, 16GB, etc. of storage space usually had all of that (less existing contents) available for internal storage. We will get into what changed in Android 3.0 and its impacts on the storage model as part of tomorrow’s blog post on external storage.
For Android 1.x and 2.x, internal storage was only really for small files, and you needed to use external storage for everything else. Android 3.0+ means that for most devices and most users, internal storage is fine for files that are not meant to be used routinely by other apps or accessible by the user independently from your app. Some power users, though, will find that even on-board flash is insufficient for what they want to store, so they turn to removable storage… which is a whole ‘nuther can of worms that we will get into later in the week.
Frequently-Asked Questions
Here are some FAQs about what the SDK refers to as internal storage:
Should I Make Files on Internal Storage World-Readable or World-Writeable?
Oh, $DEITY, no. Use FileProvider and serve that content via that ContentProvider implementation. Then, you at least have the option of using Android’s permission system to manage access to those files, versus having any app on the system be able to monkey with those files.
Well, How About android:sharedUserId?
I also counsel against this.
android:sharedUserId is an attribute you can place in your manifest that indicates a logical user ID to be used for your app. Any other app that is installed that is signed by the same signing key and requests the same android:sharedUserId will use the same Linux user from a security standpoint. The net effect is that those two apps will be able to work with each other’s files with impunity, as those files are all owned by the same Linux user.
This attribute is really designed for pre-installed apps, such as some software suite pre-loaded by the device manufacturer, carrier, or ROM mod maintainer. In particular, once you ship your app, you cannot reliably change your android:sharedUserId value without locking your user out of any existing files… as Android does not change the ownership of existing files when it changes the Linux user account that your app runs as.
There are various risks in having multiple processes work simultaneously with files. Some subsystems, like SQLite, have built-in logic to deal with this. But if you are doing your own file access yourself (e.g., via File and Java I/O), then you have to somehow deal with simultaenous access, which can get tricky.
You also have to deal with what happens when one app is uninstalled, taking away files that another app was using. In a hub-and-spoke model, like an app and a suite of plugins, perhaps this is not that risky. In other models, where apps are closer to being peers, you cannot afford to have your app’s data vanish because the user elected to uninstall some separate app.
Finally, you do not know what the future might bring. Right now, you might view your set of apps as a tightly-coupled suite. Somebody who acquires those apps, or acquires your firm, might wish to go a different route. Using data sharing options that are more loosely coupled, like a ContentProvider, gives you greater flexibility than does assuming that your apps should co-mingle their files. In an ideal world, your app should treat other apps as a fairly-reliable but not always avaialble resource, just like you treat your own Web service.
How Do I Prevent Users of Rooted Devices From Accessing My Files on Internal Storage?
Simple: don’t put files on internal storage. Users of rooted devices can access whatever they want on the device, so the only way to prevent them from accessing your data is to not have it on the device.
Some developers will attempt to encrypt their files, using a hard-coded password, to prevent rooted device users from using those files. This does erect a “speed bump”, but it is a small one. All it takes is one person with interest to reverse-engineer your app, determine how to decrypt those files, then write up a blog post or discussion board entry on how to do it.
On the whole, there are relatively few people with rooted devices – I estimate it at well under 1%. IMHO, you will have better success by focusing your engineering work on writing a better app, rather than spending that time trying to block rooted device users.
The Rest of the Posts
The entire blog post series will cover:
Internal storage, as defined by users and Google
External storage, as defined by users and Google
Removable storage, and where things have gone off the rails
Where Google went wrong with all of this
Where developers went wrong with all of this
March 31, 2014
CWAC-LoaderEx and Failed Abstractions
When the Loader framework showed up in Android 3.0, my initial interest was tempered by the fact that there was only one concrete Loader implementation provided by Android. That was CursorLoader, and it required a ContentProvider as the backing store for the data. After the umpteenth question on StackOverflow about trying to use CursorLoader without a ContentProvider, I elected to take a shot at providing other concrete Loader implementations. Specifically, I created the CWAC-LoaderEx library, with three such Loader classes:
SharedPreferencesLoader (because initially loading preferences involves disk I/O)
SQLiteCursorLoader (like CursorLoader, but for working directly with SQLite)
SQLCipherCursorLoader (same as above, but for SQLCipher for Android)
All of them sucked, and so I never used them. Since I never used them, I never maintained them. And, since I never maintained them, I have officially discontinued the project.
This is not to say that CursorLoader sucks. CursorLoader is a fine solution for three common problems:
How do we retrieve data in the background?
How do we retain that data across configuration changes?
How do we arrange to get updated data when the data changes elsewhere in the app?
The first two are handled mostly by the framework itself, through classes like LoaderManager and AsyncTaskLoader. Anyone else implementing an AsyncTaskLoader will get those two features “for free”, more or less.
The third one is the sticking point and is why my loaders sucked.
The framework, on its own, has little means of determining when some arbitrary data changes. Hence, the implementation of this mostly is up to the Loader, with minimal framework assistance.
The problem is that the interesting cases for this feature is where the data is changed in some random spot in your app. For example, a service might update a database. Or some other activity (like a PreferenceActivity) might update a preference.
This begs the question: how does a Loader, attached to a Activity, find out when data of interest changes anywhere in the app?
In the case of SharedPreferences, there is a listener. However, the SharedPreferences instance is not replaced when it is updated – rather, it is updated in situ. This runs afoul of an optimization inside of the Loader framework, where it is assumed that data changes are reflected in object instance changes, such as where a new Cursor replaces an old Cursor. Hence, my SharedPreferencesLoader never really provided a new SharedPreferences when another part of the app updated those preferences.
In the case of a database, we do not even have an Android-supplied listener. Instead, our code that updates the database would have to somehow let the Loader know about those updates. For simplistic cases, such as the Activity hosting the Loader doing its own database manipulation, this is easy. For cases where the data-updating component has no access to the Loader, this is difficult.
The Loader framework effectively assumes that all implementations of loaders:
Have singleton manager objects (like a ContentProvider)
Have distinct data objects per update (like a Cursor from a ContentProvider)
Anything not meeting those requirements does not fit.
Ideally, when the Loader framework was introduced, three or more concrete implementations would have gone into the Android SDK. The act of creating those implementations would have put stress on the Loader design, probably highlighting the aforementioned implicit requirements. That, in turn, might have changed the design. As it stands, I consider Loader to be a bit of a failed abstraction – it works very well for the one concrete implementation and is rather awkward for everything else that I have seen or tried.
So, feel free to use CursorLoader, if you wish to load data from a ContentProvider, whether that is one you wrote or one provided by somebody else (e.g., ContactsContract). And, if you happen to have an environment where a custom Loader really can fulfill all the requirements, explicit and implicit, feel free to do so.
In my case, if I am going to have some singleton manager object, with distinct data objects per operation, I am going to use something more flexible than Loader, such as an event bus.
March 28, 2014
The Busy Coder's Guide to Android Development Version 5.7 Released
Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 5.7, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!
This update:
Adds a dedicated chapter on MediaRouter, including a bit of material out of the chapter on external displays, plus coverage of MediaRouteActionProvider. This includes covering my CWAC-MediaRouter project, a port of MediaRouteActionProvider (and related classes) that allow it to work with the native API Level 11 version of the action bar, instead of requiring you to use ActionBarActivity and, in turn, the fragments backport. This chapter also covers the use of RemotePlaybackClient for playing back media on routes where the playback happens on a remote device… like a Chromecast.
Adds a partial chapter on Chromecast and Google Cast. I wound up beating my head against a wall a fair bit with the RemotePlaybackClient stuff. I wanted to cover the open source library first (contrasted with the Cast SDK, which is proprietary), but RemotePlaybackClient has issues. I am aiming to get to the Cast SDK in the next update.
Adds a small chapter on how to reduce your application size, if you are concerned that your APK is too portly.
Includes some new recommendations in the Miscelleanous Security chapter, such as avoiding accidental APIs, sanitizing your inputs, and so on.
Tweaks some of the tutorials to deal with version 22.6.x of the Android SDK Tools and the ADT plugin for Eclipse. In particular, I have officially given up on starting the tutorial from the new-project wizard, so while Tutorial #2 still includes those steps, they are optional. The real starting point is importing a blank Android project that I am publishing, one that avoids all the cruft (and resulting build errors) in what the Eclipse templates presently generate.
Revises coverage of streaming content providers for enhanced compatibility with client apps (e.g., handles the “why doesn’t QuickOffice open my PDF?” issue).
Updates the Gradle for Android coverage to 0.9.0.
Updates OkHTTP to 1.52 and Retrofit to 1.5.0.
Moves the SSL coverage into a dedicated chapter, to set things up for expanded coverage, including code samples, in future versions of the book.
Your typical smattering of errata fixes and other minor improvements.
As usually, the table of contents will have changed sections shown in bold-italic format, and changebars will indicate specific paragraphs that have changed.
Note that I did remove the SQLCipher for Android tutorial. I discontinued the CWAC-LoaderEx project, as I was not maintaining it, the implementations sucked, and I have largely sworn off the Loader framework as being a failed abstraction. The SQLCipher for Android chapter is still there, but the tutorial was based on SQLCipherCursorLoader, so I removed it. If you are still using that chapter, be sure to hold onto your previous version of the book in addition to obtaining a new one.
The next update is tentatively scheduled for late April.
About the "Pileup" Vulnerabilities
An academic paper made the news recently regarding a new round of vulnerabilities in Android. This paper’s focus was distinctive, though, in that they examined vulnerabilities that occur due to OS upgrades.
…
Yes, some Android devices do get their OS upgraded.
…
No, I’m serious, they do. Stop laughing.
Some of the vulnerabilities are a firmware-centered variant of the problem I pointed out recently with custom permissions. In this case, though, the permissions are system permissions that will be defined in the future.
For example, suppose that, by examining an Android 5.0 device or the published source code, we determined that Android 5.0 added new CONTROL_SEA_BASS and ATTACH_FRICKIN_LASER_BEAMS permissions. We could publish an app that requests these permissions. On older Android devices, we would not be able to use the permissions to do anything. But, for those devices that have our app and get upgraded to Android 5.0, we would automatically get the permissions, without user knowledge… even system or signature-level permissions.
(and one would certainly hope that these would be system-level permissions – imagine the damage that could be wrought with CONTROL_SEA_BASS!)
There are other variants on the theme, where the app can arrange to get things that it ordinarily could not, because of the particular algorithms and processes used when applying an OS upgrade.
From my reading of the paper, little of this affects app developers specifically. If anything, pre-installed apps (e.g., AOSP, Google app, manufacturer apps) appear to be at greater risk than ordinary SDK apps. Users are at risk, and while the frequency of possible attack is low (since OS upgrades are at best infrequent), the possible damage is substantial.
If, in your reading of the paper, you can think of ways that ordinary app developers might be affected by Pileup flaws, drop me a line.
March 26, 2014
Gradle for Android... And You! Free Webinar
As part of my regular webinar series, I am offering a free 30-minute webinar on Gradle for Android.
This webinar is designed for people who have perhaps heard about Gradle for Android but are not using it today and may not understand its role or why it will be important for all developers, starting here in 2014.
This is not a deep technical dive into using Gradle for Android – Gradleware and I have a half-day virtual training class for that. Instead, this presentation is to explain why you should be thinking about Gradle for Android now, even though it has not yet quite reached a 1.0 release.
If this intrigues you, sign up!. Space is limited, though there are four sessions to choose from, in April and May.
March 17, 2014
Dual Screen App Challenge
One of the areas that I have spent a bit of time on in the past year is the use of Presentation to display alternative content on an external display, such as monitor or TV connected via MHL, HDMI, Miracast, or SlimPort.
As an adjunct to that, I am participating as a judge in Silicon Image’s “Dual Screen App Challenge”, a ~4 month, $100K development contest specifically for apps that support such external displays. Silicon Image is the firm helping spur adoption of MHL, MHL3, and WirelessHD external display protocols.
I have also released my current chapter on Presentation under a Creative Commons license, in support of this contest.
Note that I am not being compensated for my work with this contest; I am doing all this out of an interest in getting more apps (and devices) working with external displays.
I will be updating my book’s content in this area over the contest duration, though those updates will be in the full book, not in the free excerpt that I released for the contest. In particular:
I will be expanding coverage of MediaRouter, including MediaRouteActionProvider
I will be attempting to cover Chromecast development, including how to support both external displays and Chromecast-style devices from a single app (though all of this is limited by Google’s bugs)
I will run some experiments with lower-level access to external displays, to get past the Presentation-is-a-Dialog limitation, per this StackOverflow answer
March 12, 2014
Webinars: Jank Busting and Device Administration APIs
Another pair of webinar topics have been added to the roster. One is on “jank busting”, or how to identify and repair over-use of the CPU in ways that cause your UI to stutter during animations. The other is on Android’s device administration APIs, how you can request to use those APIs and what you can accomplish with that permission.
As with the other webinars, these are each scheduled for four different dates and times, to try to provide you with enough options to find one that you can attend.
Subscribers can visit their Warescription page to get the discount codes for these and the other scheduled webinars, though they are also open to the public.
If you have any questions regarding the webinars, let me know.
March 6, 2014
App Widgets as Wearable UIs
Since I am attending Wearables DevCon here in scenic Burlingame (no, really, the walk along the bay is quite nice), this seemed to be a good time for me to grouse about developing apps for wearables.
Wearable devices — particularly those that run Android — are not that hard to adapt an Android app to. You have to deal with different screen sizes, be more judicious about your gestures, worry all the more about power consumption, and so on. But, at the end of the day, it’s still an Android app.
Where things start to get messy is with wearable accessories, where your app does not run on the wearable itself, but instead runs on a tethered phone or tablet. You use some manufacturer-supplied API to render a GUI and respond to touch input.
The reason why this is messy is two-fold:
The people who design those manufacturer-supplied APIs do not necessarily think about what is going to garner the most adoption of those APIs
Each manufacturer rolls their own, meaning that developers have several such APIs to mess with, if not today, then tomorrow
Now, in some cases, the wearable really does need a distinctive API, because the UI you would want to create is itself distinctive. Augmented spectacles, like Google Glass, would be one such example. However, writing an app for one wrist wearable should not be radically different than writing an app for another wrist wearable, at least for basic apps.
What makes this all the more grating is that wearable manufacturers have a perfectly good API already in Android that they could be using: app widgets.
A home screen app widget has three characteristics in common with wrist wearables UIs:
The UI is small
The UI does not support much in the way of touch events (taps, plus swipes on select widgets like ListView)
The information shown there is stuff that is supposed to be for ready access at any point
App widgets have been around since 2009. There are tens of thousands of Android apps out on the Play Store with app widgets, and many (if not most) of them would be right at home as an app on a wearable.
For a wearable accessory, the mediation app supplied by the manufacturer that runs on the phone or tablet would serve as an AppWidgetHost. Rather than render the app widgets on the phone or tablet screen, though, it would render them to a Bitmap-backed Canvas, sending the bitmap over to the wearable for display. Touch events would be handled either by forwarding them along to the View hierarchy of the app widget (e.g., for swipes on a ListView) or by triggering the PendingIntent associated with a tap. From the standpoint of the app widget developer, everything would look just as if the device’s home screen were the one hosting the app widget.
And that’s the point.
Every line of code needed custom for a wearable is a barrier to adoption. Developers are not necessarily going to run and jump on every wearable that comes down the pike. By using an existing framework, one that is (reasonably) well-documented and in use elsewhere, wearables can get more app support more quickly with less proprietary stuff.
Now, the app widget API was not designed with wearables in mind, in all likelihood. There may be things that the wearable can do that go beyond the app widget. How much of that could be shoehorned into an extended version of the app widget framework (e.g., WearableWidgetProvider subclass of AppWidgetProvider supporting additional broadcasts and methods) would depend up on the wearable. And offering a complete proprietary API as an alternative to using app widgets, for developers who want to deeply integrate with the wearable, is similarly reasonable.
Wearables are still a fringe technology in 2014, compared to their phone and tablet brethren. If wearable manufacturers want a lot of apps quickly, using app widgets would seem to be the route to go. The wearable needs to adapt to the developers, not the other way around. Or, as the saying goes, “If the mountain won’t come to Muhammad then Muhammad must go to the mountain.”
February 18, 2014
The Busy Coder's Guide to Android Development Version 5.6 Released
Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 5.6, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!
This is a bit of a lateral release.
Since I am not going to be attempting to cover every different wrist wearable device on the market, and since my SONY SmartWatch coverage was for the first generation device (and its API), I elected to replace the SmartWatch chapter with a chapter on general issues involving wrist wearable devices.
I also needed to update my own Qualcomm MDP device and the Trepn profiler. That, in turn, led me to agree to a new Trepn license agreement, and at this point I am no longer comfortable with covering Trepn in the book, due to the agreement terms. I replaced the Trepn chapter with one discussing typical problem spots with power usage and, in some cases, how to try to reduce the power consumed by your app.
Beyond this, there’s a smattering of updates to:
the Gradle for Android coverage, particularly conditional dependencies for build types and product flavors
the material on custom permissions, integrating what I blogged about a week ago in terms of issues with other apps defining your permissions ahead of you
the chapter on external display support
Plus, there is a bumper crop of errata fixes, courtesy of a few contributors who went above and beyond the norm for bug reports. :-)
I apologize that this update wasn’t all I had planned on, but I ran into some challenges that stole away more time than I expected.
Version 5.7 should be out in ~4 weeks. Of note, I hope to add coverage of Google Cast to the book, in particular how to write apps that can deliver content to a Chromecast or to more traditional external displays (HDMI, MHL, SlimPort, Miracast, etc.). That, in turn, will require additional material on MediaRouter and its associated action bar support.
As always, if you have questions or concerns with your update, contact me.



