Mark L. Murphy's Blog, page 51
June 10, 2015
The End of the Webinars
The grand experiment of offering live webinars to subscribers is coming
to a close. I will be adding other benefits to the Warescription later
this year that will hopefully be of greater value to more subscribers.
In the meantime, though, in addition to the
���RecyclerView Basics���
and
���RecyclerView, Beyond the Basics���
webinars that
I mentioned previously,
there are two other ones available to you.
One is a quick 30-minute primer on getting your app
running on Chrome OS using ARC,
outlining where ARC is now and how you can start experimenting with it.
The other is a 45-minute discussion of
image loaders.
Image loading libraries are very popular, with Picasso and Universal Image
Loader high on the list. In this webinar, we will cover some criteria
to consider when choosing an image loading library. It will also have an
in-depth walkthrough of two projects, one each for Picasso and Universal
Image Loader.
June 9, 2015
The ACTION_IMAGE_CAPTURE Fallacy
The documentation for
the new permission system in the M Developer Preview
has:
In many cases, you can choose between two ways for your app to perform a task. You can have your app ask for permission to perform the operation itself. Alternatively, you can have the app use an intent to have another app perform the task.
For example, suppose your app needs to be able to take pictures with the device camera. Your app can request the android.permission.CAMERA permission, which allows your app to access the camera directly. Your app would then use the camera APIs to control the camera and take a picture. This approach gives your app full control over the photography process, and lets you incorporate the camera UI into your app.
However, if you don���t need such control, you can just use an ACTION_IMAGE_CAPTURE intent to request an image. When you start the intent, the user is prompted to choose a camera app (if there isn���t already a default camera app), and that app takes the picture. The camera app returns the picture to your app���s onActivityResult() method.
Oh, if it were only this easy.
The theory is sound, but the practice is unrealistic. The problem is
three-fold:
The rules for what ACTION_IMAGE_CAPTURE is supposed to do are
fairly limited, at least in terms of what is documented
I am not aware that the CTS actually tests ACTION_IMAGE_CAPTURE
There is no test suite that I am aware of to test arbitrary
camera apps��� implementation of ACTION_IMAGE_CAPTURE, let alone anyone
actually using it to test their camera apps
As a result, ACTION_IMAGE_CAPTURE is not reliable or consistent.
For example:
Some cameras will store photos taken in portrait mode as portrait
images. Some cameras will store photos taken in portrait mode as
landscape, setting an EXIF header to say ���hey, image viewer, could you
rotate this for me please, kthxbye���. Since BitmapFactory ignores
this header, Android apps frequently load these images as landscape,
ignoring the header. And either behavior is perfectly legitimate, because
ACTION_IMAGE_CAPTURE does not specify one way or another.
Some cameras will record images taken with the front-facing camera
as-is. Some will mirror the images, to make them appear more like what
the user saw in the camera preview. And either behavior is perfectly legitimate, because
ACTION_IMAGE_CAPTURE does not specify one way or another.
The documentation says that by default the camera should return
���a small sized image��� in an unfortunately undocumented Intent
extra (hint: the key is data). But there are no standards as to what
���a small sized image��� means. It has to be less than 1MB due to IPC
constraints, but whether it is a 120x80 thumbnail or a 512x512 image
is up to the camera app.
The documentation says that you can use EXTRA_OUTPUT to indicate
where the image should be written as a full-size image. But the documentation
does not state what valid values for EXTRA_OUTPUT are. Is that limited
only to file:// Uri values? Will a content:// Uri work, if the 
provider supports write access? Again, any behavior of the camera is
perfectly fine, insofar as there is no right or wrong answer, even if
the behavior difference is important to developers.
Stack Overflow is littered with people trying to use ACTION_IMAGE_CAPTURE
and having difficulty dealing with the wide range of results from
camera apps. It���s the primary reason I wrote a library
to try to make it easier for apps to have consistent behavior, and why
I am rewriting that library (since my first attempt
gots issues, yo).
I sincerely wish I didn���t feel the need to write these things, as there
are lots of other things that I would like to do with my time.
Google, in the interests of granting implementors flexibility, has
constrained the practicality of using stuff like ACTION_IMAGE_CAPTURE.
Lots of implicit Intent actions tend to work OK, because they
do not return any results, and so are simply one-way communications
channels, like Web page links. But any implicit Intent that is
supposed to return results ��� basically, anything using
startActivityForResult() ��� has the potential to be unreliable,
if there are many implementations that offer to handle that Intent.
ACTION_IMAGE_CAPTURE is one of the worst in that regard.
Google���s recommendation of relying on third-party apps for things like
basic picture-taking still hold true, but only in cases where the app
needing the picture does not really care about the picture, and so whatever
the other app happens to hand back will be just fine, thanks. If Google
wants developers to rely on third-party apps for more than really
trivial stuff, Google needs to tighten up the contract between
both sides, so everybody knows what everybody is expecting.
June 5, 2015
Supporting the M Developer Preview... And Previous Versions
Google, as they did with the L Developer Preview last year, is playing
games with the development process.
The documentation
states that you need the following in your
build.gradle file to build against the M Developer Preview (a.k.a., MNC):
a compileSdkVersion value of ���android-MNC���
a minSdkVersion value of ���MNC���
a targetSdkVersion value of ���MNC���
This means your app will not run on older devices, as the minSdkVersion
is set to MNC. If you try lowering either minSdkVersion or
targetSdkVersion, there will be no effect ��� simply having
compileSdkVersion set to android-MNC causes the build tools to put
MNC in the generated manifest for minSdkVersion and
targetSdkVersion.
This is short-sighted.
Android developers need to be able to test their apps on MNC. They also
need to ensure that the same app can work on older devices, as relatively
few developers will be creating apps that ship only to Android M or
higher devices. Yet Google tries to prevent you from testing the same code
in both environments via this silly MNC trick.
My only guess as to why Google is doing this is to prevent Android
developers from shipping apps compiled against the developer preview.
That���s a noble goal. Screwing around with the build process is not the answer.
IMHO, the answer is two-fold:
Block MNC-compiled apps at the Play Store. Instead of preventing the
apps from running on older devices, make sure that the Play Store can detect
APKs that are compiled against MNC and block them, just as the Play Store
detects signing keystore problems and such. Google could even document
the process of detecting an MNC-compiled app, so other distribution channels
(e.g., Amazon AppStore for Android) can add in similar blocks if they chose.
Shame developers, as I am about to do:
Only drooling idiots ship apps compiled against preview SDKs.
Are you a drooling idiot?
With that warning in mind, let���s solve two problems: how to compile
against MNC yet still test on older devices, and how your code can detect
that it is running on MNC.
NOTE: The recipes described below work for the first version of the
M Developer Preview. This recipe may well require
adjustments in future developer preview updates.
Through what���s known as the ���manifest merger��� process, the manifest that
goes in your APK is synthesized out of several sources:
your main sourceset���s manifest
your androidTest sourceset���s manifest, if you are testing
any other manifests in other build variants��� sourcesets
stuff in build.gradle
manifests from any library modules or AARs you have as dependencies
In the case of the M Developer Preview, the compileSdkVersion value
of android-MNC causes the build process to put MNC in as the minSdkVersion
and targetSdkVersion in the generated manifest.
Fortunately, manifests are text files.
So, here is an android closure that can build an app module
that compiles against MNC but will run on API Level 15+ devices:
android {
compileSdkVersion 'android-MNC'
buildToolsVersion "23.0.0 rc1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 15
}
// based on http://stackoverflow.com/a/27372806/1...
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.processManifest.doLast {
def manifestOutFile = output.processManifest.manifestOutputFile
def newFileContents = manifestOutFile.getText('UTF-8').replace("MNC", "15")
manifestOutFile.write(newFileContents, 'UTF-8')
}
}
}
}
This takes a very ���caveman��� approach to the problem, reading in the
generated manifest, replacing all occurrences of MNC with 15, and
writing the adjusted manifest back out. This will fail on projects that
have MNC somewhere else, like an activity���s class name. It also sets
both minSdkVersion and targetSdkVersion to the same value. A more
sophisticated script would replace those individual attributes ���
the proof of this is left as an exercise for the reader. Similarly,
a more powerful script would read the desired values out of
defaultConfig and apply them. And, a safety-conscious edition of
this would only apply this for debuggable variants, thereby helping to
reduce the impact of a drooling idiot trying to ship a release
build that performs this override. This is merely a proof of concept, not
implementing all possible bells and whistles.
Again, doing this and releasing the results to the Play Store or elsewhere
is monumentally idiotic. Use this for testing only.
However, we then run into a related problem: how do we determine that we
are running on MNC, so we can call MNC-specific methods and avoid them
on older devices?
Since there is a Build.VERSION_CODES.MNC in the SDK, you might think
that you could just compare it with Build.VERSION.SDK_INT, the way we
do for any other Android version.
And you would be mistaken.
There are two problems with MNC, at least in terms of the hardware images
(haven���t tried this on an emulator just yet):
Build.VERSION.SDK_INT is 22, the same value as Android 5.1
devices use
Build.VERSION_CODES.MNC is 10000, because,
according to Google,
���this is WAI. there is no official API level yet.���
(WAI presumably means ���working as intended���)
As usual, there���s a workaround. The following static method will
return true if your code is running on MNC; false otherwise:
static private boolean putMarzipanInYourPiePlateBingo() {
boolean result=false;
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP_MR1) {
try {
Field f=Build.VERSION.class.getField("PREVIEW_SDK_INT");
if (f.getInt(null)>0) {
result=true;
}
}
catch (NoSuchFieldException e) {
// no problem, must really be API 22
}
catch (IllegalAccessException e) {
// ummm... this shouldn't happen
}
}
return(result);
}
It takes advantage of the fact that PREVIEW_SDK_INT was added
to the MNC SDK. If we are older than API Level 22, we can���t be on
MNC. If we are on API Level 22, and we cannot find or access
PREVIEW_SDK_INT, or it is 0, presumably we are really on API Level 22.
But, if Build.VERSION.SDK_INT returns 22 or higher (higher if they
actually set it to a better value in future developer preview updates),
and PREVIEW_SDK_INT exists and is higher than zero, we should be
on MNC.
This has been tested on a Nexus 5 running MNC, a Nexus 5 running Android 5.1,
and a Galaxy Nexus running Android 4.1 (or thereabouts, something old), and
it seems to hold up. That being said, YMMV, unless you are on the metric
system, in which case YKMV.
Once again, this is the sort of thing that should only be used in testing.
Don���t ship anything that refers to marzipan.
Once Android M ships ���for realz���, you should be able to switch back
to normal Build.VERSION.SDK_INT checks, when you ship your M-ready
app.
June 4, 2015
Random Musings on the M Developer Preview: the Ugly (Part One)
This post continues the series that I started on Monday
(���the Good���)
and Tuesday
(���the Moderately Disconcerting���, or ���the Bad��� for short),
reviewing what is in the M Developer Preview.
At this point, I should re-emphasize that I am covering the state
of the initial M Developer Preview. Further previews are supposed
to be released, and none of this is shipping production software yet.
There may be changes to M along the way that affect some of what
I am covering in these posts.
With that as prologue, today I am going to look at the first of
the ���ugly��� bits: background processing.
Look, I like long-lived batteries as much as the next person. However,
I also like software that works as advertised. The problem with what
the M Developer Preview is doing with respect to background processing
is that, in the service of extending battery life, it makes software
unreliable with respect to documented functionality.
This isn���t new. Long-time followers of this blog may recall that I
sounded the warning of the first occurrence of aggressive power-saving
behavior, in the form of
SONY���s STAMINA mode,
over two years ago. Other manufacturers have made their own attempts
at the same sort of thing, and so to the extent that Android M may
standardize some of this behavior, I suppose that���s good.
However, what Android M does to our apps is:
More aggressive than what I have seen manufacturers do
Is generally hidden from the user
Is largely uncontrollable by the user
Is (almost) completely uncontrollable by developers
So, what���s changing?
First, we have ���Doze mode���. If the device is not charging and not moving,
after about an hour, the device enters ���Doze mode���. While dozing, pretty
much all background processing is disabled. No AlarmManager. No JobScheduler.
No SyncManager. If you somehow get control by other means, no
WakeLock and no Internet (with one noteworthy exception that I���ll 
cover later). In short, your code won���t run.
The device will briefly exit ���Doze mode��� for about five minutes after
an hour passes, then return to ���Doze mode���. You get similar windows
after another two hours, then after another four hours, then after another
six hours, then I ran out of time for testing.
However, even during these brief non-dozing windows, Internet access
may or may not be available. From what I have seen, my guess is that
Android ���releases the hounds��� and runs pending background work
immediately after exiting ���Doze mode���, but before Internet access is
necessarily available (or possibly I am seeing a switchover to WiFi).
Regardless, the state of your world during these brief windows is
in flux.
Second, we have ���app standby���. If the device is not charging, and if
your app has not been in the foreground for some time, but due to sticky
services or something your process still exists, your app will move
into a ���standby��� state. This appears to amount to a local ���Doze mode���,
affecting only your app, where your alarms and network and whatnot
are unavailable. Your app may get the ability to run and access the
Internet around once per day (whether it is also allowed time in the
prison���s exercise area is undocumented).
The user is not made aware of any of this. The user is not told that
certain apps were put in standby, or the device had been in ���Doze mode���
and so background work may have been blocked. In theory, the users
do not need to know this, any more than they knew exactly what was
going on when the screen turned off on their devices before. However,
for quite a few apps, these changes in behavior will break functionality.
Users may, in time, grok that if they keep their device on a charger,
their apps will behave better, just as users would grok that on older
versions of Android, if they keep their device on a charger, their battery
would be charged. However, whereas the user is told about battery
levels, they are not told about app degradations, and they are likely to
assume that the app developer is at fault.
Now, once ���Doze mode��� and ���app standby��� exit, such as the user plugging
the device into a charger, things return to normal. At least, sort of.
Initially, there���s going to be a lot of contention, as all sorts
of background work tries to get caught up. It may take a bit before
Internet access stabilizes as well. This gets worse when the causes normal
behavior is because the user presses the POWER button, as now there is a
window in which the apps are scrambling to do what they were supposed
to have been doing but do not have the results yet, and so the user will
be exposed to stale information.
This wouldn���t be so bad if there were options for the user, or possibly
for developers, to manage this.
The Android M Settings app has a place where users can indicate that they
want to ���ignore optimizations��� for certain apps. However:
This is not easy to find, buried in an overflow menu item off the Apps
screen
It doesn���t affect ���Doze mode���,
at least on the current M Developer Preview,
and devices will be in ���Doze mode��� a fair bit
It is possible that ���ignore optimizations��� affects ���app standby���. That
is what���s documented, and I have not tested that scenario yet, in part
because I have no good way of distinguishing ���app standby��� from
���Doze mode���, and for this sort of analysis I want real-world results,
not the results from issuing adb commands to simulate real-world
results.
On the developer side, in theory, the new setAndAllowWhileIdle()
(and, presumably, setExactAndAllowWhileIdle()) methods would allow
you to get control even during ���Doze mode���. At least, that���s what
the documentation says. However:
My guess is that you may still not get Internet access or have
wakelocks, and so these methods would mostly be for time-critical
local-only processing, such as raising a calendar reminder
Notification
They don���t work,
insofar as they do not affect ���Doze mode��� as
documented
If they do work, we���re going to have lots of ���special snowflake���
developers who choose to use them just to get past Google���s nudges
in the direction of better power management, even though they may
not need the functionality
(it would certainly help if the OS and tools could make inexact
alarms more visible, so that
things like adb shell dumpsys alarm would tell us when the alarm actually will go off)
Google seems to have a ���golden ticket��� approach to getting
around this problem: use GCM. A future edition of GCM will offer
���high-priority messages���, which will be delivered to your app even
in ���Doze mode��� or ���app standby��� states, and that you will briefly
have network access and some time to do some work in response to
those messages.
Even without ���high-priority messages���, there is little doubt that
push messages are more efficient, on the whole, than are polling-based
techniques. I have no problem with the notion of pushing push.
However, GCM is proprietary, powered by Google Play Services, and route
through Google���s servers.
This introduces problems:
While Google likes to think that the only devices that matter are
ones that are part of the Google Play ecosystem, other manufacturers
and channels (e.g., Amazon) would beg to differ. At best, those manufacturers
would need to offer their own push solution and tie it into their
forks of Android to provide similar effects with respect to ���Doze mode���
and ���app standby���. And then developers have to fragment their apps
further to support pushing through multiple systems, just to arrange
to get their apps to run in the background.
There is no SLA for GCM, and so we have no reliability guarantees.
There are many apps for which passing communications through Google���s
servers would be inappropriate or illegal for privacy and security reasons.
While GCM appears to be encrypted over the air, GCM payloads are cleartext to Google
and to whoever Google elects to share the data with.
Devices are sometimes in airplane mode, so using GCM as a generic
���send a message to tickle the device��� approach will not be reliable.
Beyond this, intentionally altering an open source operating system to
steer people towards proprietary APIs reeks of Mafia-style behavior
(���Gee, that���s a nice app you have there. Pity if something were to
happen to it���). If push messaging on Android were an open, pluggable
system, with multiple competing implementations, I would have no problem
with Android giving benefits towards apps that use push. But third-party
push engines (e.g., XMPP, WebSockets-based long polling) are going
to be subject to ���Doze mode��� and ���app standby��� and cannot help apps get
the data they need when the user asked for that data. Here, GCM���s exalted
status, and Android���s dependence upon it, represents damage to be routed
around.
Now, lots of apps will not really be harmed by these changes. And some
apps that are ���harmed��� were written poorly in the first place and these
changes will help wrestle them into better behavior. However, this is a
very heavy club that Google is wielding, and many apps and their developers
are going to get beaten by that club, even though their apps are
fairly good citizens. This is even more the case if the apparent bugs
in M turn out to be documentation bugs, not functionality bugs, and
so calendars can no longer remind users on time in a reliable fashion.
Assuming nothing changes, developers are going to need to take yet more
steps for dealing with unreliable background work.
For example, make sure that you are keeping your user informed, by one
means or another, if they come back into your UI and you are waiting
for blocked background work to complete and so do not have the results
that the user is expecting. Ideally, you would be doing this sort of thing
already, to help cope with other things that mess up background work
(e.g., ���Force Stop���). However, background work has typically been reliable
enough that developers could be forgiven for assuming that it worked
in general. That���s no longer going to be the case.
Tomorrow, I will conclude this series of posts reviewing the M
Developer Preview with the remaining ���ugly��� area: ���auto backups for apps���.
Random Musings on the M Developer Preview: the Ugly (Part Two)
This post wraps up the series that I started on Monday
(���the Good���)
and continued Tuesday
(���the Moderately Disconcerting���, or ���the Bad��� for short)
and Wednesday
(���the Ugly (Part One)���),
reviewing what is in the M Developer Preview.
IOW, as with popular movie franchises like ���The Hunger Games��� and
���Avengers���, this trilogy goes up to 4.
Today���s focus is on ���auto backup for apps���.
As with yesterday���s rant on M���s aims to reduce background processing to
improve battery life, railing against backups would seem to be being
against ���motherhood and apple pie���, to use the American euphemism.
I love backups. I have a fairly extensive backup regimen for my office.
I even blog about how developers need to do backups.
However, it has non-trivial privacy and security issues.
Suppose that Microsoft, a decade ago, made this announcement:
As part of Windows 7, we are going to automatically make a copy of
all the files on your hard drive (or whatever subset we choose) to
our servers. In accordance with our terms of service, we have a worldwide
right to do pretty much whatever we want with that data. In exchange,
we agree to restore that data, if your PC suffers some
fatal calamity and you elect to replace it with another Windows 7
PC and the same software in a timely fashion.
I would expect there to be Congressional and EU commission inquiries
about this, and for privacy advocates to be railing against the practice.
In essence, though, this is what Google has been doing all along, and
is simply re-emphasizing now in M. Though, with luck, some of the problems
with their approach are merely documentation errors.
Automatic backups are enabled for all apps installed on devices running the Android M Preview. No additional app code is required. The system provides users with the ability to opt out of automatic data backups.
Here, it indicates that the user has to opt out to avoid the backups,
meaning that the user presumably was automatically opted-in. The current
M Developer Preview does not work that way, in that backups are an
opt-in process via the Settings app. However, that backup process
is device-wide ��� either all apps are backed up or none are.
The automatic backup feature preserves the data your app creates on a user device by uploading it to the user���s Google Drive account and encrypting it.
Google is going to emphasize that the backups are encrypted. However,
this is only going to work, from a privacy and security standpoint,
if the user is supplying the passphrase or other key information. There
is no evidence that this is part of the flow. Then again, since
the backup system seems to have issues,
it���s possible that there is somewhere for a user to supply a backup
key that is just not obvious (or not available) in MNC.
However, my guess is that there is no plan for the user to supply the
key. In that case, Google has the encryption algorithm and key,
and so they can decrypt the data whenever they want. Keeping it encrypted
on Google Drive might help in the case of a breach of network security,
but it will not prevent Google from decrypting it of their own volition
and using that data, including sharing it with third parties (whether
by design or under duress). The only real defense that users and developers
have are the terms of service agreements, and I leave it up to qualified
legal counsel to determine whether or not those are adequate. In my
decidedly non-legal-expert opinion, they are not.
All of this leads to two issues:
What if the app is being used for data that cannot just be backed up
wherever/whenever? Using a US-centric example, what about apps that
hold medical data governed by HIPAA?
What is the legal exposure to app developers for allowing Google
to have access to app data like this? In the case of Google playing
around with the app data,
people will certainly sue Google. But might they come after the app developer as well?
And what happens for other ecosystems (Amazon, BlackBerry, etc.) that
use Android but not Play Services? If they adopt this same auto-backup
stuff and route it to their servers, what are the risks?
This auto-backup capability needs to be more granular and support
user-supplied pluggable backup transports. In other words, businesses
should be able to say that the backup data goes to their servers, not
Google���s, particularly for their own business apps.
And if individuals would prefer that their data be backed
up somewhere other than Google���s servers, that should be their right.
Also, please note that while this is advertised as ���backup���, it is
really ���disaster recovery���. It appears that the only time these
backups will be restored is if the user replaces their device with another
one. There are plenty of other possible problems (human data entry
error, unexpected data corruption, etc.) for which backups will be useful,
but you will need to implement that sort of stuff yourself in your app,
for any data that is uniquely stored on the app and is not automatically
being reflected in some server somewhere.
So, what should developers do?
First, opt out in the short term, by adding android:allowBackup="false"
to the <application> element in the manifest.
Then, work out a longer-term plan, perhaps in concert with your legal
adviser, who can give you feedback about your risk exposure.
From there, I see four major implementation flavors emerging:
Simply remain opted out, so your app���s data will not be backed up.
Opt in (android:allowBackup="true") and rely on the fact that your
app just doesn���t have any significant data that might represent any sort
of privacy or security risk if Google ships it to their servers. For
example, perhaps all of the data is actually on a server somewhere,
with the device merely holding a cache (and note that caches, by default,
are not backed up).
Opt in, but configure the backups
to only back up one file, one that contains ���bootstrap��� data to help you
connect the user to real backups that you are maintaining separately.
This will allow you to compete on the basis of sophistication of backups,
and you can still take advantage of ���auto backup for apps��� for disaster
recovery scenarios. Just make sure that the ���bootstrap��� data is not
itself going to lead to security issues ��� for example, using a URL
to a backup is fine, so long as access to that URL is defended separately.
Opt in, but encrypt your app���s data at rest in the app itself,
as part of normal work. For example, you could be using
SQLCipher for Android
as your database container. Now it does not matter if Google (or anyone)
backs up the data, as the data is useless to them without the encryption key
(or perhaps a $5 wrench).
Again, backups are good. Disaster recovery is good. Google���s stock
implementation has risks for developers and is incomplete (in that it
only deals with disaster recovery). Developers need to think through
how backups work and what is appropriate for their app and their
users.
June 2, 2015
Random Musings on the M Developer Preview: the Bad
As I noted in
yesterday���s post,
each time Google releases a new SDK platform, I putter around looking
for changes and identifying things that developers should think
about, either because they were not covered in the I|O presentations
or high-level overviews, or because they may cause problems.
Here, we start to get into the potential problems.
That being said, this post covers ���the Bad���, simply because Sergio
Leone did not name his movie ���The Good, the Moderately Disconcerting, and
the Ugly���. Probably that would be too long for the movie poster.
So, what has me, um, moderately disconcerted?
The biggest area of concern is with the new app permission system.
The increased user control over permissions is, on the whole,
a Very Good Thing. I and others have been calling for this for six
years. Allowing users to control what apps can do what, on a more 
fine-grained basis than before, is great. However, that does not mean
that what is proposed is all unicorns and rainbows ��� there are
issues for developers and users alike.
On the developer front, you���ll need to quickly ���retcon��� your app to assume
that you do not have all the permissions you want, to ask for them
on the fly, and to deal with rejection with grace and aplomb. That
may or may not be easy to all get in place in the next few months, in
concert with everything else you were planning on doing with your
summer (or, in the case of the Southern Hemisphere, winter).
If you elect to ignore the new permission system, that���s fine, but
now you wind up with
App Ops-esque behavior. 
Dave Smith performed some early analysis
and gives you an idea of what your ���legacy��� app should expect.
However, what Google giveth in terms of user control, Google also
taketh away, at least in how the permissions are presently organized.
The preview docs state:
When the user installs or updates the app, the system grants the app all permissions that the app requests that fall under PROTECTION_NORMAL. For example, alarm clock and internet permissions fall under PROTECTION_NORMAL, so they are automatically granted at install time.
The problem is, as a Redditor pointed out,
that many of the existing normal permissions are things that the user
really needs to know about, such as:
the ability for the app to find out the user���s Gmail address
(GET_ACCOUNTS)
the ability for the app to find out the user���s (probable) phone
number (READ_PHONE_STATE)
the ability for the app to read external storage (READ_EXTERNAL_STORAGE),
which we just got a year or so ago
fuss with tasks (GET_TASKS, REORDER_TASKS) and background
processes (KILL_BACKGROUND_PROCESSES)
open and close the status bar (EXPAND_STATUS_BAR)
and so on
Apps can request and get all of those capabilities without much in the
way of user notice.
There are normal permissions in the SYSTEM_TOOLS permission group
that really need to be better controlled, like WRITE_SETTINGS. Also, it
is unclear what happens to dangerous permissions in permission groups
that are not ones that the user can control via Settings, such
as SYSTEM_TOOLS.
Now, at Google I|O, they indicated that an overhaul of these permissions,
in terms of permission groups at least, was on the docket. Hopefully,
it will cover these sorts of problems by the time M ships as Android
5.2/6.0/Turbo System 5000/whatever.
Here are some other things showing up in the first edition of the M
Developer Preview that represent possible trouble spots:
There are changes to ART that apparently break the Android Support
package. There is a tiny note in the preview docs:
If your app uses the v7 appcompat library or the v7 recyclerview library, you must update your app to use to the latest versions of these libraries.
That���s buried deep in the preview docs, though, and many developers
will miss it outright. I can only hope that the build tools will point
out incompatibilities here, via Lint checks or the equivalent. Regardless,
you should consider upgrading your appcompat-v7 and
recyclerview-v7 libraries before M goes to production.
The built-in edition of Apache���s HttpClient was deprecated in Android
5.1 and removed entirely for the M Developer Preview, though there
are things you can add to your Gradle build files to re-enable it.
I have no idea how you would re-enable it if you are not building
via Gradle, though (e.g., Eclipse users). And this is going to cause
no end of support headaches for those of us trying to help newcomer
Android developers. I would have left it as deprecated for longer,
unless there is a specific security concern, in which case it���d be neat
if Google would mention such a concern. As I wrote in
a previous blog post,
if you
need to continue using the HttpClient API, consider switching to
OkHttp and their HttpClient
compatibility layer, or consider switching to
Apache���s separate Android edition of HttpClient.
Otherwise, switch to HttpURLConnection or OkHttp���s native API.
Google heavily touted ���Now on Tap���, but that���s not shipping in the
previews, so we have no idea what the default behavior will be with
our apps and we cannot test the Assist API to try to manage that
behavior. We also do not know what ���the standard set of information that
the platform passes to the assistant��� means and whether there is any
means to control that short of FLAG_SECURE. I am starting to contemplate
recommending FLAG_SECURE as default behavior, to be opted out of for
activities where you are really really sure that the user won���t mind
other things peeking at.
UPDATE:
A post on ProgrammableWeb
suggests that ���Now on Tap���
will be accomplishing this via ���the view hierarchy���. I would surmise that
this means the accessibility APIs, with FLAG_SECURE simply serving as
an indicator that Now really shouldn���t peek (Until Google decides to do
that too. Because Google.).
Google touted Chrome custom tabs, but it seems undocumented, and it
is unclear if anything related to it is something that we would
be able to test prior to M shipping for realz.
Users can silence heads-up notifications. That���s fine, and I think
there���s hooks in the API to find out that the user has done this, but
it does mean that your heads-up notifications may not behave as you
have been expecting from Android 5.0 and 5.1.
���Adopting��� removable storage will be useful for users, particularly
of lower-end Android devices with limited on-board storage, as adopted
removable storage expands internal storage. For Android development
old-timers, android:installLocation is back in play. For newcomers
to Android, you probably have not been thinking about android:installLocation
and the ramifications of the user moving your app to removable media.
Apps can now inject themselves into the EditText action mode, so
they show up as an available option, by
implementing an ACTION_PROCESS_TEXT activity.
This has interesting possibilities, but
I worry about overuse and lack of user control.
There are signs that multi-window support is making it into Android,
with various sites reporting ways that a firmware can be tweaked to enable
this developer option. I sincerely hope that developers have access
to a preview of this capability before it goes live, whether that is
part of the M Developer Preview or some future developer preview.
The regression from Android 5.1, where
AlarmManager repeating events are limited to a minimum one-minute period,
is still undocumented. Then again, the whole background processing
area is FUBAR in the M Developer Preview, as will be covered in a blog
post tomorrow.
External storage has moved yet again. At least on the Nexus 9,
adb users will find it in /storage/emulated/0.
The AnalogClock widget has been deprecated, for the 37 of you still
using it.
Tomorrow, I���ll start looking at stuff that is decidedly more ugly,
starting with background processing.
June 1, 2015
Random Musings on the M Developer Preview: The Good
Each time Google releases a new SDK platform, I rummage through
the API differences report, the new Build.VERSION_CODES entry,
and the high-level overviews,
to see if there are things that warrant more attention from 
developers, with an emphasis on mainstream features that any developer
might reasonably use.
This time around, for the M Developer Preview, I am
dividing up my random musings into a series of posts, named after
the famous Sergio Leone ���spaghetti Western���,
���The Good, the Bad, and the Ugly���.
In today���s post, let���s look at some stuff that is fairly clearly good
for all parties.
Many items that fall in this category got attention in the
M Developer Preview overview or in Google I|O presentations, such as:
the data binding engine
the Android Support Design library (at least, once it works)
app linking (though I worry about no-connectivity scenarios)
direct share
better information from gfxinfo for finding jank
However, a few things did not get much ���press��� from Google that are wins
for developers and users:
Build.VERSION now has a PREVIEW_SDK_INT value. Normally, that will be zero,
but when running on a device powered by a developer preview, it will be
a positive integer indicating what revision of the preview the device or
emulator is running. Google has indicated that they will ship updates
to the M Developer Preview, and they might change method signatures on
new APIs added to the preview. You can confirm that you are on a specific
preview revision via PREVIEW_SDK_INT, so you can opt into preview APIs
when running a specific revision.
NotificationManager has a getAllNotifications() method. Despite
the name, this returns information about the notifications that your app
raised, not all notifications raised by any app. That being said, for the
first time, we have an API that can tell us if a Notification that we
raised earlier is still outstanding or not, without us having to try
to track this information ourselves. In other words, Google is starting
to add read capabilities to formerly write-only APIs.
StrictMode can now warn you if you attempt to perform network I/O
over an unencrypted socket connection. This will likely be prone to
false positives, particularly for non-HTTPS protocols, but it is still
worth trying, to help ensure that you are properly securing the user���s
communications over the Internet.
The Debug class has access to ���runtime stats���, via methods like
getRuntimeStat(). Right now, this is mostly reporting information from
ART about garbage collection, but in the future it may be expanded for
more stuff.
NetworkStatsManager can give you access to historical network
access statistics, without your having to track it yourself via TrafficStats.
ActivityManager allows you to call setWatchHeapLimit() when running
on an emulator (at least, I think that���s what ���This API only work if running
on a debuggable (userdebug or eng) build��� means in this case). This
sets a threshold of memory consumption for your process. If your process
exceeds that threshold, a heap dump will be generated, so you can try 
to determine why your app is consuming so much memory. By default, the
heap dump will be shared using an ACTION_SEND Intent, so you can arrange
to save it off somewhere. Or, your app can have an ACTION_REPORT_HEAP_LIMIT
activity and get the heap dump yourself, perhaps set up to only be part
of your debug builds so the activity does not ship with your production
app.
There are many more bits of goodness in the M Developer Preview, particularly
for more specialized areas (e.g., better BLE scanning), and there are probably
some tidbits that I have missed. Note, though, that this blog post is about
the M Developer Preview, and things can change for better or worse by the
time this ships ���for realz��� as Android 5.2/6.0/whatever.
Tomorrow, I will take a look at some stuff that, IMHO, is more of a ���mixed bag���
that showed up in the M Developer Preview.
April 23, 2015
AndGlobe: Another Call For More Sites
I maintain a list of Android developer support sites
called AndGlobe. The
particular emphasis is on sites that are not in
English. Android development is worldwide and multilingual;
our support sites need to match.
If you operate, or know of, a site for asking
Android development questions and answers, that is not
listed on the AndGlobe site,
please let me know,
or follow the instructions on the GitHub repo
to contribute new sites that way.
And, of course, please link to or otherwise promote
the AndGlobe site, so Android
developers know the wider range of Q&A sites that they
can use for getting their questions answered.
Thanks!
April 16, 2015
The Busy Coder's Guide to Android Development Version 6.6 Released
Subscribers now have
access to the latest release of The Busy Coder’s Guide to Android Development,
known as Version 6.6, in all formats. Just log into
your Warescription page and download
away, or set up an account and subscribe!
This update includes:
A new chapter on Android’s convoluted tasks system. This chapter
includes a review of what tasks are, what the standard behavior that
users see without any changes on our part, and what some common modifications
are to task behavior. It also covers persistent tasks and
documents-as-tasks, introduced in Android 5.0.
A new chapter on the App Runtime for Chrome (ARC), for getting
your Android app running on Chrome OS, as was profiled
earlier in this blog
An updated chapter on UI Automator, covering the new UI Automator 2.0
and its Gradle/Android Studio integration
A new chapter on Android Studio dialogs, focusing on the Project
Structure dialog and the Translations Editor.
A new section in the chapter on the Play Services SDK’s fused location
provider, covering SettingsApi (to prompt users to enable locations)
and requestLocationUpdates() (for periodically getting location fixes)
Minor changes for Android 5.1
A somewhat revamped chapter on ContactsContract, as the previous
edition of this chapter was really old
The next update is planned for the first half of June. In other words,
the next update is planned for sometime after the Google I|O conference,
in case Google makes some Earth-shattering (or at least book-shattering
or author-shattering) announcements.
April 9, 2015
Getting on the ARC
2015 has potential to be a rather interesting year in the world of
Android development, as Google builds an ARC.
The App Runtime for Chrome (ARC) is now in a beta state, where any
developer can repackage their app to run… on Chrome OS.
Now, that may not excite you much.
There are a variety of Chromebooks and other Chromeboxen available
(though personally I am still waiting for a Chromedome to be announced).
Sales appear to be in the low tens of millions. To put that in perspective,
that means there are probably more Chrome OS users than there are users
of Froyo, but fewer than there are users of Gingerbread, based on the
April 2015 device dashboards.
Or, to put it another way, there are probably more Kindle Fire tablets
and BlackBerry 10 phones (which, BTW, can run Android apps, lest ye forget)
than Chrome OS devices. And since the ARC runtime environment is not
completely standard, getting to Kindle Fire and BlackBerry 10 may be an
easier jump for many developers.
However, what makes ARC interesting is not Chrome OS, but Chrome itself.
ARC apps can run in the Chrome Web browser, as it is one of the development
tools. So far, Google has emphasized ARC for Chrome OS, possibly as part
of building up a catalog of ARC-enabled apps. But it would seem bizarre
for Google to limit ARC to Chrome OS over the long term if it can also be
used with the “desktop” Chrome browser.
Chrome OS users are modest in number. Chrome users number in the hundreds
of millions. And while some of that will overlap with existing Android
users (who may be running Chrome on their Android devices), there will
still be countless others for whom Chrome might be their first avenue for
using Android apps.
To look at it another way, Chrome OS devices are seriously outnumbered
by OS X devices, which are outnumbered by Chrome browser users. There have
been rumors, off and on, of OS X eventually being able to run iOS apps
natively. ARC not only increases the odds that Apple might make that
move, to keep up competitively, but Google still comes out ahead if they
make ARC available for Chrome.
Now, most Android apps on Chrome probably require tweaking. Gestures that might
make sense on a touchscreen may be difficult, if not impossible, to execute
using a mouse or touchpad. Hardware that may not be available on the host
computer, like NFC, will not be available on the ARC. That’s why I think
that Google is soft-pedaling this now, to allow developers to play around
with ARC while expectations are low, as they are “only” going to be available
to Chrome OS users. Google is probably hoping that there will be a fairly
large set of ARC-ready apps by the time that they roll out ARC for public
use on desktop Chrome.
(and many of the tweaks needed for ARC will also help those apps’ compatibility
with other less-conventional environments, like TVs)
For some developers, ARC will be a non-starter or permanently uninteresting.
But for other apps and other environments, ARC could be a game-changer.
In particular, ARC powers a “write once, run on every form factor” model,
where Android handles phones, tablets, and TVs, while ARC handles desktops,
notebooks, and netbooks. Apps that require that sort of full-fleet availability,
such as bespoke apps for businesses, governments, and other organizations,
could really benefit from ARC, and may suffer less from ARC’s limitations.
While you could get ARC-style ubiquity from other tools, like Bluestacks
or Genymotion, ARC and Chrome will likely have a simpler distribution model,
if for no other reason than they will be free and, in the case of Chrome,
perhaps already installed.
If ARC sounds intriguing, your #1 problem will be the
singular lack of documentation.
Then again, you are probably used to this, as various aspects of Android
development also are under-documented. But with trial, error, and
the assistance of Android book authors with chrome domes,
you may find that ARC opens up some new opportunities for you.
Just be a bit careful using RxJava on ARC. An arc reactor
is nothing to be trifled with.



