@@ -26,105 +26,56 @@ import android.content.Context
2626import android.content.Intent
2727import android.os.Bundle
2828import android.util.Log
29- import android.widget.RemoteViews
30- import android.widget.TextView
31- import androidx.work.ExistingPeriodicWorkPolicy
32- import androidx.work.PeriodicWorkRequestBuilder
33- import androidx.work.WorkManager
29+ import androidx.work.*
3430import dagger.android.AndroidInjection
35- import kotlinx.coroutines.Dispatchers
36- import kotlinx.coroutines.async
37- import kotlinx.coroutines.runBlocking
38- import kotlinx.coroutines.withContext
3931import org.blitzortung.android.alert.handler.AlertDataHandler
4032import org.blitzortung.android.alert.handler.AlertHandler
41- import org.blitzortung.android.data.Flags
42- import org.blitzortung.android.data.Parameters
43- import org.blitzortung.android.data.TimeInterval
4433import org.blitzortung.android.data.provider.standard.JsonRpcDataProvider
4534import org.blitzortung.android.location.LocationHandler
4635import org.blitzortung.android.map.overlay.color.StrikeColorHandler
47- import java.text.DateFormat
48- import java.text.SimpleDateFormat
49- import java.util.*
5036import java.util.concurrent.TimeUnit
5137import javax.inject.Inject
52- import org.blitzortung.android.alert.handler.Strikes
53- import org.blitzortung.android.app.view.AlarmView
54- import org.blitzortung.android.data.DataArea
55- import org.blitzortung.android.data.provider.calculateLocalCoordinate
56- import org.blitzortung.android.data.provider.result.DataReceived
57-
5838
5939class WidgetProvider : AppWidgetProvider () {
6040
61- @set:Inject
62- internal lateinit var colorHandler: StrikeColorHandler
63-
64- @set:Inject
65- internal lateinit var alertHandler: AlertHandler
66-
67- @set:Inject
68- internal lateinit var alertDataHandler: AlertDataHandler
69-
70- @set:Inject
71- internal lateinit var locationHandler: LocationHandler
72-
73- @set:Inject
74- internal lateinit var dataProvider: JsonRpcDataProvider
75-
76- var df: DateFormat = SimpleDateFormat (" hh:mm:ss" )
77-
7841 companion object {
7942 private const val WIDGET_UPDATE_WORK_NAME = " widget_update_work"
8043 private const val UPDATE_INTERVAL_MINUTES = 5L
8144 }
8245
83-
84- override fun onAppWidgetOptionsChanged (context : Context ? , appWidgetManager : AppWidgetManager ? , appWidgetId : Int , newOptions : Bundle ? ) {
85- AndroidInjection .inject(this , context)
46+ override fun onAppWidgetOptionsChanged (context : Context , appWidgetManager : AppWidgetManager , appWidgetId : Int , newOptions : Bundle ? ) {
8647 Log .v(Main .LOG_TAG , " WidgetProvider.onAppWidgetOptionsChanged()" )
8748 super .onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
88-
89- // Update the widget with the new size
90- if (context != null && appWidgetManager != null ) {
91- locationHandler.start()
92- val views = getUpdatedViews(context, appWidgetManager, appWidgetId)
93- appWidgetManager.updateAppWidget(appWidgetId, views)
94- locationHandler.shutdown()
95- }
49+ update(context, appWidgetManager, intArrayOf(appWidgetId))
9650 }
9751
98- override fun onReceive (context : Context ? , intent : Intent ) {
99- AndroidInjection .inject(this , context)
52+ override fun onReceive (context : Context , intent : Intent ) {
10053 val action = intent.action
10154 Log .v(Main .LOG_TAG , " WidgetProvider.onReceive() $action " )
10255 if (ACTION_APPWIDGET_UPDATE == action) {
103- locationHandler.start()
104- val appWidgetManager = AppWidgetManager .getInstance(context!! )
56+ val appWidgetManager = AppWidgetManager .getInstance(context)
10557 val appWidgetIds = appWidgetManager.getAppWidgetIds(
10658 ComponentName (context, WidgetProvider ::class .java)
10759 )
108- for (appWidgetId in appWidgetIds) {
109- val views = getUpdatedViews(context, appWidgetManager, appWidgetId)
110- appWidgetManager.updateAppWidget(appWidgetId, views)
111- }
112- locationHandler.shutdown()
60+ update(context, appWidgetManager, appWidgetIds)
11361 }
11462 }
11563
11664 override fun onUpdate (context : Context , appWidgetManager : AppWidgetManager , appWidgetIds : IntArray ) {
117- AndroidInjection .inject(this , context)
11865 Log .v(Main .LOG_TAG , " WidgetProvider.onUpdate()" )
66+ update(context, appWidgetManager, appWidgetIds)
67+ }
11968
120- locationHandler.start()
69+ private fun update (context : Context , appWidgetManager : AppWidgetManager , appWidgetIds : IntArray ) {
70+ val workManager = WorkManager .getInstance(context)
12171
122- for (appWidgetId in appWidgetIds) {
123- val views = getUpdatedViews(context, appWidgetManager, appWidgetId)
124- appWidgetManager.updateAppWidget(appWidgetId, views)
125- }
72+ val inputData = workDataOf(" appWidgetIds" to appWidgetIds)
73+
74+ val workRequest = OneTimeWorkRequestBuilder <WidgetUpdateWorker >()
75+ .setInputData(inputData)
76+ .build()
12677
127- locationHandler.shutdown( )
78+ workManager.enqueue(workRequest )
12879 }
12980
13081 override fun onEnabled (context : Context ) {
@@ -154,92 +105,4 @@ class WidgetProvider : AppWidgetProvider() {
154105 private fun cancelPeriodicUpdates (context : Context ) {
155106 WorkManager .getInstance(context).cancelUniqueWork(WIDGET_UPDATE_WORK_NAME )
156107 }
157-
158- private fun getUpdatedViews (context : Context , appWidgetManager : AppWidgetManager , appWidgetId : Int ): RemoteViews {
159- // Get widget size from options
160- val options = appWidgetManager.getAppWidgetOptions(appWidgetId)
161- val isPortrait = context.resources.configuration.orientation == android.content.res.Configuration .ORIENTATION_PORTRAIT
162- val widthDp = options.getInt(if (isPortrait) AppWidgetManager .OPTION_APPWIDGET_MIN_WIDTH else AppWidgetManager .OPTION_APPWIDGET_MAX_WIDTH )
163- val heightDp = options.getInt(if (isPortrait) AppWidgetManager .OPTION_APPWIDGET_MAX_HEIGHT else AppWidgetManager .OPTION_APPWIDGET_MIN_HEIGHT )
164-
165- // Convert dp to pixels
166- val displayMetrics = context.resources.displayMetrics
167- val density = displayMetrics.density
168-
169- // Use reasonable defaults if size is not available
170- val totalWidthPx = if (widthDp > 0 ) (widthDp * density).toInt() else 300
171- val totalHeightPx = if (heightDp > 0 ) (heightDp * density).toInt() else 300
172-
173- // Account for LinearLayout padding (10dp on each side)
174- val paddingPx = (10 * density).toInt()
175- val availableWidth = (totalWidthPx - paddingPx * 2 ).coerceAtLeast(100 )
176-
177- // Account for text view height and margin
178- val textHeightPx = (32 * density).toInt() // Headline text size
179- val textMarginPx = (4 * density).toInt()
180- val availableHeight = (totalHeightPx - paddingPx * 2 - textHeightPx - textMarginPx).coerceAtLeast(100 )
181-
182- Log .v(Main .LOG_TAG , " Widget total: ${widthDp} dp x ${heightDp} dp = ${totalWidthPx} px x ${totalHeightPx} px" )
183- Log .v(Main .LOG_TAG , " Widget available for image: ${availableWidth} px x ${availableHeight} px" )
184-
185- val alarmView = AlarmView (context)
186- alarmView.setColorHandler(colorHandler, 60 )
187-
188- val location = locationHandler.location!!
189- val scale = 5
190- val x = calculateLocalCoordinate(location.longitude, scale)
191- val y = calculateLocalCoordinate(location.latitude, scale)
192- val dataArea = DataArea (x, y, scale)
193-
194- val parameters = Parameters (region = 0 , gridSize = 5000 , interval = TimeInterval (duration = 60 ), dataArea = dataArea)
195- val result = runBlocking {
196- withContext(Dispatchers .Default ) {
197- async {
198- Log .v(Main .LOG_TAG , " Widget.getUpdatedViews() retrieve running in ${Thread .currentThread().name} " )
199- var result = DataReceived (
200- referenceTime = System .currentTimeMillis(),
201- parameters = parameters,
202- flags = Flags ()
203- )
204- dataProvider.retrieveData {
205- result = getStrikesGrid(parameters, null , Flags ())
206- }
207- Log .v(Main .LOG_TAG , " Widget.getUpdatedViews() check running in ${Thread .currentThread().name} " )
208- Log .v(Main .LOG_TAG , " WidgetProvider.getUpdatedViews() received ${result.parameters} , ${result.gridParameters} strikes" )
209- val strikes = Strikes (result.strikes!! , result.gridParameters)
210- alertDataHandler.checkStrikes(strikes, location, alertHandler.alertParameters, result.referenceTime)
211- }.await()
212- }
213- }
214-
215- Log .v(Main .LOG_TAG , " Widget.getUpdatedViews() result in ${Thread .currentThread().name} $result " )
216- alarmView.alertEventConsumer.invoke(result)
217-
218- // Measure and layout the view with available dimensions
219- val widthSpec = android.view.View .MeasureSpec .makeMeasureSpec(availableWidth, android.view.View .MeasureSpec .EXACTLY )
220- val heightSpec = android.view.View .MeasureSpec .makeMeasureSpec(availableHeight, android.view.View .MeasureSpec .EXACTLY )
221- alarmView.measure(widthSpec, heightSpec)
222- alarmView.layout(0 , 0 , alarmView.measuredWidth, alarmView.measuredHeight)
223-
224- // Create bitmap and draw the view
225- val bitmap = android.graphics.Bitmap .createBitmap(
226- alarmView.measuredWidth,
227- alarmView.measuredHeight,
228- android.graphics.Bitmap .Config .ARGB_8888
229- )
230- val canvas = android.graphics.Canvas (bitmap)
231- alarmView.draw(canvas)
232-
233- Log .v(Main .LOG_TAG , " Bitmap created: ${bitmap.width} px x ${bitmap.height} px" )
234-
235- val views = RemoteViews (context.packageName, R .layout.widget)
236- views.setImageViewBitmap(R .id.alarm_diagram, bitmap)
237-
238- val format = df.format(Date ())
239- Log .v(Main .LOG_TAG , " WidgetProvider.getUpdatedViews() $format " )
240- views.setTextViewText(R .id.widget_update_time, format)
241- return views
242- }
243-
244-
245108}
0 commit comments