SYSTEM_ALERT_WINDOW on Android Wear

It’s a question I’ve seen a few times now on the Google+ Wear developer community and StackOverflow: How do developers acquire the SYSTEM_ALERT_WINDOW permission on Android Wear devices running Marshmallow?

tl;dr: You don’t, at least not for now. Keep your apps on targetSdkVersion 22.

But for those of you interested in the longer answer… This question affects my leading Wear app, so after seeing it come up a couple of times – and wanting to know the answer myself – I did some research. I posted my findings on StackOverflow, but decided that the topic could use a bit more explication, so I wrote this post.

First, a bit of background. Why should anyone, developer or otherwise, care?

Well, SYSTEM_ALERT_WINDOW is the internal name for an Android permission that lets one app draw to the screen superimposed over other apps. Android Police has a good explainer on the subject in the context of Android phones – but here, we’re concerned about smartwatches. And it turns out that this is really quite a handy thing to do on a watch, mostly because it allows apps to add functionality to the Android Wear homescreen, aka its watch face:

  • Wear Mini Launcher (and other third-party app launchers) let you swipe in from an edge of the screen to open their app list, or a quick-settings panel.
  • Similarly, Tappur uses a swipe-from-edge gesture to access actions, like turning smart light bulbs on and off.
  • My own Wearable Widgets uses a swipe in the middle of the watch face to move between widgets.

You may notice that all of these examples are about swipe gestures, and therein lies SYSTEM_ALERT_WINDOW’s power on the watch. By drawing an invisible window over the watch screen, we can detect touch gestures (like swipes), and initiate actions in response. It’s not an overstatement to say that this capability is central to the usefulness of many of these apps.

So, it’s useful. What’s the problem?device-2016-01-28-161527

Well, as mentioned earlier, SYSTEM_ALERT_WINDOW is what’s known as a permission, meaning that users have to specifically allow an app to do it. This is because it can be dangerous to let one app draw over others on your screen: the same capability that lets Wear Mini Launcher detect a swipe on your watch face can be turned to evil, letting a malware app detect the touch inputs you think you’re making on some other app: say, the password you’re entering in your banking app. Such an attack is known as tapjacking, and it’s led one Googler to describe SYSTEM_ALERT_WINDOW as “raised to be above DANGEROUS“.

In Android 6 (Marshmallow), Google overhauled the permission model so that users need to explicitly allow apps access to dangerous permissions – generally hailed as a long-overdue improvement. But what about permissions that are “above DANGEROUS”? Well, granting access to those takes an additional step; you need to go to a particular screen in the system Settings and flip a switch for each app that you want to allow.

Well, OK, that seems fair. Again, what’s the problem?

In a nutshell: Android Wear doesn’t have that system Settings screen.

device-2016-01-28-162633_framedWell, perhaps it has it; API level 22 on Wear did. But as of API 23, you can no longer get to it. The system doesn’t link to it (as it did on 22), and if you try to invoke it from a Wear app, you’ll get a crash. The Intent doesn’t resolve.

So what does that mean for those of us whose Wear apps rely on SYSTEM_ALERT_WINDOW? For the time being, I can only see one course of action: keep your apps on targetSdkVersion 22.

This works, because the new permission model is only enforced on apps that target Marshmallow, which is SDK level 23. This “solution” comes with a serious downside, however: your apps will be unable to use any of the cool new features that come with Marshmallow (or later versions). And some of these are seriously handy on Wear (like the ability to use -round resource qualifiers). But at this moment, I don’t see another way forward – though I’ll discuss longer-term options in a moment.

Before I do, however, I just want to note something for the developers reading this: keeping your Wear app on targetSdkVersion 22 means that the enclosing handheld app also needs to be on 22.

I haven’t noticed this restriction before, but I’ve tested it in this case, and it’s true. If your Wear app uses SYSTEM_ALERT_WINDOW and targets API level 22, but it’s packaged in a handheld app that targets 23, installation to the watch will fail. If you’re interested, the error message in logcat is:

W/WearablePkgInstaller: Wearable com.myapp has a permission “android.permission.SYSTEM_ALERT_WINDOW” that is not granted in the host application.

Which isn’t entirely truthful (this happens even if the permission is granted to your host app), but the result is the same: it doesn’t work. Don’t do it, kids.

So, moving on, what are our options for the future?

