androidbroadcastreceiverandroid-widgetstackview

Android 12 BroadcastReceiver onReceive intent.getExtras allways null


I'm trying to build a stackview widget, which should display differnt data when swiping through it. So far everything is working, but when I want to receive the index of the clicked card in the widget, I always get an extra or action of 'null'. I already have tried several workarounds, but none of them is working in my application. I also set up a complete new application for only making this work completely isolated. But here I get the exact same behaviour.

Several workarounds I tried to pass the index:

What I observed is, that the getViewAt funtion is called several times with a position(p0) of "0" before it gets called by the right positions from the generated exampleData List... But I don't know if this causes the Nulls in the onReceive function, when an card is clicked.

Here is my coding:

Manifest.xml

<service android:name=".ExampleWidgetService"
        android:permission="android.permission.BIND_REMOTEVIEWS">
</service>

WidgetLayout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <StackView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/stackview">
    </StackView>

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textColor="#ffffff"
        android:textStyle="bold"
        android:text="empty"
        android:textSize="20sp" />
</FrameLayout>

WidgetItemEntry

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:text="Icon"
        android:id="@+id/newwidgetentry">

    </TextView>
</LinearLayout>

AppWidgetProvider

package com.example.widgettest
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.RemoteViews
import android.widget.Toast

/**
 * Implementation of App Widget functionality.
 */
public const val clickedCategory: String = "com.example.myapplication.buttonpress.id"
public const val stackviewButton = "stackviewbutton"

class newwidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray,
    ) {
        // There may be multiple widgets active, so update all of them
        for (appWidgetId in appWidgetIds) {

        /*    val widgetText = context.getString(R.string.appwidget_text)
            // Construct the RemoteViews object
            val views = RemoteViews(context.packageName, R.layout.newwidget)
            views.setTextViewText(R.id.newwidgetentry, widgetText)*/

            val serviceIntent: Intent = Intent(context, ExampleWidgetService::class.java).apply{
                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
                data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
            }
            val views = RemoteViews(
                context.packageName,
                R.layout.newwidget
            ).apply{
                setRemoteAdapter(R.id.stackview, serviceIntent)
                setEmptyView(R.id.stackview, R.id.empty_view)
            }

            val toastIntent = Intent(context, newwidget::class.java).run {
                action= stackviewButton
                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
                data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
                PendingIntent.getBroadcast(context,
                    0,
                    this,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
            }
            views.setPendingIntentTemplate(R.id.stackview, toastIntent)


            // Instruct the widget manager to update the widget
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds)
    }

    override fun onEnabled(context: Context) {
        // Enter relevant functionality for when the first widget is created
    }

    override fun onDisabled(context: Context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    override fun onReceive(context: Context?, intent: Intent?) {


   var clickedCat2 = intent?.getBundleExtra("test")?.getInt(clickedCategory,-1)
             /*val clickedCat2: Int? = intent?.getIntExtra(clickedCategory, -1)*/

        Toast.makeText(context, "onreceive +$clickedCat2" , Toast.LENGTH_SHORT).show();
        if (stackviewButton.equals(intent?.getAction())){
            val clickedCat: Int? = intent?.getIntExtra(clickedCategory, 0)
            Toast.makeText(context, "widgetbuttonpressed id + $clickedCat", Toast.LENGTH_SHORT).show();
        }
        super.onReceive(context, intent)
    }
}

RemoteView Factory

package com.example.widgettest

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import com.google.gson.Gson

private const val REMOTE_VIEW_COUNT: Int = 2

data class WidgetItem(
    val id: String,
)

class ExampleWidgetService : RemoteViewsService() {

    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
        return ExampleWidgetService1(this.applicationContext, intent)
    }
}

class ExampleWidgetService1(private val context: Context, intent: Intent) :
    RemoteViewsService.RemoteViewsFactory {

    private lateinit var exampleData: List<WidgetItem>

    override fun onCreate() {
        exampleData = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") }
        val test = 123
    }

    override fun onDataSetChanged() {
    }

    override fun onDestroy() {
    }

    override fun getCount(): Int {
        return exampleData.size
    }

    override fun getItemId(p0: Int): Long {
        return p0.toLong()
    }

    override fun getViewAt(p0: Int): RemoteViews {

        return RemoteViews(context!!.packageName, R.layout.newwidgetentry).apply {

            setTextViewText(R.id.newwidgetentry, exampleData[p0].id)

       

     val fillIntent = Intent().apply {
                    Bundle().also { extras ->
                        extras.putInt(clickedCategory, p0)
                        putExtra("test",extras)
                    }
                }

  /*val fillIntent = Intent().apply {
                putExtra(clickedCategory, p0)
            }*/
            setOnClickFillInIntent(R.id.newwidgetentry, fillIntent)
        }
    }

    override fun getLoadingView(): RemoteViews? {
        return null
    }

    override fun getViewTypeCount(): Int {
        return 1
    }


    override fun hasStableIds(): Boolean {
        return true
    }

}

I really appreciate everykind of help!!! Thank you already in advance!!


Solution

  • I've the same issue, finally I resolve this issue!

    Just change setPendingIntentTemplate's pending intent flags to PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE.