diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 292c24b..b6284b3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -108,10 +108,6 @@
-
-
-
-
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/CalendarHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/CalendarHelper.kt
index 01bf676..62a6c5f 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/CalendarHelper.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/CalendarHelper.kt
@@ -4,7 +4,6 @@ import android.Manifest
import android.content.Context
import android.content.Intent
import android.provider.CalendarContract
-import com.tommasoberlose.anotherwidget.services.EventListenerJob
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.services.UpdateCalendarWorker
@@ -50,11 +49,11 @@ object CalendarHelper {
}
fun setEventUpdatesAndroidN(context: Context) {
- EventListenerJob.schedule(context)
+ UpdateCalendarWorker.enqueueTrigger(context)
}
fun removeEventUpdatesAndroidN(context: Context) {
- EventListenerJob.remove(context)
+ UpdateCalendarWorker.cancelTrigger(context)
}
fun List.applyFilters() : List {
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt
index cf2152e..d37172e 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt
@@ -324,7 +324,9 @@ object WeatherHelper {
}
}
- fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when (iconString.substringBefore('?').substringAfterLast('/')) {
+ fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when (
+ iconString.substringBefore('?').substringAfterLast('/').substringBefore(',')
+ ) {
"skc" -> "01"
"few" -> "02"
"sct" -> "02"
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt
index 0092180..49c1c7a 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt
@@ -42,12 +42,12 @@ class WeatherReceiver : BroadcastReceiver() {
5 -> 60L * 24
else -> 60
}
- WeatherWorker.enqueue(context, interval, TimeUnit.MINUTES)
+ WeatherWorker.enqueuePeriodic(context, interval, TimeUnit.MINUTES)
}
}
fun removeUpdates(context: Context) {
- WeatherWorker.cancel(context)
+ WeatherWorker.cancelPeriodic(context)
}
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/BatteryListenerJob.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/BatteryListenerJob.kt
deleted file mode 100644
index 19e6e0e..0000000
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/BatteryListenerJob.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.tommasoberlose.anotherwidget.services
-
-import android.app.job.JobInfo
-import android.app.job.JobParameters
-import android.app.job.JobScheduler
-import android.app.job.JobService
-import android.content.ComponentName
-import android.content.Context
-import android.os.Build
-import android.provider.CalendarContract
-import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
-import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
-
-class BatteryListenerJob : JobService() {
- override fun onStartJob(params: JobParameters): Boolean {
- MainWidget.updateWidget(this)
- schedule(
- this
- )
- return false
- }
-
- @Synchronized
- override fun onStopJob(params: JobParameters): Boolean {
- return false
- }
-
- companion object {
- private const val chargingJobId = 1006
- private const val notChargingJobId = 1007
- fun schedule(context: Context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- remove(context)
- val componentName = ComponentName(
- context,
- EventListenerJob::class.java
- )
- with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
- schedule(
- JobInfo.Builder(chargingJobId, componentName)
- .setRequiresCharging(true)
- .setPersisted(true)
- .build()
- )
- schedule(
- JobInfo.Builder(notChargingJobId, componentName)
- .setRequiresCharging(false)
- .setPersisted(true)
- .build()
- )
- }
- }
- }
-
- private fun remove(context: Context) {
- val js = context.getSystemService(JobScheduler::class.java)
- js?.cancel(chargingJobId)
- js?.cancel(notChargingJobId)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/EventListenerJob.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/EventListenerJob.kt
deleted file mode 100644
index a8a811b..0000000
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/EventListenerJob.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.tommasoberlose.anotherwidget.services
-
-import android.app.job.JobInfo
-import android.app.job.JobInfo.TriggerContentUri
-import android.app.job.JobParameters
-import android.app.job.JobScheduler
-import android.app.job.JobService
-import android.content.ComponentName
-import android.content.Context
-import android.os.Build
-import android.provider.CalendarContract
-import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
-
-
-class EventListenerJob : JobService() {
- override fun onStartJob(params: JobParameters): Boolean {
- CalendarHelper.updateEventList(this)
- schedule(
- this
- )
- return false
- }
-
- @Synchronized
- override fun onStopJob(params: JobParameters): Boolean {
- return false
- }
-
- companion object {
- private const val jobId = 1005
- fun schedule(context: Context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- val componentName = ComponentName(
- context,
- EventListenerJob::class.java
- )
- with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
- schedule(
- JobInfo.Builder(jobId, componentName)
- .addTriggerContentUri(TriggerContentUri(
- CalendarContract.CONTENT_URI,
- TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
- ))
- .build()
- )
- }
- }
- }
-
- fun remove(context: Context) {
- val js = context.getSystemService(JobScheduler::class.java)
- js?.cancel(jobId)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/UpdateCalendarWorker.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/UpdateCalendarWorker.kt
index 6f610a9..a8a3ac4 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/UpdateCalendarWorker.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/services/UpdateCalendarWorker.kt
@@ -2,6 +2,9 @@ package com.tommasoberlose.anotherwidget.services
import android.Manifest
import android.content.Context
+import android.os.Build
+import android.provider.CalendarContract
+import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
@@ -17,12 +20,12 @@ import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
import me.everything.providers.android.calendar.CalendarProvider
import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.collections.ArrayList
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
class UpdateCalendarWorker(private val context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
@@ -36,7 +39,6 @@ class UpdateCalendarWorker(private val context: Context, params: WorkerParameter
if (!context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
eventRepository.resetNextEventData()
eventRepository.clearEvents()
- Preferences.showEvents = false
} else {
// fetch all events from now to next ACTION_CALENDAR_UPDATE + limit
val now = Calendar.getInstance()
@@ -139,6 +141,7 @@ class UpdateCalendarWorker(private val context: Context, params: WorkerParameter
} catch (ignored: java.lang.Exception) {
}
}
+ enqueueTrigger(context)
} else {
eventRepository.resetNextEventData()
eventRepository.clearEvents()
@@ -156,11 +159,34 @@ class UpdateCalendarWorker(private val context: Context, params: WorkerParameter
companion object {
fun enqueue(context: Context) {
- WorkManager.getInstance(context.applicationContext).enqueueUniqueWork(
- "UpdateCalendarWorker",
- ExistingWorkPolicy.REPLACE,
+ WorkManager.getInstance(context).enqueueUniqueWork(
+ "updateEventList",
+ ExistingWorkPolicy.KEEP,
OneTimeWorkRequestBuilder().build()
)
}
+
+ fun enqueueTrigger(context: Context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ WorkManager.getInstance(context).enqueueUniqueWork(
+ "updateEventListByTrigger",
+ ExistingWorkPolicy.KEEP,
+ OneTimeWorkRequestBuilder().setConstraints(
+ Constraints.Builder().addContentUriTrigger(
+ CalendarContract.CONTENT_URI,
+ true
+ ).build()
+ ).build()
+ )
+ }
+ }
+
+ fun cancelTrigger(context: Context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ WorkManager.getInstance(context).cancelUniqueWork(
+ "updateEventListByTrigger"
+ )
+ }
+ }
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/services/WeatherWorker.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/services/WeatherWorker.kt
index edf3c43..3f3edbb 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/services/WeatherWorker.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/services/WeatherWorker.kt
@@ -14,19 +14,18 @@ import androidx.work.WorkerParameters
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.location.LocationServices
-import com.google.android.gms.tasks.Tasks
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.TimeUnit
+import kotlin.coroutines.resume
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
class WeatherWorker(private val context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
@@ -42,7 +41,11 @@ class WeatherWorker(private val context: Context, params: WorkerParameters) :
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
== ConnectionResult.SUCCESS
) {
- LocationServices.getFusedLocationProviderClient(context).lastLocation
+ suspendCancellableCoroutine { continuation ->
+ LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnCompleteListener {
+ continuation.resume(if (it.isSuccessful) it.result else null)
+ }
+ }
} else {
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
var location: Location? = null
@@ -54,21 +57,15 @@ class WeatherWorker(private val context: Context, params: WorkerParameters) :
location = it
}
}
- Tasks.forResult(location)
- }.addOnCompleteListener { task ->
- val networkApi = WeatherNetworkApi(context)
- if (task.isSuccessful) {
- val location = task.result
- if (location != null) {
- Preferences.customLocationLat = location.latitude.toString()
- Preferences.customLocationLon = location.longitude.toString()
- }
+ location
+ }.let { location ->
+ if (location != null) {
+ Preferences.customLocationLat = location.latitude.toString()
+ Preferences.customLocationLon = location.longitude.toString()
}
-
- CoroutineScope(Dispatchers.IO).launch {
- networkApi.updateWeather()
+ withContext(Dispatchers.IO) {
+ WeatherNetworkApi(context).updateWeather()
}
- EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
}
else -> {
@@ -83,24 +80,24 @@ class WeatherWorker(private val context: Context, params: WorkerParameters) :
companion object {
fun enqueue(context: Context) {
- WorkManager.getInstance(context.applicationContext).enqueueUniqueWork(
- "OneTimeWeatherWorker",
+ WorkManager.getInstance(context).enqueueUniqueWork(
+ "updateWeather",
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequestBuilder().build()
)
}
- fun enqueue(context: Context, interval: Long, unit: TimeUnit) {
- WorkManager.getInstance(context.applicationContext).enqueueUniquePeriodicWork(
- "WeatherWorker",
+ fun enqueuePeriodic(context: Context, interval: Long, unit: TimeUnit) {
+ WorkManager.getInstance(context).enqueueUniquePeriodicWork(
+ "updateWeatherPeriodically",
ExistingPeriodicWorkPolicy.REPLACE,
PeriodicWorkRequestBuilder(interval, unit).build()
)
}
- fun cancel(context: Context) {
- WorkManager.getInstance(context.applicationContext).cancelUniqueWork(
- "WeatherWorker"
+ fun cancelPeriodic(context: Context) {
+ WorkManager.getInstance(context).cancelUniqueWork(
+ "updateWeatherPeriodically"
)
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/MainActivity.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/MainActivity.kt
index 4e01a0d..5bb464a 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/MainActivity.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/MainActivity.kt
@@ -141,7 +141,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
if (Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
Preferences.showEvents = false
- com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver.removeUpdates(this)
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/PreferencesFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/PreferencesFragment.kt
index c531a40..6295a55 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/PreferencesFragment.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/PreferencesFragment.kt
@@ -88,6 +88,7 @@ class PreferencesFragment : Fragment() {
CalendarHelper.setEventUpdatesAndroidN(requireContext())
} else {
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
+ UpdatesReceiver.removeUpdates(requireContext())
}
}
}
@@ -124,7 +125,6 @@ class PreferencesFragment : Fragment() {
requireCalendarPermission()
} else {
Preferences.showEvents = enabled
- UpdatesReceiver.removeUpdates(requireContext())
}
}
@@ -165,6 +165,7 @@ class PreferencesFragment : Fragment() {
.withPermissions(
Manifest.permission.READ_CALENDAR
).withListener(object: MultiplePermissionsListener {
+ private var shouldShowRationale = false
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
val granted = report.areAllPermissionsGranted()
@@ -172,12 +173,33 @@ class PreferencesFragment : Fragment() {
if (granted) {
CalendarHelper.updateEventList(requireContext())
}
+ else if (!shouldShowRationale && report.isAnyPermissionPermanentlyDenied) {
+ MaterialBottomSheetDialog(
+ requireContext(),
+ getString(R.string.title_permission_calendar),
+ getString(R.string.description_permission_calendar)
+ ).setNegativeButton(getString(R.string.action_ignore))
+ .setPositiveButton(getString(R.string.action_grant_permission)) {
+ startActivity(
+ android.content.Intent(
+ android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ ).apply {
+ data = android.net.Uri.fromParts(
+ "package",
+ requireContext().packageName,
+ null
+ )
+ }
+ )
+ }.show()
+ }
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList?,
token: PermissionToken?
) {
+ shouldShowRationale = true
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt
index e93e1c0..d80ad89 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/WeatherFragment.kt
@@ -221,18 +221,40 @@ class WeatherFragment : Fragment() {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
).withListener(object: MultiplePermissionsListener {
+ private var shouldShowRationale = false
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.grantedPermissionResponses.isNotEmpty()) {
checkLocationPermission()
WeatherHelper.updateWeather(requireContext())
}
+ else if (!shouldShowRationale && report.isAnyPermissionPermanentlyDenied) {
+ MaterialBottomSheetDialog(
+ requireContext(),
+ getString(R.string.title_permission_location),
+ getString(R.string.description_permission_location)
+ ).setNegativeButton(getString(R.string.action_ignore))
+ .setPositiveButton(getString(R.string.action_grant_permission)) {
+ startActivity(
+ Intent(
+ android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ ).apply {
+ data = android.net.Uri.fromParts(
+ "package",
+ requireContext().packageName,
+ null
+ )
+ }
+ )
+ }.show()
+ }
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList?,
token: PermissionToken?
) {
+ shouldShowRationale = true
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
@@ -241,6 +263,12 @@ class WeatherFragment : Fragment() {
.check()
}
+ override fun onResume() {
+ super.onResume()
+ checkWeatherProviderConfig()
+ checkLocationPermission()
+ }
+
private fun maintainScrollPosition(callback: () -> Unit) {
binding.scrollView.isScrollable = false
callback.invoke()
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
index 52be37d..872fa15 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
@@ -155,6 +155,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::secondRowInformation)) { value = true }
addSource(Preferences.asLiveData(Preferences::showWeather)) { value = true }
+ addSource(Preferences.asLiveData(Preferences::weatherProvider)) { value = true }
addSource(Preferences.asLiveData(Preferences::weatherTempUnit)) { value = true }
addSource(Preferences.asLiveData(Preferences::weatherIconPack)) { value = true }
addSource(Preferences.asLiveData(Preferences::customLocationLat)) { value = true }
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
index 484fd54..cd70e38 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
@@ -34,25 +34,26 @@ class MainWidget : AppWidgetProvider() {
CalendarHelper.updateEventList(context)
WeatherReceiver.setUpdates(context)
MediaPlayerHelper.updatePlayingMediaInfo(context)
-
- if (Preferences.showEvents) {
- CalendarHelper.setEventUpdatesAndroidN(context)
- } else {
- CalendarHelper.removeEventUpdatesAndroidN(context)
- }
}
override fun onDisabled(context: Context) {
if (getWidgetCount(context) == 0) {
+ CalendarHelper.removeEventUpdatesAndroidN(context)
UpdatesReceiver.removeUpdates(context)
WeatherReceiver.removeUpdates(context)
}
}
companion object {
+ private val handler by lazy { android.os.Handler(android.os.Looper.getMainLooper()) }
fun updateWidget(context: Context) {
- context.sendBroadcast(IntentHelper.getWidgetUpdateIntent(context))
+ handler.run {
+ removeCallbacksAndMessages(null)
+ postDelayed ({
+ context.sendBroadcast(IntentHelper.getWidgetUpdateIntent(context))
+ }, 100)
+ }
}
fun getWidgetCount(context: Context): Int {