Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update Glance App Widget inside a service in android or outside of the GlanceAppWidget

Android 12 introduced new API for creating app widgets called Glance. My use case is, I have a button inside a Glance composable and upon pressing that a foreground service is invoked which fetches data from server and update the widget. In legacy API we can do update by creating new remote views and update the widget via app widget manager like below.

class COVIDSummaryUpdateService : Service() {
            private val TAG = "COVIDSummaryUpdateService"
            private val FOREGROUND_SERVICE_ID = 111

            override fun onBind(intent: Intent?): IBinder? {
                return null
            }

            override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
                startNotificationForForeground()
                val views = RemoteViews(
                    [email protected],
                    R.layout.covid_summary_layout
                )
                views.setViewVisibility(R.id.ivRefresh, View.GONE)
                views.setViewVisibility(R.id.progressBar, View.VISIBLE)
                val componentName = ComponentName(
                    [email protected],
                    COVIDSummaryAppWidgetProvider::class.java
                )
                val manager =
                    AppWidgetManager.getInstance([email protected])
                manager.updateAppWidget(componentName, views)

                COVIDApiService.getCOVIDApi().getSummary()
                    .enqueue(object : Callback<SummaryResponse> {
                        override fun onResponse(
                            call: Call<SummaryResponse>,
                            response: Response<SummaryResponse>
                        ) {
                            if (response.isSuccessful && response.code() == 200) {
                                updateWidgetWithResponse(response.body())
                            } else {
                                hideProgressView()
                            }
                            stopService()
                        }

                        override fun onFailure(call: Call<SummaryResponse>, t: Throwable) {
                            t.message?.let { Log.d(TAG, it) }
                            hideProgressView()
                            stopService()
                        }
                    })
                return START_STICKY
            }

            private fun stopService() {
                stopForeground(true)
                stopSelf()
            }

            private fun updateWidgetWithResponse(summaryResponse: SummaryResponse?) {
                try {
                    summaryResponse?.let {
                        val views = RemoteViews(
                            [email protected],
                            R.layout.covid_summary_layout
                        )
                        views.setTextViewText(
                            R.id.tvNewConfirmedCases,
                            "${summaryResponse.global.newConfirmed}"
                        )
                        views.setTextViewText(
                            R.id.tvNewDeaths,
                            "${summaryResponse.global.newDeaths}"
                        )
                        views.setTextViewText(
                            R.id.tvNewRecovered,
                            "${summaryResponse.global.newRecovered}"
                        )
                        views.setTextViewText(
                            R.id.tvTotalConfirmedCases,
                            "${summaryResponse.global.totalConfirmed}"
                        )
                        views.setTextViewText(
                            R.id.tvTotalDeaths,
                            "${summaryResponse.global.totalDeaths}"
                        )
                        views.setTextViewText(
                            R.id.tvTotalRecovered,
                            "${summaryResponse.global.totalRecovered}"
                        )
                        views.setViewVisibility(R.id.ivRefresh, View.VISIBLE)
                        views.setViewVisibility(R.id.progressBar, View.GONE)
                        val componentName = ComponentName(
                            [email protected],
                            COVIDSummaryAppWidgetProvider::class.java
                        )
                        val manager =
                            AppWidgetManager.getInstance([email protected])
                        manager.updateAppWidget(componentName, views)
                    }
                } catch (e: Exception) {
                    e.message?.let { Log.d(TAG, it) }
                    hideProgressView()
                    stopService()
                }
            }

            private fun hideProgressView() {
                val views = RemoteViews(
                    [email protected],
                    R.layout.covid_summary_layout
                )
                views.setViewVisibility(R.id.ivRefresh, View.VISIBLE)
                views.setViewVisibility(R.id.progressBar, View.GONE)
                val componentName = ComponentName(
                    [email protected],
                    COVIDSummaryAppWidgetProvider::class.java
                )
                val manager =
                    AppWidgetManager.getInstance([email protected])
                manager.updateAppWidget(componentName, views)
            }

            private fun startNotificationForForeground() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    startForeground(
                        FOREGROUND_SERVICE_ID,
                        createNotification(
                            "COVID19Service", "COVID19 Summary Channel",
                            null,
                            getString(R.string.foreground_not_text)
                        )
                    )
                }
            }

            @RequiresApi(Build.VERSION_CODES.O)
            private fun createNotification(
                channelId: String,
                channelName: String,
                contentTitle: String?,
                contentText: String,
                pendingIntent: PendingIntent? = null
            ): Notification {
                val notificationChannel =
                    NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
                notificationChannel.description = channelId
                notificationChannel.setSound(null, null)
                notificationChannel.lightColor = Color.BLUE
                notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE

                val notificationManager =
                    getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
                notificationManager.createNotificationChannel(notificationChannel)

                return Notification.Builder(this, channelId).let { builder ->
                    contentTitle?.let {
                        builder.setContentTitle(contentTitle)
                    }
                    builder.setContentText(contentText)
                    builder.setSmallIcon(R.drawable.ic_covid_19_33)
                    pendingIntent?.let { builder.setContentIntent(it) }
                    builder.build()
                }
            }
        }
    }
like image 221
Vengatesh Murugasamy Avatar asked Oct 20 '25 02:10

Vengatesh Murugasamy


1 Answers

You can use GlanceAppWidgetReceiver to fetch data from your source. To send data to your widget:

val glanceId = GlanceAppWidgetManager(context).
getGlanceIds(YourAppWidget::class.java).firstOrNull()

YourAppWidget.update(context,glanceId)

Please check this article for all source code : https://enofeb.medium.com/android-jetpack-glance-for-app-widgets-bd7a704624ba

like image 113
Enes Zor Avatar answered Oct 21 '25 15:10

Enes Zor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!