From beab5248de6b20e48393628475cb30701b1ebf08 Mon Sep 17 00:00:00 2001 From: Michael Kourlas Date: Sun, 28 Feb 2021 06:00:12 -0500 Subject: [PATCH] Fixes to sync scheduling --- CHANGES.md | 4 + .../metadata/android/en-US/changelogs/138.txt | 2 + voipms-sms/build.gradle | 4 +- voipms-sms/src/main/AndroidManifest.xml | 1 - .../kourlas/voipms_sms/CustomApplication.kt | 16 +++- .../conversations/ConversationsActivity.kt | 8 +- .../SynchronizationPreferencesFragment.kt | 9 +- .../voipms_sms/preferences/preferences.kt | 17 +--- .../sms/receivers/SyncBootReceiver.kt | 4 +- .../sms/receivers/SyncIntervalReceiver.kt | 92 ------------------- .../voipms_sms/sms/workers/SyncWorker.kt | 66 ++++++++----- voipms-sms/src/main/res/values/arrays.xml | 4 - voipms-sms/src/main/res/values/strings.xml | 2 +- .../services/FcmListenerService.kt | 3 +- 14 files changed, 84 insertions(+), 148 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/138.txt delete mode 100644 voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncIntervalReceiver.kt diff --git a/CHANGES.md b/CHANGES.md index a3301297..f6ff2158 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +## 0.6.18 ## + +* Bug fixes + ## 0.6.17 ## * Bug fixes diff --git a/fastlane/metadata/android/en-US/changelogs/138.txt b/fastlane/metadata/android/en-US/changelogs/138.txt new file mode 100644 index 00000000..f82d5cff --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/138.txt @@ -0,0 +1,2 @@ +0.6.18 +• Bug fixes \ No newline at end of file diff --git a/voipms-sms/build.gradle b/voipms-sms/build.gradle index a610d0d7..a0f84838 100644 --- a/voipms-sms/build.gradle +++ b/voipms-sms/build.gradle @@ -9,8 +9,8 @@ android { applicationId 'net.kourlas.voipms_sms' minSdkVersion 21 targetSdkVersion 30 - versionCode 137 - versionName '0.6.17' + versionCode 138 + versionName '0.6.18' } flavorDimensions 'version', 'demo' productFlavors { diff --git a/voipms-sms/src/main/AndroidManifest.xml b/voipms-sms/src/main/AndroidManifest.xml index 52c6e23a..0c75f019 100644 --- a/voipms-sms/src/main/AndroidManifest.xml +++ b/voipms-sms/src/main/AndroidManifest.xml @@ -224,7 +224,6 @@ - diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/CustomApplication.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/CustomApplication.kt index c4505c8f..9ed2c69d 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/CustomApplication.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/CustomApplication.kt @@ -1,6 +1,6 @@ /* * VoIP.ms SMS - * Copyright (C) 2017-2020 Michael Kourlas + * Copyright (C) 2017-2021 Michael Kourlas * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package net.kourlas.voipms_sms import android.app.Application @@ -23,8 +24,11 @@ import androidx.appcompat.app.AppCompatDelegate import net.kourlas.voipms_sms.network.NetworkManager.Companion.getInstance import net.kourlas.voipms_sms.preferences.fragments.AppearancePreferencesFragment import net.kourlas.voipms_sms.preferences.getAppTheme +import net.kourlas.voipms_sms.preferences.getSyncInterval +import net.kourlas.voipms_sms.preferences.setRawSyncInterval import net.kourlas.voipms_sms.sms.ConversationId import net.kourlas.voipms_sms.sms.Database +import net.kourlas.voipms_sms.sms.workers.SyncWorker import net.kourlas.voipms_sms.utils.subscribeToDidTopics import java.util.* @@ -73,6 +77,12 @@ class CustomApplication : Application() { // Create static reference to self. self = this + // Limit synchronization interval to 15 minutes. Previous versions + // supported a shorter interval. + if (getSyncInterval(applicationContext) < (15.0 / (24 * 60)) ) { + setRawSyncInterval(applicationContext, "0.01041666666") + } + // Update theme when (getAppTheme(applicationContext)) { AppearancePreferencesFragment.SYSTEM_DEFAULT -> AppCompatDelegate.setDefaultNightMode( @@ -96,6 +106,10 @@ class CustomApplication : Application() { // Subscribe to topics for current DIDs subscribeToDidTopics(applicationContext) + + // Schedule a database synchronization, if required. + SyncWorker.performFullSynchronization(applicationContext, + scheduleOnly = true) } companion object { diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/conversations/ConversationsActivity.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/conversations/ConversationsActivity.kt index 6fb672e4..cb616baf 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/conversations/ConversationsActivity.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/conversations/ConversationsActivity.kt @@ -239,7 +239,7 @@ open class ConversationsActivity(val archived: Boolean = false) : R.id.swipe_refresh_layout) swipeRefreshLayout.setOnRefreshListener { adapter.refresh() - SyncWorker.performSynchronization(this, forceRecent = false) + SyncWorker.performFullSynchronization(applicationContext) } swipeRefreshLayout.setColorSchemeResources(R.color.swipe_refresh_icon) } @@ -329,10 +329,10 @@ open class ConversationsActivity(val archived: Boolean = false) : performAccountDidCheck() val firstSyncRequired = performInitialSetup() - // Refresh and perform limited synchronization\ + // Refresh and perform limited synchronization if (!firstSyncRequired) { adapter.refresh() - SyncWorker.performSynchronization(this, forceRecent = true) + SyncWorker.performPartialSynchronization(applicationContext) } // Refresh on resume just in case the contacts permission was newly @@ -399,7 +399,7 @@ open class ConversationsActivity(val archived: Boolean = false) : val swipeRefreshLayout = findViewById( R.id.swipe_refresh_layout) swipeRefreshLayout.isRefreshing = true - SyncWorker.performSynchronization(this, forceRecent = false) + SyncWorker.performFullSynchronization(applicationContext) val emptyTextView = findViewById( R.id.empty_text) diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/fragments/SynchronizationPreferencesFragment.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/fragments/SynchronizationPreferencesFragment.kt index d1dbc2e1..ef21965e 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/fragments/SynchronizationPreferencesFragment.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/fragments/SynchronizationPreferencesFragment.kt @@ -23,16 +23,19 @@ import androidx.preference.ListPreference import androidx.preference.Preference import com.takisoft.preferencex.PreferenceFragmentCompat import net.kourlas.voipms_sms.R -import net.kourlas.voipms_sms.sms.receivers.SyncIntervalReceiver +import net.kourlas.voipms_sms.sms.workers.SyncWorker import net.kourlas.voipms_sms.utils.preferences class SynchronizationPreferencesFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { // Preference change handlers private val syncIntervalPreferenceChangeListener = - Preference.OnPreferenceChangeListener { _, _ -> + Preference.OnPreferenceChangeListener { _, newValue -> activity?.let { - SyncIntervalReceiver.setInterval(it) + SyncWorker.performFullSynchronization( + it, + customPeriod = (newValue as String).toDouble(), + scheduleOnly = true) } true } diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/preferences.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/preferences.kt index 595a7133..892d839c 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/preferences.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/preferences/preferences.kt @@ -111,12 +111,6 @@ fun getFirstSyncAfterSignIn(context: Context): Boolean = context.getString(R.string.preferences_first_sync_after_sign_in_key), false) -fun getLastCompleteSyncTime(context: Context): Long = - getLongPreference(context, - context.getString( - R.string.preferences_sync_last_complete_time_key), - 0) - fun getMessageTextBoxMaximumSize(context: Context): Int = getStringPreference( context, @@ -354,12 +348,6 @@ fun setFirstSyncAfterSignIn(context: Context, firstSyncAfterSignIn: Boolean) { firstSyncAfterSignIn) } -fun setLastCompleteSyncTime(context: Context, - lastCompleteSyncTime: Long) = - setLongPreference( - context, context.getString( - R.string.preferences_sync_last_complete_time_key), lastCompleteSyncTime) - fun setSetupCompletedForVersion(context: Context, version: Long) { if (getLongPreference(context, context.getString( @@ -385,6 +373,11 @@ fun setStartDate(context: Context, date: Date) { SimpleDateFormat("MM/dd/yyyy", Locale.US).format(date)) } +fun setRawSyncInterval(context: Context, string: String) { + setStringPreference(context, context.getString( + R.string.preferences_sync_interval_key), string) +} + @Suppress("SameParameterValue") private fun getSecureStringPreference(context: Context, key: String, default: String?): String? { diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncBootReceiver.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncBootReceiver.kt index dbf72cea..b900a5b7 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncBootReceiver.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncBootReceiver.kt @@ -20,6 +20,8 @@ package net.kourlas.voipms_sms.sms.receivers import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import net.kourlas.voipms_sms.preferences.getSyncInterval +import net.kourlas.voipms_sms.sms.workers.SyncWorker import net.kourlas.voipms_sms.utils.logException /** @@ -36,7 +38,7 @@ class SyncBootReceiver : BroadcastReceiver() { && intent.action != "android.intent.action.ACTION_LOCKED_BOOT_COMPLETED") { throw Exception("Unrecognized action " + intent.action) } - SyncIntervalReceiver.setInterval(context) + SyncWorker.performFullSynchronization(context, scheduleOnly = true) } catch (e: Exception) { logException(e) } diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncIntervalReceiver.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncIntervalReceiver.kt deleted file mode 100644 index 72174567..00000000 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/receivers/SyncIntervalReceiver.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * VoIP.ms SMS - * Copyright (C) 2017-2021 Michael Kourlas - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.kourlas.voipms_sms.sms.receivers - -import android.app.AlarmManager -import android.app.PendingIntent -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import androidx.core.app.AlarmManagerCompat -import net.kourlas.voipms_sms.R -import net.kourlas.voipms_sms.preferences.getLastCompleteSyncTime -import net.kourlas.voipms_sms.preferences.getSyncInterval -import net.kourlas.voipms_sms.sms.workers.SyncWorker -import net.kourlas.voipms_sms.utils.logException - -/** - * Receiver called when a database synchronization is requested, either - * automatically or triggered by a particular action. - */ -class SyncIntervalReceiver : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - try { - if (context == null || intent == null) { - throw Exception("No context or intent provided") - } - if (intent.action != context.getString( - R.string.sync_interval_action)) { - throw Exception("Unrecognized action " + intent.action) - } - SyncWorker.performSynchronization(context) - } catch (e: Exception) { - logException(e) - } - } - - companion object { - /** - * Set up an alarm to trigger database synchronization. - */ - fun setInterval(context: Context) { - val alarmManager = context.getSystemService( - Context.ALARM_SERVICE) as AlarmManager - val pendingIntent = PendingIntent.getBroadcast( - context, SyncIntervalReceiver::class.java.hashCode(), - getIntent(context), - 0) - alarmManager.cancel(pendingIntent) - - val syncInterval = (getSyncInterval(context) - * (24 * 60 * 60 * 1000)).toLong() - // Only setup interval if periodic synchronization is enabled - if (syncInterval != 0L) { - val nextSyncTime = getLastCompleteSyncTime(context) + - syncInterval - - val now = System.currentTimeMillis() - if (nextSyncTime <= now) { - pendingIntent.send() - } else { - AlarmManagerCompat.setAndAllowWhileIdle( - alarmManager, AlarmManager.RTC_WAKEUP, nextSyncTime, - pendingIntent) - } - } - } - - /** - * Gets an intent which can be used to trigger this receiver. - */ - private fun getIntent(context: Context): Intent { - val intent = Intent(context, SyncIntervalReceiver::class.java) - intent.action = context.getString(R.string.sync_interval_action) - return intent - } - } -} diff --git a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/workers/SyncWorker.kt b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/workers/SyncWorker.kt index a79e4eff..44eacdd2 100644 --- a/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/workers/SyncWorker.kt +++ b/voipms-sms/src/main/kotlin/net/kourlas/voipms_sms/sms/workers/SyncWorker.kt @@ -34,7 +34,6 @@ import net.kourlas.voipms_sms.notifications.Notifications import net.kourlas.voipms_sms.preferences.* import net.kourlas.voipms_sms.sms.ConversationId import net.kourlas.voipms_sms.sms.Database -import net.kourlas.voipms_sms.sms.receivers.SyncIntervalReceiver import net.kourlas.voipms_sms.utils.httpPostWithMultipartFormData import net.kourlas.voipms_sms.utils.logException import net.kourlas.voipms_sms.utils.toBoolean @@ -43,6 +42,7 @@ import java.io.IOException import java.net.URLEncoder import java.text.SimpleDateFormat import java.util.* +import java.util.concurrent.TimeUnit import kotlin.math.ceil /** @@ -134,14 +134,6 @@ class SyncWorker(context: Context, params: WorkerParameters) : val retrievalRequests = createRetrievalRequests( retrieveOnlyRecentMessages) processRequests(retrievalRequests, retrieveDeletedMessages) - - // If this was not an intentionally limited database - // synchronization, set a new alarm for the next sync - if (!forceRecent) { - setLastCompleteSyncTime(applicationContext, - System.currentTimeMillis()) - SyncIntervalReceiver.setInterval(applicationContext) - } } catch (e: CancellationException) { // We need to propagate the exception from processRequests throw e @@ -414,25 +406,49 @@ class SyncWorker(context: Context, params: WorkerParameters) : /** * Synchronize the database with VoIP.ms. * - * @param forceRecent If true, retrieves only the most recent messages - * regardless of the app configuration. + * @param customPeriod A custom period for synchronization, in + * fractions of a day. If not provided, the system configuration will + * be used. + * @param scheduleOnly Do not perform synchronization immediately. */ - fun performSynchronization(context: Context, - forceRecent: Boolean = false) { - val work = OneTimeWorkRequestBuilder() - .setInputData( - workDataOf( - context.getString( - R.string.sync_force_recent) to forceRecent)) - .build() - WorkManager.getInstance(context) - .enqueueUniqueWork( + fun performFullSynchronization(context: Context, + customPeriod: Double? = null, + scheduleOnly: Boolean = false) { + val delayInterval = ( + (customPeriod ?: getSyncInterval(context)) + * (24 * 60 * 60 * 1000)).toLong() + if (delayInterval != 0L) { + val workRequest = PeriodicWorkRequestBuilder( + delayInterval, + TimeUnit.MILLISECONDS) + if (scheduleOnly) { + workRequest.setInitialDelay(delayInterval, + TimeUnit.MILLISECONDS) + } + val work = workRequest.build() + WorkManager.getInstance(context).enqueueUniquePeriodicWork( context.getString(R.string.sync_work_id), - if (forceRecent) - ExistingWorkPolicy.KEEP - else - ExistingWorkPolicy.REPLACE, + ExistingPeriodicWorkPolicy.REPLACE, work) + } else { + val work = OneTimeWorkRequestBuilder().build() + WorkManager.getInstance(context) + .enqueueUniqueWork(context.getString(R.string.sync_work_id), + ExistingWorkPolicy.REPLACE, work) + } + } + + /** + * Check VoIP.ms for new messages. + */ + fun performPartialSynchronization(context: Context) { + val work = OneTimeWorkRequestBuilder().setInputData( + workDataOf( + context.getString(R.string.sync_force_recent) to true)) + .build() + WorkManager.getInstance(context).enqueueUniqueWork( + context.getString(R.string.sync_partial_work_id), + ExistingWorkPolicy.KEEP, work) } } } diff --git a/voipms-sms/src/main/res/values/arrays.xml b/voipms-sms/src/main/res/values/arrays.xml index 94a892d4..56a534b4 100644 --- a/voipms-sms/src/main/res/values/arrays.xml +++ b/voipms-sms/src/main/res/values/arrays.xml @@ -17,8 +17,6 @@ - Every minute - Every 5 minutes Every 15 minutes Every 30 minutes Every hour @@ -30,8 +28,6 @@ Never - 0.00069444444 - 0.00347222222 0.01041666666 0.02083333333 0.04166666666 diff --git a/voipms-sms/src/main/res/values/strings.xml b/voipms-sms/src/main/res/values/strings.xml index 98d28495..29fed4de 100644 --- a/voipms-sms/src/main/res/values/strings.xml +++ b/voipms-sms/src/main/res/values/strings.xml @@ -122,7 +122,6 @@ No handler available to select database import location - sync_last_complete_time External storage permission required to access ringtones setup_completed_for_version 0 @@ -279,6 +278,7 @@ net.kourlas.voipms_sms.SYNC_WORK_ID + net.kourlas.voipms_sms.SYNC_PARTIAL_WORK_ID net.kourlas.voipms_sms.SYNC_FORCE_RECENT Sync failed: network unavailable Sync failed: VoIP.ms unavailable diff --git a/voipms-sms/src/primary/kotlin/net/kourlas/voipms_sms/notifications/services/FcmListenerService.kt b/voipms-sms/src/primary/kotlin/net/kourlas/voipms_sms/notifications/services/FcmListenerService.kt index 50e34c74..90e71c39 100644 --- a/voipms-sms/src/primary/kotlin/net/kourlas/voipms_sms/notifications/services/FcmListenerService.kt +++ b/voipms-sms/src/primary/kotlin/net/kourlas/voipms_sms/notifications/services/FcmListenerService.kt @@ -43,8 +43,7 @@ class FcmListenerService : FirebaseMessagingService() { // database and shows notifications for any new messages if (Notifications.getInstance( application).getNotificationsEnabled()) { - SyncWorker.performSynchronization(applicationContext, - forceRecent = true) + SyncWorker.performPartialSynchronization(applicationContext) } } else { // Otherwise, unsubscribe from this topic