How to launch widget Config when placing a widget using requestPinAppWidget()

338 views Asked by At

Current Situation

My widget uses a config Activity to Select type of Widget.. So whenever I place my widget (using system launcher), the config activity launches first. It asks for configuring the widget and which is must for my widget. This works well...

Second method to place the widget on Homescreen is using the following code `

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName myProvider = new ComponentName(context, ExampleAppWidgetProvider.class);

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // that the user allowed the widget to be pinned. Note that, if the pinning
    // operation fails, your app isn't notified. This callback receives the ID 
    // of the newly-pinned widget (EXTRA_APPWIDGET_ID).
    PendingIntent successCallback = PendingIntent.getBroadcast(
            /* context = */ context, 
            /* requestCode = */ 0,
            /* intent = */ new Intent(...), 
            /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT);

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
}

` Above is from official docs

My code is this

ComponentName mmwidgetProvider = new ComponentName(MainActivity.this, mm_WidgetAppWidgetProvider.class);
                if (mAppWidgetManager.isRequestPinAppWidgetSupported()) {
                    Intent pinnedWidgetCallbackIntent = new Intent(MainActivity.this, mm_WidgetAppWidgetProvider.class);
                    PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0,
                            pinnedWidgetCallbackIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

                    mAppWidgetManager.requestPinAppWidget(mmwidgetProvider, null, pendingIntent);
                }

The Problem

However the problem is, when I execute this code the widget is placed on the screen but the widgetConfig activity is not launched and so my widget shows nothing. Widget's data totally depends upon the config activity which needs to be initialized eveytime a new widget is placed.

Please is there any way I can use the above code and when I execute it, My widget config activity is launched asking for widget to configured first.

Any help is Greatly Appreciated Thanks in Advance.

2

There are 2 answers

0
Subash K On

This solution worked for me: Try replacing the use of 'getBroadcast' with 'getActivity' and see if it works. Change your pinnedWidgetCallback Intent in your configuration activity.

ComponentName mmwidgetProvider = new ComponentName(MainActivity.this, YourConfigurationScreenActivity.class);
            if (mAppWidgetManager.isRequestPinAppWidgetSupported()) {
                Intent pinnedWidgetCallbackIntent = new Intent(MainActivity.this, mm_WidgetAppWidgetProvider.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0,
                        pinnedWidgetCallbackIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

                mAppWidgetManager.requestPinAppWidget(mmwidgetProvider, null, pendingIntent);
            }
0
licryle On

@Subash answer wouldn't work for me so I've dug this a bit.

I'm also puzzled why this isn't either made easier, or explained in the documentation page

I think the best solution here, and likely the one intended given the pendingIntentCallBack is to use the AppWidgetProvider() as receiver of the callback intent.

So here's what I ended up doing

In the AppWidgetProvider full code on github, I declare the action in my companion object

class FlashcardWidgetProvider : AppWidgetProvider() {
...

    companion object {
        const val ACTION_CONFIGURE_LATEST = "APPWIDGET_CONFIGURE_LATEST"
    }
}

Which I then use as callback pendingIntent:

        binding.homeAddWidget.setOnClickListener {
            val appWidgetManager = AppWidgetManager.getInstance(context)
            val myProvider = ComponentName(requireContext(), FlashcardWidgetProvider::class.java)

            if (appWidgetManager.isRequestPinAppWidgetSupported) {
                val confIntent = Intent(context, FlashcardWidgetProvider::class.java)
                confIntent.action = FlashcardWidgetProvider.ACTION_CONFIGURE_LATEST

                val callbackIntent = PendingIntent.getBroadcast(
                    /* context = */ context,
                    /* requestCode = */ 0,
                    /* intent = */ confIntent,
                    /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)

                appWidgetManager.requestPinAppWidget(myProvider, null, callbackIntent)
            }
        }

And finally, back to my AppWidgetProvider, I start my activity in the onReceiver. Note that the WidgetId is unknown, and for now I only take the highest ID. I'm not 100% sure this is the right way:

class FlashcardWidgetProvider : AppWidgetProvider() {
...
    override fun onReceive(context: Context?, intent: Intent?) {
        Log.i("WidgetProvider", "onReceive (action: ${intent?.action})")

        when (intent!!.action) {
            ACTION_CONFIGURE_LATEST -> {
                val widgetId = appMgr.getAppWidgetIds(
                    ComponentName(context, FlashcardWidgetProvider::class.java)).last()

                val confIntent = Intent(context, FlashcardConfigureActivity::class.java)
                confIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)
                confIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

                startActivity(context, confIntent, null)
            }
        }
    }
}

Hope that helps!