2

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(),
            )
        }
    }
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Karim
  • 73
  • 8

4 Answers4

4

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.

PierreBdR
  • 42,120
  • 10
  • 46
  • 62
  • hello @PierreBdR, where should we generate our own stable ID? I am using a config activity, tried to pass my own preferences via the bundle send to the setResult() call of the configuration activity but bundle parameters are not available in currentState of the GlanceAppWidget instance. – mehmet6parmak Mar 17 '22 at 12:46
  • Thank you! Solved it like this in combination with what I describe here: https://stackoverflow.com/questions/70502137/how-to-update-the-appwidgetstate-of-a-compose-glance-widget-from-a-configuration/73670747#73670747 – Karim Sep 10 '22 at 09:46
2

Well, I struggled with this as well, finally I log the glanceId, it prints like this: AppWidgetId(appWidgetId=304)

This is my hack way:

val appWidgetId = LocalGlanceId.current.toString().filter { it.isDigit() }.toInt()

It should be fine if you don't upgrade your glance version or Google keeps print glance id with appWidgetId.

Tsung Wu
  • 1,064
  • 9
  • 17
  • Thank you for your reply! That seems to work. However, I solved it in a proper way as described in the answer one above. – Karim Sep 10 '22 at 09:48
1
fun GlanceId.toAppWidgetId(): Int {
    val appWidgetId = javaClass.kotlin.memberProperties.find { it.name == "appWidgetId" }
        ?.get(this) as? Int
    return appWidgetId ?: AppWidgetManager.INVALID_APPWIDGET_ID
}
  • Answer needs supporting information Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](https://stackoverflow.com/help/how-to-answer). – moken Jul 17 '23 at 07:07
0

You can get it calling

GlanceAppWidgetManager(context).getAppWidgetId(glanceId)
Roberto Leinardi
  • 10,641
  • 6
  • 65
  • 69