If we’re lucky, Google will add the Settings screen for users to enable SYSTEM_ALERT_WINDOW on the watch at some point, maybe when Marshmallow is released to the wider Wear ecosystem. You can (possibly) encourage them to do so by starring this issue in the external Android bug tracker. I have my doubts, though, as I get the feeling they are trying hard to discourage use of this permission, and may just cut it off completely on Wear. What if they do – what then?

The obvious (but wrong) answer is to keep our apps on API 22 indefinitely. At some point, however, this will become untenable. There will eventually be some new feature that your app can’t live without, or at the very least, someday you’ll want to move your minSdkVersion beyond 22.

The only other solution that occurs to me is to abandon swipe gestures for some other interaction.

One that I’ve experimented with in Wearable Widgets is tapping on the side of the watch (rather than its screen): by monitoring the device’s accelerometer, such a tap can usually be detected. My current code for doing so is somewhat primitive, and doesn’t work on some older, low-spec watches (with slow accelerometers), but it’s a start – and by the time it becomes necessary, hopefully there’ll be very few of these low-spec watches left in the wild. I intend to open-source my code for doing this soon.

If you have any other ideas, I’d be happy to hear them! Drop a comment below, or join the discussion on the Android Wear dev community.

UPDATE: (2 May 2016) My original testing of SYSTEM_ALERT_WINDOW on Android Wear was done using an API level 23 emulator, and the (recalled) second-edition LG Urbane LTE – the only publicly-released Android Wear hardware running Marshmallow at the time. Since then, the official Android 6.0.1 update has rolled out to all Wear devices, and I’ve confirmed that this issue still exists.

The larger issue also affects the other “super-permission”, WRITE_SETTINGS. It appears to be the same situation: the intent for the user to grant or deny the permission doesn’t resolve on Android Wear.

In addition, I’ve followed up a couple of related leads, which interested developers might find good to know about:

  • It’s emerged that apps installed to Android 6+ from Google Play are being granted SYSTEM_ALERT_WINDOW by default, simply by requesting the permission in their manifests. When I first read about this, I thought it might be a usable workaround for the problem that this post is all about… but no. I’ve tested it, and this grant does not extend to Wear. Apparently, even if the “host” handheld app is installed form Play, the Wear app isn’t considered to be – it still doesn’t get the permission
  • It is possible to grant SYSTEM_ALERT_WINDOW (and, I would expect, WRITE_SETTINGS) to a Wear app by installing with adb -g. I can’t see how this would be useful to end-user deployment, but might be handy for testing.

Bottom line is that we’re no further along in finding a resolution to this issue, so as far as I know, my workaround recommendations above still stand.

UPDATE: (19 July 2016) With the release of the second dev preview for Android Wear 2.0, this issue is now fixed. Firing a Settings.ACTION_MANAGE_OVERLAY_PERMISSION intent device-2016-07-17-213626 now opens a system window where the user can enable this permission. And as you can see, it applies to WRITE_SETTINGS too. Perfect!

Many thanks to the folks at Google who have shepherded the fix through.

Layout-based Watch Faces for Android Wear

Watch faces are basically live wallpapers for your smartwatch – this makes a certain sort of sense, and it is indeed how Google has implemented them on Android Wear. And like live wallpapers, they can be either Canvas or OpenGL-based. But while that works okay for most traditional live wallpapers, there are a lot of watch face designs for which neither of those models works overly well. Examples might include predominantly-digital faces, legacy faces (which were developed as Activities), faces that pack in a lot of data, and anything else with a fairly sophisticated layout.

What you’d like, in fact, is exactly that – to use a standard Android layout for your watch face. It turns out that you can, and in this post, I’m going to show you how. Which of course means that it’s long post, heavy with code. You have been warned.

We’re going to build our layout-based watch face on top of a CanvasWatchFaceService, and the key to it is that you can inflate an arbitrary layout into a View, and then call View.draw(canvas) to render a Canvas from it. The rest of the code is just window dressing, really, but some if it isn’t entirely obvious.

Before we get started, I just want to say that this guide is meant for programmers with some Android experience, and ideally a bit of experience on Android Wear. I’m not going to walk you through every last step of creating a project in the IDE, setting up and running an emulator, what ambient mode means, and so forth. There are lots of great tutorials online for those sorts of things, so I’m going to assume that you have those skills comfortably in hand.

With that said, it’s high time that we…

Get Started

Begin by creating a new Wear watch face project in Android Studio. The current version (1.2 as of this writing) includes watch face templates; we’ll use the Digital template for the example I’ll be explaining here.

