Sync: fix crash on gplay flavor and reschedule when no network instead of showing a potential notification all the time

This commit is contained in:
ganfra 2019-12-11 16:24:30 +01:00
parent 5338f93852
commit 3a269be2ef
4 changed files with 48 additions and 18 deletions

View File

@ -62,6 +62,9 @@ internal class NetworkConnectivityChecker @Inject constructor(private val contex
override fun onMoveToForeground() { override fun onMoveToForeground() {
merlin.bind() merlin.bind()
merlinsBeard.hasInternetAccess {
hasInternetAccess = it
}
merlin.registerDisconnectable { merlin.registerDisconnectable {
if (hasInternetAccess) { if (hasInternetAccess) {
Timber.v("On Disconnect") Timber.v("On Disconnect")

View File

@ -34,8 +34,9 @@ import java.util.concurrent.atomic.AtomicBoolean
* in order to be able to perform a sync even if the app is not running. * in order to be able to perform a sync even if the app is not running.
* The <receiver> and <service> must be declared in the Manifest or the app using the SDK * The <receiver> and <service> must be declared in the Manifest or the app using the SDK
*/ */
open class SyncService : Service() { abstract class SyncService : Service() {
private var userId: String? = null
private var mIsSelfDestroyed: Boolean = false private var mIsSelfDestroyed: Boolean = false
private lateinit var syncTask: SyncTask private lateinit var syncTask: SyncTask
@ -50,9 +51,10 @@ open class SyncService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Timber.i("onStartCommand $intent") Timber.i("onStartCommand $intent")
intent?.let { intent?.let {
val userId = it.getStringExtra(EXTRA_USER_ID) val safeUserId = it.getStringExtra(EXTRA_USER_ID) ?: return@let
val sessionComponent = Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(userId) val sessionComponent = Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(safeUserId)
?: return@let ?: return@let
userId = safeUserId
syncTask = sessionComponent.syncTask() syncTask = sessionComponent.syncTask()
networkConnectivityChecker = sessionComponent.networkConnectivityChecker() networkConnectivityChecker = sessionComponent.networkConnectivityChecker()
taskExecutor = sessionComponent.taskExecutor() taskExecutor = sessionComponent.taskExecutor()
@ -87,9 +89,11 @@ open class SyncService : Service() {
private suspend fun doSync() { private suspend fun doSync() {
if (!networkConnectivityChecker.hasInternetAccess()) { if (!networkConnectivityChecker.hasInternetAccess()) {
Timber.v("No network, try to sync again in 10s") Timber.v("No network reschedule to avoid wasting resources")
delay(DELAY_NO_NETWORK) userId?.also {
doSync() onRescheduleAsked(it, delay = 10_000L)
}
stopMe()
return return
} }
Timber.v("Execute sync request with timeout 0") Timber.v("Execute sync request with timeout 0")
@ -109,6 +113,8 @@ open class SyncService : Service() {
} }
} }
abstract fun onRescheduleAsked(userId: String, delay: Long)
override fun onBind(intent: Intent?): IBinder? { override fun onBind(intent: Intent?): IBinder? {
return null return null
} }
@ -116,7 +122,6 @@ open class SyncService : Service() {
companion object { companion object {
const val EXTRA_USER_ID = "EXTRA_USER_ID" const val EXTRA_USER_ID = "EXTRA_USER_ID"
private const val TIME_OUT = 0L private const val TIME_OUT = 0L
private const val DELAY_NO_NETWORK = 10_000L
private const val DELAY_FAILURE = 5_000L private const val DELAY_FAILURE = 5_000L
} }
} }

View File

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="im.vector.riotx"> package="im.vector.riotx">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application> <application>
<!-- Firebase components --> <!-- Firebase components -->

View File

@ -15,11 +15,12 @@
*/ */
package im.vector.riotx.core.services package im.vector.riotx.core.services
import android.app.AlarmManager
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import androidx.core.content.ContextCompat
import im.vector.matrix.android.internal.session.sync.job.SyncService import im.vector.matrix.android.internal.session.sync.job.SyncService
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.extensions.vectorComponent import im.vector.riotx.core.extensions.vectorComponent
@ -44,16 +45,6 @@ class VectorSyncService : SyncService() {
notificationUtils = vectorComponent().notificationUtils() notificationUtils = vectorComponent().notificationUtils()
} }
override fun onDestroy() {
removeForegroundNotif()
super.onDestroy()
}
private fun removeForegroundNotif() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE)
}
/** /**
* Service is started in fdroid mode when no FCM is available or is used for initialSync * Service is started in fdroid mode when no FCM is available or is used for initialSync
*/ */
@ -65,4 +56,33 @@ class VectorSyncService : SyncService() {
} }
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
} }
override fun onDestroy() {
removeForegroundNotif()
super.onDestroy()
}
override fun onRescheduleAsked(userId: String, delay: Long) {
reschedule(userId, delay)
}
private fun removeForegroundNotif() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE)
}
private fun reschedule(userId: String, delay: Long) {
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PendingIntent.getForegroundService(this, 0, newIntent(this, userId), 0)
} else {
PendingIntent.getService(this, 0, newIntent(this, userId), 0)
}
val firstMillis = System.currentTimeMillis() + delay
val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent)
} else {
alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent)
}
}
} }