Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Receiving broadcast from notification on Android Oreo

I have a custom button in a sticky notification.
I used to attach a PendingIntent to it for receiving button clicks:

Intent intent = new Intent();

intent.setAction("com.example.app.intent.action.BUTTON_CLICK");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 2000, intent, PendingIntent.FLAG_UPDATE_CURRENT);
contentViewExpanded.setOnClickPendingIntent(R.id.button, pendingIntent);

When i run this code on Oreo , i get BroadcastQueue: Background execution not allowed in logcat and don't receive button click.

I registered receiver with manifest:

<receiver
    android:name=".BroadcastReceiver.NotificationActionReceiver"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.intent.action.BUTTON_CLICK"/>
    </intent-filter>
</receiver>

I also tried registering receiver in my code:

NotificationActionReceiver mMyBroadcastReceiver = new NotificationActionReceiver();
IntentFilter filter = new IntentFilter("com.example.app.intent.action.BUTTON_CLICK");
mContext.registerReceiver(mMyBroadcastReceiver, filter);

This works but only when the app is visible to user.

Thanks for help

like image 984
Behnam Maboudi Avatar asked Sep 02 '17 17:09

Behnam Maboudi


People also ask

What is meant by receiving a broadcast in Android?

Broadcast in android is the system-wide events that can occur when the device starts, when a message is received on the device or when incoming calls are received, or when a device goes to airplane mode, etc. Broadcast Receivers are used to respond to these system-wide events.

How do you stop broadcasting on Android?

CB stands for Cell Broadcast. To stop recieving CB messages, go to Messaging then tap the Menu key and select Settings. New menu appears then please, find CB activation and Uncheck it.

On which thread broadcast receivers will work in Android?

Broadcast Receiver by default runs on Main Thread only.


2 Answers

Never use an implicit Intent when an explicit Intent will work.

Replace:

Intent intent = new Intent();

intent.setAction("com.example.app.intent.action.BUTTON_CLICK");

with:

Intent intent = new Intent(this, NotificationActionReceiver.class);

And remove the <intent-filter> from the NotificationActionReceiver <receiver> element.

like image 116
CommonsWare Avatar answered Oct 18 '22 10:10

CommonsWare


I ran into this issue as well on Android 8 - Oreo, but given my library project requirements, I don't have the explicitly named BroadcastReceiver class implementation, that the end-client will declare in it's AndroidManifest.

Solution:

Specify the application package on the Intent using setPackage(String).

Example:

// Application unique intent action String
final String receiverAction = getApplicationContext().getPackageName() 
                             + BaseLibraryReceiver.ACTION_SUFFIX;
// No need for Class definition in the constructor.
Intent intent = new Intent(); 
// Set the unique action.
intent.setAction(receiverAction);
// Set the application package name on the Intent, so only the application
// will have this Intent broadcasted, thus making it “explicit" and secure.
intent.setPackage(getApplicationContext().getPackageName());
...

From the Android Broadcasts: Security considerations and best practices docs.

In Android 4.0 and higher, you can specify a package with setPackage(String) when sending a broadcast. The system restricts the broadcast to the set of apps that match the package.

Here’s an example of the BroadcastReceiver declared (or merged) in to the end-client application’s AndroidManifest:

 <receiver
        android:name=“com.subclassed.receiver.ReceiverExtendedFromLibrary"
        android:exported="false"
        android:enabled="true">

        <intent-filter>
            <action android:name="${applicationId}.action.MY_UNIQUE_ACTION"/>
        </intent-filter>

 </receiver>

Since my example revolves around a library project that broadcasts an Intent, I’ve decided to keep the <intent-filter> and <action /> in the <receiver> declaration. Otherwise, there would be non-unique broadcast actions being fired, which could lead to potential issues where multiple applications receive the wrong broadcast. This is mostly a safety precaution. Of course you still need to check the action in the implementation of the BroadcastReceiver.

Hope someone finds this helpful!

like image 27
Sakiboy Avatar answered Oct 18 '22 09:10

Sakiboy