[If you’re not using Android Studio yet, now’s a great time to start – and one of these days I’ll write up my hard-won guidelines for converting a mature Eclipse project over to AS. But today, we’ll be starting with a new project, so that’s not an issue.]

Here’s a walk-through of the project creation wizard. The details of these things tend to change from version to version of the IDE, so your screens may not look exactly like this, but hopefully they’ll be close enough.image10

Obviously, the app and package names are up to you.image06

Android Wear isn’t supported below API level 18, so it makes sense to choose that as the minSdkVersion on the phone/tablet side.

For this example, you don’t need an activity on the handheld (mobile) app, because it only serves as a container for installing the watch face. If the previous sentence doesn’t make sense to you, I suggest you go look at Packaging Wearable Apps for clarification.

On the Wear side, however, we do want an activity – or more precisely, a watch face:image04

And on the next screen, choose the Digital watch face template, and give it a name of LayoutFaceService:image00

When Android Studio has created the new project, go ahead and run it, just to make sure that you have a working starting point. It’s probably easiest to do so in an emulator, and when you do, it should look something like this..image03

Now that we have it working, let’s break it! This is an ordinary canvas-based watchface; it’s a reasonable foundation for what we’re going to build, but has some unnecessary bits. So, the next step is to clear those out. Delete the following from your LayoutFaceService source file:

  • The entire createTextPaint method
  • The contents of the onDraw method
  • The two Paint fields (mBackgroundPaint and mTextPaint) and all references to them in the code

And in the interest of brevity, I’m not going to walk you through cleaning up various other loose ends in the template (such as its use of the deprecated Time class). If it works at the end, we’ll call that good. Turning it into production-ready code is left as an exercise for the reader.

But before we move on, let’s create a few new fields that we’ll be needing soon. In the Engine class, insert the following:

private int specW, specH;
private View myLayout;
private TextView day, date, month, hour, minute, second;
private final Point displaySize = new Point(); 

Creating the layout

If all we wanted to render was a simple digital face (like the template), we wouldn’t need a layout – it’s easy enough to render directly. But the whole idea here is to render something more complicated, something that would be a pain to draw out directly onto the canvas.

On the other hand, I still want to keep it simple-ish for this example. image05Here’s a mockup of the watch face I had in mind when I started this post:

It’s just about complicated enough to make this technique worthwhile.

If you have any Android dev experience, you can probably create a layout like this in your sleep. I’m using a simple RelativeLayout, and you can find it in the source code for this example on GitHub. But really, the important thing to take away is that it’s in res/layout/watchface.xml, in my project’s wear module.image01

Initialization

Now we need to load that layout into our watch face service. The place to do so is in the Engine.onCreate method, and the code is as follows:

