Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

widget case that doesn't work with Oreo 8.1 - message received: W/BroadcastQueue: Background execution not allowed: receiving Intent

My widget app is running fine on all android version except 8 Oreo. I get a W/BroadcastQueue: Background execution not allowed: receiving Intent message.

There is an interesting blog from CommonsWare but I don't fully understand why it applies to my case. https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html

My case looks pretty simple: I have a widget with a button and I want to change the text's button when it is clicked.

What is the right way to fix this issue?

TestWidget.java

public class TestWidget extends AppWidgetProvider {
    private static RemoteViews views;
    private static boolean buttonClicked = false;
    public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";

    @Override
    public void onReceive(Context context, Intent intent)
    {
        super.onReceive(context, intent);

        if(intent.getAction().equals(ACTION_AUTO_UPDATE))
        {
                Log.i("TESTWID", "get onReceive");
        }
    }

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        views = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        views.setOnClickPendingIntent(R.id.wid_btn_tst, setButton(context));

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.i("TESTWID", "onupdate ");

        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    public static PendingIntent setButton(Context context) {
        Intent intent = new Intent();
        intent.setAction("TEST");
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
        ComponentName myWidget = new ComponentName(context, TestWidget.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(myWidget, remoteViews);
    }

}

TestWidgetReceiver.java

public class TestWidgetReceiver extends BroadcastReceiver{
    private static boolean isButtonON = false;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("TESTWID", "onReceive "+intent.getAction());

        if(intent.getAction().equals("TEST")){
            updateWidgetButton(context, 2);
        }
    }

    private void updateWidgetButton(Context context, int index) {
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        if(index == 2) {
            if(isButtonON) {
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test Off");
                isButtonON = false;
            }
            else{
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test On");
                isButtonON = true;
            }
        }

        TestWidget.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
    }

}

Manifest.xml:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Test"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name=".TestWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <intent-filter>
                <action android:name="AUTO_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/test_widget_info" />
        </receiver>

        <receiver
            android:name=".TestWidgetReceiver"
            android:label="widgetBroadcastReceiver" >
            <intent-filter>
                <action android:name="TEST" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/test_widget_info" />
        </receiver>

    </application>
like image 755
narb Avatar asked Jun 17 '18 07:06

narb


2 Answers

It's subtle, but it is because of the implicit broadcast being used to trigger your TestWidgetReceiver. It is implicit because it is only specifying the action portion of the Intent. Make the broadcast Intent explicit by specifying the receiver class in the constructor:

public static PendingIntent setButton(Context context) {
    Intent intent = new Intent(context, TestWidgetReceiver.class);
    intent.setAction("TEST");
    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
like image 186
Larry Schiefer Avatar answered Sep 20 '22 17:09

Larry Schiefer


Things are changed now a days in Android. For the security & battery consumption google introduced so many ways & increased some problem for developers. You haven't passed the Context of the TestWidgetReceiver.class to you intent.

You can do it like that in java

Intent intent = new Intent(context, TestWidgetReceiver.class);

or in kotlin

val intent = Intent(context, TestWidgetReceiver.class);

You can read more changes here

https://developer.android.com/about/versions/oreo/android-8.0-changes

Regards

like image 45
Shivam Mathur Avatar answered Sep 21 '22 17:09

Shivam Mathur