Awareness API & Android O using BroadcastReceiver

4.3k Views Asked by At

I have an Android app which uses the Awareness API to setup a fence when a headset is plugged in.

I have implemented the AwarenessFence using code much like in the examples at: https://developers.google.com/awareness/android-api/fence-register.

I have a PendingIntent defined as:

PendingIntent.getBroadcast(context, 0, new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)

Then in my AndroidManifest.xml file I have

<receiver android:name=".fence.FenceDetector$MyFenceReceiver">
<intent-filter>
    <action android:name="my.application.packageFENCE_RECEIVER_ACTION" />
</intent-filter>

This is declared in the Manifest due to the fact that I want to receive broadcasts even when my app is in the background.

This all worked fine on Android 7.0 and below, but when I run this on a Android 8.0 I get the error:

BroadcastQueue: Background execution not allowed: receiving Intent { act=my.application.packageFENCE_RECEIVER_ACTION

I assume this is due to the new restrictions for background execution on Android O.

Can anybody tell me how to register a broadcast receiver which can listen to awareness fence triggers when in the background on a Android device running API 26.

Let me know If there is something which is unclear or if I need to elaborate something.

Thanks in advance

3

There are 3 best solutions below

4
On BEST ANSWER

I can't test it on device now, but from all I've read, the limitation is only on implicit broadcasts. That means, if you create a explicit broadcast instead, that's all you need to make it work.

That means instead of this:

// implicit intent matching action
PendingIntent.getBroadcast(context, 0,
    new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)

you do that:

// explicit intent directly targeting your class
PendingIntent.getBroadcast(context, 0,
    new Intent(context, FenceDetector.MyFenceReceiver.class), 0)
2
On

Your understanding is very correct.

Apps that target Android 8.0 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest. An implicit broadcast is a broadcast that does not target that app specifically.

Apps can continue to register for explicit broadcasts in their manifests.

Source

If you are only interested in setup a fence when a headset is plugged in. You can use

Note: A number of implicit broadcasts are currently exempted from this limitation. Apps can continue to register receivers for these broadcasts in their manifests, no matter what API level the apps are targeting. For a list of the exempted broadcasts, see Implicit Broadcast Exceptions.

You can resister for ACTION_HEADSET_PLUG in Android Manifest. In onReceive you can either:

  • start a NotificationManager.startServiceInForeground() so that you can keep doing work in background.
  • Find a way to duplicate the service's functionality with a scheduled job. If the service is not doing something immediately noticeable to the user, you should generally be able to use a scheduled job instead. Refer Job Scheduler
  • Defer background work until the application is naturally in the foreground.

I would suggest to use the combination of Job Scheduler with ACTION_HEADSET_PLUG if long running work needs to be done.

Other wise if a short duration work needs to be done which in onReceive of you can take help from the following:

A BroadcastReceiver that uses goAsync() to flag that it needs more time to finish after onReceive() is complete. This is especially useful if the work you want to complete in your onReceive() is long enough to cause the UI thread to miss a frame (>16ms), making it better suited for a background thread.

you should not start long running background threads from a broadcast receiver. After onReceive(), the system can kill the process at any time to reclaim memory, and in doing so, it terminates the spawned thread running in the process. To avoid this, you should either call goAsync() (if you want a little more time to process the broadcast in a background thread) or schedule a JobService from the receiver using the JobScheduler, so the system knows that the process continues to perform active work.

Source

1
On

I did a little digging around and stumbled upon this blog post by CommonsWare. It states the very problem that you're facing.

From the above post :-

One of the more controversial changes in Android O — for apps with a sufficiently-high targetSdkVersion — is the effective ban on implicit broadcasts.

So, according to this, I don't think your problem has anything to do with the Awareness API. Instead, it's because of the new behaviour introduced in Android 8.

Unfortunately, though, there doesn't seem to be viable solution to this as of now. Again, phrasing from the same post :-

If you are receiving system-sent implicit broadcasts (e.g., ACTION_PACKAGE_ADDED), keep your targetSdkVersion at 25 or lower, until we figure out better workarounds that (hopefully) do not involve polling.

So, hopefully there would be a better solution for 8 in the near future. Meanwhile, you could consider other options or could consider lowering your targetSDK.