Search code examples
androidandroid-widgetandroid-jetpack-composeglanceglance-appwidget

How to get the AppWidgetId of a Compose Glance widget?


I have a table with all the widgets a user has created. I want to customize individual widgets using the according table entry and update the according table entry upon interaction with a widget.

uid AppWidgetId Title
0 23 First widget
1 165 Second widget

(1) When the user clicks on the widget, I want to update only the entry for the widget that was clicked. In the non-Glance world, I do this by adding an onClickListener to every widget which looks somewhat like this:

val widgetView = RemoteViews(context.packageName, R.layout.widget_layout)
val widgetPendingIntent = ...
widgetView.setOnClickPendingIntent(R.id.appwidget_text, widgetPendingIntent)
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidgetId, widgetView)

In the glance widget, I assume that I need to make the composable clickable like this:

    @Composable
    override fun Content() {
        Column(
            modifier = GlanceModifier
                .fillMaxSize()
                .clickable(onClick = actionRunCallback<ClickOnWidget>())
        ) {
            Text(
                text = "Title",
                modifier = GlanceModifier.fillMaxSize(),
            )
        }
    }

The ActionCallback looks like this:

class ClickOnWidget : ActionCallback {
    override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
       // Update my table with the click
    }
}

I would expect an appWidgetId here, but only see a glanceId: GlanceId. Can I use this to get the appWidgetId or directly use glanceId as an identifier in my table?

(2) I want to style my widget according to the data in the table. What is the best way to style the widget according to the table entry with the according appWidgetId? E.g. somehow like this:

    @Composable
    override fun Content() {
        Column(
            modifier = GlanceModifier
                .fillMaxSize()
                .clickable(onClick = actionRunCallback<ToastAction>())
        ) {
            Text(
                // *** Add a text depending on the appWidgetId ***
                text = titleOf(appWidgetId),
                modifier = GlanceModifier.fillMaxSize(),
            )
        }
    }

Solution

  • You cannot get the AppWidgetId, and this is by design.

    For your use case, we recommended creating your own stable ID each time a new App Widget is created. You will store that ID in the state attached to the App Widget and use it to link it to some of your data (where you would have previously stored the AppWidgetId). The reason for this indirection is that we intend on handling Backup & Restore, but the AppWidget IDs change during that process, so relying on them in your own data structures is not a very good approach.

    To implement this, you might want to look at GlanceAppWidget.stateDefinition, PreferencesGlanceStateDefinition, LocalState and GlanceAppWidget.updateAppWidgetState.