LayoutInflater inflater = 
    (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
myLayout = inflater.inflate(R.layout.watchface, null);

If you’ve ever worked with layouts in Android Java code, this will look familiar. It’s pretty standard stuff.

In order to use this layout, we’ll also need some data about the display, so put the following code in onCreate also:

Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
        .getDefaultDisplay();
display.getSize(displaySize);

specW = View.MeasureSpec.makeMeasureSpec(displaySize.x, 
    View.MeasureSpec.EXACTLY);
specH = View.MeasureSpec.makeMeasureSpec(displaySize.y,
    View.MeasureSpec.EXACTLY);

It looks complicated, but this is just boilerplate; you can copy this stuff verbatim into any layout-based watch face you build.

Finally, we’ll initialize the TextView fields to avoid having to find them every time we need to update the date and time. Again, this is quite basic stuff.

day = (TextView) myLayout.findViewById(R.id.day);
date = (TextView) myLayout.findViewById(R.id.date);
month = (TextView) myLayout.findViewById(R.id.month);
hour = (TextView) myLayout.findViewById(R.id.hour);
minute = (TextView) myLayout.findViewById(R.id.minute);
second = (TextView) myLayout.findViewById(R.id.second);

Making it work

In all Canvas-based watch faces, the onDraw method is where the pixels meet the code. Ours is no different, but one of the advantages to a layout-based face is that onDraw tends to be simpler than if we were drawing everything manually. In essence, we’ve front-loaded the drawing when we set up the layout, so we can offload the actual drawing code to the layout itself.

All of the following code goes in the onDraw handler. The first line is unchanged from the template that Android Studio generated for us:

mTime.setToNow();

That sets up the Time variable to the current instant. Next we apply it to all the on-screen date and time TextViews:

day.setText(String.format("%ta", mTime.toMillis(false)));
date.setText(String.format("%02d", mTime.monthDay));
month.setText(String.format("%ta", mTime.toMillis(false)));

hour.setText(String.format("%02d", mTime.hour));
minute.setText(String.format("%02d", mTime.minute));
if (!mAmbient) {
    second.setText(String.format("%02d", mTime.second));
}

These all follow a similar pattern, extracting a field from mTime and formatting it for display. It’s fiddly, but not actually hard.

So now, all our text fields have been updated, and we need to output it to the screen. But we’re not quite ready to draw it to the Canvas yet; first, we need to finalize the layout.

myLayout.measure(specW, specH);
myLayout.layout(0, 0, myLayout.getMeasuredWidth(), 
myLayout.getMeasuredHeight());

This is the crucial step to making a layout-based watch face work. If you’ve been doing ordinary Android development, it’s likely you haven’t seen code like this before; it usually happens behind the scenes in the View classes, and you don’t need to worry about it. But in our case, we’re using a “naked” layout – one not attached to a view hierarchy – so we need to do this ourselves. If we didn’t the layout simply wouldn’t render, and this technique wouldn’t work.

Whatever you do, don’t skip this step.

Now, we’re ready to output it to the Canvas:

canvas.drawColor(Color.BLACK);
myLayout.draw(canvas);

The first line clears the Canvas to black, and the second one draws the current contents of our layout.

And that’s it for interactions with the Canvas: usually the biggest part of onDraw, but reduced by the layout approach to a trivial line of code.

Making it work in the real world

At this point, we have a working watch face. It updates the display fields to the current time, and draws them to the screen.

Before moving on, I’d just like to note that much of the job has been done for us by the template itself. It contains quite a few pre-written methods for triggering updates every minute (when in ambient mode) or every second (when not), as well as more esoteric details like tracking time zone changes. Google has put all of this code into the template, and we don’t need to touch any of it.image02

Our watch face works! But, it’s not quite ready for release.

Ambient Mode

One key behavior of Android Wear watches is the two modes they operate in, ambient and normal. The latter is when the user’s actively engaging with their watch, and we’ve got that covered.

But a watch spends most of its time in ambient mode, and a watch face needs to behave differently when it does. The Engine class we’re working from includes a method, onAmbientModeChanged, which is where we’ll put the code to handle the changes.

First, the time-keeping infrastructure built into the template drops its refresh rate from once-per-second to once-per-minute, and as a result, we don’t want to be showing the “seconds” fields when in ambient mode. Because we’re using a standard Android layout, we hide and show the seconds the same way you would in any Activity:

if (inAmbientMode) {
    second.setVisibility(View.GONE);
    myLayout.findViewById(R.id.second_label)
            .setVisibility(View.GONE);
} else {
    second.setVisibility(View.VISIBLE);
    myLayout.findViewById(R.id.second_label)
            .setVisibility(View.VISIBLE);
}

The second change is a bit less obvious. The visual design I’m working from is based around chunky fonts, and I’ve used boldface type to achieve that effect. But that’s not a good idea when a watch is in ambient mode, for a couple of reasons.

  • AMOLED screens use less power when fewer pixels are lit, so boldface text probably uses twice as much power as normal text.
  • Some screen technologies have an issue with burn-in, and Android Wear addresses this by shifting pixels slightly on-screen. This works much better with thin lines, however, so watch face developers are encouraged to avoid thick strokes in ambient mode.

The upshot is, I only want to use boldface for my text fields when the watch is not in ambient mode. Here’s the code I use to do it:

Typeface font = Typeface.create("sans-serif-condensed",
        inAmbientMode ? Typeface.NORMAL : Typeface.BOLD);
ViewGroup group = (ViewGroup) myLayout;
for (int i = group.getChildCount() - 1; i >= 0; i--) {
    ((TextView) group.getChildAt(i)).setTypeface(font);
} 

You’ll notice that this is kind of a cheat, and only works because every view in my layout is a TextView. image07But it does work – here’s my watch face in ambient mode:

In most cases, more complicated layouts will require more complicated transitions between ambient and normal modes, but the details will need to be determined case-by-case.

Screen shape

In this example, I’m primarily designing for a square watch face. But in the real world, you’ll want to support round watches too – they make up the majority of Android Wear devices in the wild..

To avoid making this long post even longer, all I’m going to do to adjust this watchface for round screens is to shrink it a bit, so that the square text fits in the round hole. I’ll do that in two places; the first is the template’s existing onApplyWindowInsets method. Replace the code in that method (after the call to super.onApplyWindowInsets with the following:

if (insets.isRound()) {
    mXOffset = mYOffset = displaySize.x * 0.1f;
    displaySize.x -= 2 * mXOffset;
    displaySize.y -= 2 * mYOffset;

    specW = View.MeasureSpec.makeMeasureSpec(displaySize.x, 
         View.MeasureSpec.EXACTLY);
    specH = View.MeasureSpec.makeMeasureSpec(displaySize.y,
         View.MeasureSpec.EXACTLY);
} else {
    mXOffset = mYOffset = 0;
}

For round screens, we basically compute a margin – 10% of the square layout width – and apply it to the displaySize we got in onCreate. From there, we just recompute the MeasureSpec fields accordingly – this is determines the actual size of the layout.

We also need to use this margin when drawing, and that happens in onDraw, not surprisingly. All that’s needed is one new line of code, highlighted below, in the canvas-drawing section:

canvas.drawColor(Color.BLACK);
canvas.translate(mXOffset, mYOffset);
myLayout.draw(canvas);

As its name implies, translate just moves the Canvas before drawing to it, applying the offsets that we calculated above.image09

Here’s what it looks like on a round screen:

Nothing fancy, but it works. However, this is another case where the exact implementation details will depend upon your design. Besides just shrinking the design like this, other solutions might include moving elements of the layout around to fit, or using a different layout completely.

Our layout-based watch face is now complete, and just about ready to deploy. All that’s left are metadata elements like previews and icons, but these are no different than any other watch face, and don’t really merit coverage here.

Caveats

So far, I’ve mostly talked about the advantages of layout-based watch faces: primarily that you can use all of Android’s UI tools to build your watch face, rather than laboriously drawing it by hand (as it were).

But there are a few downsides as well.

Layout isn’t automatic

This is the biggest pitfall of this approach, for Android devs of all experience levels. Ordinarily, you create your layout, stick it in an activity, and it displays on screen. With a watch face, it’s not quite that simple.

I touched on this back in the onDraw method, but it’s important enough that it bears repeating. Remember these two lines of code?

myLayout.measure(specW, specH);
myLayout.layout(0, 0, myLayout.getMeasuredWidth(), 
         myLayout.getMeasuredHeight());

These two methods, measure and layout, need to be called after any change to your content that affects the size of any layout element. In my example, I ensure that it will happen by putting them in onDraw, right before drawing to the Canvas. But if you have more complicated logic – perhaps with different parts of your layout being updated in different places – you’ll need to take some care to ensure that measure and layout are always called when they need to be.

If you ever find that your layout is not rendering correctly, this is the first thing to look for.

Battery impact is not out of the question

I’ve developed (and deployed) several watch faces using layouts, and none of them seem to use an excessive amount of battery. However, battery life is always a concern on Android Wear, and it at least seems plausible that using a layout for your watch face will incur some extra overhead – and thus use more power.

As I said, I haven’t seen an issue with it yet, but given this is a new technique, I feel I should mention it.

And while we’re on the subject, you should take care to optimize your code for battery life generally. In the interests of brevity and clarity, I’ve taken a few shortcuts with this example (like updating the date fields every second) that you probably shouldn’t do in the real world. Google has some specific guidelines in this area; read them, follow them, and use your own good sense.

WatchViewStub doesn’t seem to work

A few paragraphs ago, I mentioned the possibility of using different layouts for round versus square screens. If you’ve done much Android Wear development, you’re probably familiar with a standard pattern for addressing this: WatchViewStub, which automagically selects the correct layout based on screen shape.

Unfortunately, WatchViewStub doesn’t work with the technique I’ve outlined here. It’s not open-source, so I can’t delve into the details of why not, but in my testing, inflating a WatchViewStub-based layout just doesn’t work. The magic smoke escapes somewhere, and you always end up with the same layout, regardless of screen shape.

Of course, you can still use different layouts for different shapes; this simply means that you need to select the proper one manually. And the good news is that onApplyWindowInsets does work, so you can easily get the screen shape there – and inflate the proper layout accordingly. Take a look at the Android docs (or the onApplyWindowInsets method in the template) for guidance on how to use this handy method.

Are layout-based watch faces for you?

It’s a fair question – they’re not right for every case.

If you’re creating a face that’s mostly built from graphical assets, it’s probably easier to render them directly to the screen, rather than shunting them through a layout first. Likewise, if your design involves moving many elements around the screen (such as analog clock hands, for example), using a layout may actually be more work.image08

On the other hand, if your watch face design is text-heavy, or has complicated interrelationships between the elements, or perhaps is based off an existing Android app – then using a layout probably is a good choice. And some operations that are a real PITA with direct rendering – like wrapping text – are just effortless with a layout.

It’s also worth noting that layouts aren’t an all-or-nothing proposition. It’s perfectly reasonable to draw some graphical elements directly to the Canvas, then draw your layout. I’ve used this hybrid technique in production watchfaces too.

In any case, I hope you’ve found this guide useful, and it helps you build better watch faces. The sample watch face I’ve built here can be found on both GitHub and Google Play.


Update 11 May 2015:

Fixed a bug with the onApplyWindowOffsets code for round watch face support.

Testing In-App Billing on Android

I’ve spent the last few weeks extending Wearable Widgets with in-app purchasing (variously known as IAP, in-app billing, or IAB). Honestly, there’s no good reason why this should have taken weeks. I can immediately think of a couple of reasons why it has, though.

The first is security. Because IAB is a commercial transaction, and because some lowlife will always be looking to scam you out of two bucks, you need to apply various layers of security to it – and these add time and effort.

A paradoxical aspect of this is that you’re specifically advised not to use any code examples you might find online, especially those in the documentation, because the scum who crack these apps will have seen all those code structures before – and will probably have scripts ready to break it.

But on the other hand, it seems to me that there’s a real downside to asking myriad developers like me to roll their own IAB solutions. Most of us are developers with no significant security experience – meaning that our homebrewed solutions are probably riddled with security holes and rookie mistakes, making them much less secure than code that’s been developed by security professionals. It’s a bit of a programming paradox, really.

Further, Google also includes something they call an IabHelper, a pre-written wrapper around all of the IAB routines, and many of their examples are based around this helper class. But it seems to me that this flies in the face of the roll-yer-own security recommendation; I have to believe that any two-bit script-kiddie app-cracker knows right where IabHelper lives, exactly how to recognize it (even in obfuscated code), and how to exploit it. Seriously, why would Google even provide this?

But that’s not really what I want to write about here.

The topic I want to cover, the other area which has cost me a lot of time in my IAB implementation, is testing. Part of that is simply because it’s a complicated beast – OK, fair enough. But a big part of it is because the documentation for testing this stuff is about as clear as mud, if not actually misleading in some places. So I thought I’d share my experience in testing Google’s IAB as of mid-2014. Be warned, from here on in this entry’s going to be pitched at Android devs who are elbow-deep in IAB; I’m not going to explain every term along the way. If you’re not a developer, you may or may not find it worth your while to read on. But if you are in the target demographic, hopefully what follows will save you some anguish.

Google provides a couple of doc pages about IAB testing, and you should start by reading those. They lay the groundwork, and nothing they tell you is really wrong – it’s just not quite the whole story. But nonetheless, you should start there, and get some understanding of the lay of the land.

Now, I’m going to tell you the real story. Here’s the first gotcha: that first link above says that there are two ways to test your IAB app, test purchases and real purchases. And the page no sooner describes those two before it goes on to discuss a third way, static responses. So the main thing I’d like to do here is to lay out the three ways to test IAB, with the things you need to know about each. I’ll present them in the order you should do them; complete your testing with one before you move on to the next.

Stage 1: Static Responses

This is where you should start: write your first pass at your IAB implementation, unit-test all the routines involved, and send the transactions off to Google Play with an SKU of android.test.purchased. [You can also use .canceled, .refunded, and .item_unavailable to test unsuccessful responses. But let’s go for success right now.] These are the easiest tests, because you don’t need to upload or sign your APK in any way (other than the normal debug signature that the IDE automatically applies). These tests can also be run by any user – although apparently you’ll get incomplete information returned if you don’t test using your developer account, so I recommend sticking with a device registered to the same Google ID as your Play developer console. When you issue an IAB request with one of the static-response SKUs, the process will look something like this:

stage_1_1
  1. The purchase dialog Google Play shows will be completely dummied-up (see above).
  2. Assuming you’re using android.test.purchased, the transaction always succeeds.
  3. It returns to the calling activity’s onActivityResult() handler with a resultCode of -1, and a blank INAPP_DATA_SIGNATURE, but otherwise real values matching what you sent in the purchase request.

One important point I didn’t see anywhere in the docs: after you use a static-response SKU once, that SKU is now “owned” by the user that the device is registered to. And it will show as such in any subsequent IAB calls, which makes retesting a hassle. Apparently, it will reset by itself in a day or so, though I didn’t test this. I didn’t have the patience to wait a day between each debugging run of my app. But it turns out that you can also consume it in your app, with code like this:

IInAppBillingService.consumePurchase(
    3, context.getPackageName(), purchaseToken);

where purchaseToken is returned from the purchase request you sent. In my experience with static responses, the purchaseToken was a simple construct like “inapp:my.package.name:android.test.purchased”, but YMMV.

And that’s about it for static responses. When you’ve done all the testing you can with them, you’re ready to move on to…

Stage 2: Real SKU, test user

Update 10 May 2015:

Since I wrote this post 11 months ago, Google has completely overhauled their  “test purchase” procedure. At the least:

    • Apps can no longer be in draft on Google Play for non-static purchases; they must be published to some channel (alpha, beta, or production).
    • IAB transactions for apps published to alpha channels do not cost whitelisted users real money. This was how I expected things to work last year (see below); now, they actually do.
    • With the advent of Android Studio, it’s now possible to debug an app signed with a production cert. So handy!

I may do a new writeup on it at some point, but until I do, be aware that much of whatI did write in this section is no longer correct – and that Google’s docs are actually pretty reasonable now.

This is the case that Google calls test purchases, and it involves sending your real item SKUs but in a test mode. Everything is like a real purchase, except that no money actually changes hands. It sounds so simple in the documentation… but there are a couple of serious pitfalls.

First, you’ll need to get things set up on your Google Play developer console. You’ll also need to wait several hours after doing these changes for them to roll out through Google’s server network.

  • You’ll need to have created your IAB items (on the In-app Products tab of your app in the console)
  • The user ID(s) you’re going to test with must be whitelisted for IAB testing: Settings > Account Details > License Testing. Note that real SKUs can’t be purchased by the user who owns the Google Play account, even in test mode.
  • You need to upload a signed APK, with a higher versionCode (in the manifest) than anything you have published on Play.

When you actually do your testing, it will also need to be with a signed APK, and one that has the same versionCode as the uploaded-but-unpublished APK in the last step above.

The bad news here is that there’s no using the debugger at this stage: logcat is your friend. But the good news is that it doesn’t actually have to be the same APK as you’ve uploaded to the dev console; it just needs to have the same versionCode. This requirement – for an uploaded but unpublished version of your APK – is never really, explicitly covered in the docs. It’s mentioned obliquely, but nowhere near as directly as it needs to be.

If your test version hasn’t been uploaded to the APK tab on the console, the IAB call will fail. OTOH, if it is published at all – even in the alpha or beta channel – your test users will really get billed for the IAP.

This one took me days to work out: silly me, I thought the alpha channel was specifically for this kind of testing, and as long as I had the user’s Gmail address on the whitelist, the transaction wouldn’t post. Wrong. The whitelist is ignored for published APK versionCodes.

In fact, it’s even a bit worse than that – the whitelist is ignored for all versionCodes less than or equal to anything published. Let me illustrate that with a concrete example:

  1. The production versionCode of my app is 9 – that’s my baseline, before I started implementing IAB.
  2. After I had a first cut of IAB done – with versionCode 10 – I published it to my alpha-test group and had a whitelisted user try it. He got charged, because 10 wasn’t unpublished.
  3. Learning from these mistakes, I uploaded a later version (13) to Google Play, but did not publish it. I then emailed the APK to some whitelisted testers, who successfully used the IAB feature without being charged.
  4. Moving closer to release, I built versionCode 14 and published it to beta. I fully expect users of this version to be charged, and they are.
  5. However: the next day, one of my whitelisted test group from step 3 – still on versionCode 13 – tried out the IAB and got charged for it. My best explanation for this is that, even though 13 is still unpublished, the whitelist is ignored, because 14 is published.

The bottom line is, upload to Google Play but don’t publish anything at this stage. But once you have all those pieces in place, and have given them time to take effect, here’s how it’ll go:

stage_2_1
  1. The purchase dialog will be real, but with the extra “test order” line shown above.
  2. The purchase always succeeds, AFAICT
  3. The return values are all real (token, payload, etc)
  4. The transaction appears in your Google Wallet Merchant console with a “Test:” prefix

As with static responses, this SKU is now owned by the user, causing a similar headache for any retesting you need to do. You’ll need to cancel it from your Merchant console (or alternatively, it will apparently expire in a week or two).

Be aware that, in addition to cancelling the purchase, you’ll also need to clear the cache for Google Play Store and Play Services on the device – and probably reboot, and maybe wait an hour or so – before the SKU will stop showing up as owned.

Stage 3: Real Purchases

This isn’t really “testing” IAB any more; everything is live, from the APK down to the financial transaction. But Google includes it on their testing page, so I’ll discuss it briefly here as well. Basically, this is the scenario your user will be in whenever the versionCode of the APK they’re running matches one that’s published on Google Play, in any channel (Alpha, Beta, or Production). It’s also the way the purchase will play out if the user isn’t on your IAB, or the whitelist entry hasn’t percolated through the Googlenet.

As confirmation of any of these situations, any time Google Play shows a purchase dialog without the “test order” verbage (compare the above and below screenshots), the user will get charged for the purchase.

 stage_3_1

I’m not going to go through the whole process here, because it’s a live transaction, and everything happens accordingly. If you do need to retest in this case, its like Stage 2: clear the cache for Google Play Store and Services, reboot the phone, wait an hour.

Time Is Money

One recurring theme you might notice from the above is all of the waiting that goes on. From hours to weeks, there are many, many aspects of IAB testing which require you to just twiddle your thumbs (or go read Engadget) for extended periods. Which is why testing this has taken so damn long. As of today, I’m really not sure that IAB was worth doing, especially for (what should have been) a dead-simple implementation like mine: I have exactly one product, essentially an unlock key to turn the “trial” version of my app into the “full” version. There are several other tried-and-true ways to implement this sort of freemium model, and I’m not at all convinced that IAB was the right one to choose. Sure, it may be slightly lower-friction for the users – but enough so to justify weeks of extra developer time? Will it actually gain that many more conversions? It’s impossible to know.

The API of Unintended Consequences

A change to the Android API that arrived in the KitKat is that alarms don’t necessarily arrive when your code requested them to. From the docs:

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; seesetWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
Now, many apps won’t be especially bothered, but I have two apps with clock widgets that rely on the alarms being delivered exactly on time; otherwise, the clock widget is wrong until the alarm does get delivered. Which means that my widgets now need to use setExact() rather than just set().

Which is fine as far as it goes – but what’s not mentioned above is that there is no setExactRepeating(). Here’s another extract from that same page:

Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whosetargetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.”

This means that my widgets must now reschedule their alarms every minute. Which means my widgets are now running more code every minute than they were before. Which means that my widgets are now using more battery than they were before – exactly the opposite of Google’s stated intent with this change.

Footnote #1: I should also mention that, in my testing, these inexact alarms occur on KitKat devices even if targetSdkVersion is set to 18. That’s not what the docs (quoted above) say, but that’s how it works on my Nexus 7.

Footnote #2: No, I can’t use AnalogClock and Chronometer to avoid these alarms (and use less battery). They’re too limited for my widgets. My analog clocks are 24-hour (the AnalogClock class is 12-hour only), and the Chronometer class really isn’t suitable for digital clocks.

What’s a Drawable?

The Android docs sum it up as

a general abstraction for “something that can be drawn.”

as circular a definition as you’re ever likely to come across. And the rest of the description isn’t much better. So for the first 18 months of my Android career I avoided drawables, mostly because I was not at all clear just what they heck they were. But in late 2010 I found myself working on an app that actually needed them, and finally reached that understanding. Here it is, for the benefit of any other confused Android devs out there.

Lots of Android widgets (not App Widgets) have a graphical component. A button has chrome that makes it look like a button; a TextView has a background, which may simply be a color, or may be something more elaborate. And what’s interesting about these graphics is that they often are – or at least should be – more dynamic than you might think. Colors change depending on whether a widget has focus. Buttons often have a visible pressed state. Different screen sizes and densities require backgrounds to adapt.

As a result, it’s not very helpful to use a simple graphics primitive – like a color value, or a static bitmap – for the graphical aspect of a widget. What’s needed is a middleware layer: a software object which you can give graphical instructions for different circumstances, and which will then manage them accordingly. Guess what? That’s a Drawable.