Long-Running Services and User Acceptance
There is a fairly extensive thread in progress on the android-developers Google Group, discussing the behavior of long-running services.
Unfortunately, the original poster on that thread drew incorrect conclusions from his market research. He found that there were other apps like the one he wanted to create, that used long-running services, and that those apps had decent ratings. His conclusion is that there is no problem with long-running services. Along the way, he ignores not only all the problems with his analysis (including low sample size and sampling bias), but also all the evidence that points to the contrary, such as the millions of users of so-called “task killers”.
However, he does have a point. Long-running services are not intrinsically user-hostile. The issue is not the service — the issue is the control over the service.
For example, let’s examine two apps that I always have installed on whatever phone I’m carrying at the time: United Airlines and Ambling BookPlayer Pro.
If I examine the Running tab of the Apps screen in Settings on my Galaxy Nexus, I see that both of these apps have “1 process and 1 service”. Yet, I am sincerely frustrated at United Airlines and worry not a whit about Ambling BookPlayer Pro.
Why? Control, and to a lesser extent, sensibility.
It is entirely possible that there is a reason why the United Airlines app would need a service. However, there is no obvious need for why it would need a service running all the damn time. I have not run the app in days. I have no control over whether this service is used, short of getting rid of it from Settings. I tend not to bother, but it frustrates me, and I can easily see other users attacking the United Airlines app with task killers to try to get rid of the service.
Contrast that with Ambling BookPlayer Pro. It too has a service running all the time. In fact, its process consumes almost twice as much RAM as does the United Airlines app, so in theory I should be twice as annoyed. But I am not.
Why?
-
I know why the service is there — it is waiting for headset plug events
-
I value the service being there, as I like being able to just plug my phone into my Prius and not necessarily have to fumble with the touchscreen to get the audiobook playing again
-
It is a foreground service, so I have an icon that I can get to where I can stop the service through the player’s UI
The only thing that it is missing is an obvious way to prevent the service from running in the first place, albeit at the cost of not handling headset plug events.
Ideally, you do not have an everlasting service in the first place, and use polling or other techniques. If, however, you have a technically justifiable reason for trying to have a service run constantly, ensure that the user knows why the service is there and give the user the ability to control the service behavior, including disabling the service outright at the cost of some functionality. Those items should help improve user acceptance of your everlasting service and reduce the percentage of bad reviews because of your service.
—May 10, 2012
Omnibus v0.6 Released
Version 0.6 of the omnibus edition of The Busy Coder’s Guide to Android Development, as re-envisioned as part of The Big Book Reboot, is available to most subscribers. Those who subscribed after around 8am Eastern Time on May 4th will start getting the Omnibus with the next update.
This release adds ~200 pages, including a bunch of brand-new material:
-
Nine new tutorials
-
A largely rewritten chapter on Internet access
-
A partially rewritten chapter on Intents, filters, and broadcasts, incorporating some material originally found in The Busy Coder’s Guide to Advanced Android Development
-
A slightly revised chapter on services
-
A largely rewritten chapter on large-screen strategies and tactics
-
A largely rewritten chapter on backwards-compatibility strategies and tactics
This release tweaked the PDF format a bit, arranging for all chapters to begin on the right-hand page, to work better when printed.
The next update, 0.7, is expected to be out in about two weeks, with the rest of the new tutorials, plus a few more chapters.
If you encounter problems with the Omnibus or have other Omnibus-related feedback, please contact me at omnibus /at\ commonsware.com.
—May 04, 2012
It's the User's Data, Dammit
One of the benefits of projects like SQLCipher for Android getting more attention is that developers are learning that protecting users’ data from poachers is easier than they might have thought.
One of the downsides of projects like SQLCipher for Android getting more attention is that developers start thinking they can do things that they cannot. Notably, in this case, some developers are trying to use SQLCipher for Android to prevent users from accessing data on the user’s own phone.
That’s just not possible.
Users who root their devices can get to any files they want. This includes the encrypted database and your APK file. Finding the encryption key in the APK file is not going to be all that difficult – obfuscation is good for shrouding your own code implementation but is not that good at hiding encryption keys or calls to third-party code like SQLCipher for Android. At best, your encryption adds another small hurdle to overcome, reducing the percentage of people who will bother, but it will not stop them all. And, of course, once your key is compromised, that key can be widely disseminated, and lots more people can get at the data.
If you put data on the user’s device, it is now the user’s data.
Depending on the data, you can take some steps to help steer users towards proper use of that data. Watermarking is a popular solution for media (MP3s, EPUBs, etc.) – it does not stop the user from copying the file, but if the copies get widely distributed, it becomes possible to track down who the original copier was. That information may be sufficient to help prevent future copying (e.g., termination of an account) and may be sufficient for legal action, if you so choose.
If, however, the user simply cannot be allowed to see the data, do not put it on the user’s device. Keep it on your servers, downloading it only as needed, and taking steps on your servers to prevent unauthorized access. That too may prove challenging, but at least you have complete control over the environment.
Using SQLCipher for Android to help protect the data of users who leave their Android tablets in airplane seat-back pockets is a wonderful thing, and I hope more developers do it. Using SQLCipher for Android to try to hide data from users amounts to “roll your own DRM”, and we all know how well DRM solutions work.
—May 01, 2012
How I Isolated the Adobe Reader Activity Issue
Earlier today, somebody posted a question on StackOverflow regarding a SecurityException when trying to send a PDF to Adobe Reader via ACTION_SEND. I thought it might be useful to write up how I went about determining the nature of the problem.
The question author took care of my first guess for me, by indicating that the ACTION_SEND code worked fine with other PDF apps. That eliminated any issue regarding read permissions on wherever the PDF was stored (not mentioned in the question).
Fortunately, I have two apps installed on my Galaxy Nexus relevant to this issue. One is Adobe Reader, as you might expect. The other is AppXplore, published by Sony (or Sony Ericsson, as their app description still lists them).
AppXplore is a very handy app for inspecting the manifest of another application installed on your device. Simply running AppXplore and tapping on an app brings up general information about the app itself. Then, choosing a “Show manifest file” options menu item brings up a scrollable TextView of the contents of the manifest… more or less. It is actually “a regenerated verison of AndroidManifest.xml from application’s binary package and may not match exactly with the original AndroidManifest.xml file”.
However, it is certainly ample for problems like this. And, there are no pesky software piracy issues typically involved in getting one’s hands on an APK file for an app on the Play Store.
The SO question helpfully listed the activity that was failing: ARSendForSignature. Scrolling down in the generated manifest for Adobe Reader shows that ARSendForSignature indeed has an <intent-filter> for ACTION_SEND. However, it also has android:exported="false".
The default exported state for Android components is:
- Components with an
<intent-filter> are exported and can be launched by other applications
- A
ContentProvider is exported by default, despite having no <intent-filter>
- Everything else is not exported by default and therefore cannot be launched by other applications
The android:exported attribute on an <activity> allows you to override those defaults.
So, what happens?
The user does something in the original activity that triggers a startActivity() with an ACTION_SEND Intent for the application/pdf MIME type. The chooser lists all activities that have an <intent-filter> matching that specification. When the user taps on the chooser item for Adobe Reader, the chooser crashes, because it cannot start up Adobe Reader’s ACTION_SEND activity, because it is marked as not exported.
The real problem here is the chooser. The chooser should be filtering out anything that is not exported and is not from its own application, no matter what the <intent-filter> may have. That’s why I went ahead, reproduced the problem with my own code, and filed an issue.
Tactically, though, Adobe should either mark this activity as being exported (so ACTION_SEND works) or remove the <intent-filter> (thereby having it not appear in choosers for ACTION_SEND).
—Apr 25, 2012
Omnibus v0.5 Released
Version 0.5 of the omnibus edition of The Busy Coder’s Guide to Android Development, as re-envisioned as part of The Big Book Reboot, is available to most subscribers. Those who subscribed after around noon Eastern Time on April 22nd will start getting the Omnibus with the next update.
This release adds some new material:
-
A rewritten chapter on threads
-
A lightly updated chapter on permissions
-
A mostly-reworked chapter on local files and assets
-
A trimmed-down chapter on SharedPreferences
-
A reworked chapter on SQLite
Also, 0.5 introduces a new book format: APK. Here, by “APK”, I mean that the omnibus is available as an installable Android application, using its own digital book reader, EmPub, for Android 2.2 and higher.
There are several objectives with the EmPub initiative:
-
EPUB readers, on the whole, mangle the book, because they replace my CSS with their CSS. I want to make sure that there is an on-device option that always faithfully renders what I am trying to write.
-
EmPub will serve as the foundation for a new set of tutorials, building up a subset of EmPub capabilities (in a app called EmPubLite).
-
While EmPub is fairly basic at the present, I intend to add more capabilities over time, not only to make it more usable to you as a reader, but also to demonstrate Android capabilities in an app that is bigger than my typical focused examples. That being said, EmPub is not designed to have an infinite number of features.
-
EmPub is open source, so others might find use for it in its entirety, though that is not its principal aim by any stretch.
Right now, to get the APK onto an Android device, the easiest approach probably is to download the APK on your desktop or notebook, then install it on your device (e.g., via adb install). I will eventually add a QR code to allow you to get it onto the device a bit easier. Also, eventually, EmPub will optionally self-update, downloading new versions overnight and letting you then install them when you are ready. The book will not be on Google Play Store or any other market, though I may distribute a free sampler edition by those venues.
The EmPub usage model is fairly basic:
- Swipe vertically to read within a chapter
- Swipe horizontally to switch between adjacent chapters
- Click any link to open it, and if it is an internal link, you should slide over to that chapter and section
- Tap on the icon in the upper right to return to the table of contents, where you can click any link to visit any chapter
As with the PDF, KF8, and EPUB (for the few readers that support it), changebars work in EmPub to highlight what is new or changed within a chapter.
If you encounter bugs or have feature requests for EmPub, please file an issue.
If all goes according to plan, Version 0.6 will ship in about two weeks, with a few new chapters and a bunch of new tutorials, based on EmPub and EmPubLite.
If you encounter problems with the Omnibus or have other Omnibus-related feedback, please contact me at omnibus /at\ commonsware.com.
—Apr 23, 2012
Older Posts