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.
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.
Well, 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 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.