Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Push] Show notification on push notification (until sync is started) #1043

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package at.bitfire.davdroid.push

import android.accounts.Account
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.NotificationRegistry
import at.bitfire.davdroid.ui.account.AccountActivity
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject

class PushNotificationManager @Inject constructor(
@ApplicationContext private val context: Context,
private val notificationRegistry: NotificationRegistry
) {

/**
* Generates the notification ID for a push notification.
*/
private fun notificationId(account: Account, authority: String): Int {
return account.name.hashCode() + account.type.hashCode() + authority.hashCode()
}

/**
* Sends a notification to inform the user that a push notification has been received, the
* sync has been scheduled, but it still has not run.
*/
fun notify(account: Account, authority: String) {
notificationRegistry.notifyIfPossible(notificationId(account, authority)) {
NotificationCompat.Builder(context, notificationRegistry.CHANNEL_STATUS)
.setSmallIcon(R.drawable.ic_sync)
.setContentTitle(context.getString(R.string.sync_notification_pending_push_title))
.setContentText(context.getString(R.string.sync_notification_pending_push_message))
.setSubText(account.name)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setContentIntent(
PendingIntent.getActivity(
context,
0,
Intent(context, AccountActivity::class.java).apply {
putExtra(AccountActivity.EXTRA_ACCOUNT, account)
},
PendingIntent.FLAG_IMMUTABLE
ArnyminerZ marked this conversation as resolved.
Show resolved Hide resolved
)
)
.build()
}
}

/**
* Once the sync has been started, the notification is no longer needed and can be dismissed.
* It's safe to call this method even if the notification has not been shown.
*/
fun dismissScheduled(account: Account, authority: String) {
ArnyminerZ marked this conversation as resolved.
Show resolved Hide resolved
NotificationManagerCompat.from(context)
.cancel(notificationId(account, authority))
}
}
ArnyminerZ marked this conversation as resolved.
Show resolved Hide resolved
ArnyminerZ marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.repository.PreferenceRepository
import at.bitfire.davdroid.sync.worker.OneTimeSyncWorker
import dagger.hilt.android.AndroidEntryPoint
import java.util.logging.Level
import java.util.logging.Logger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.unifiedpush.android.connector.MessagingReceiver
import java.util.logging.Level
import java.util.logging.Logger
import javax.inject.Inject

@AndroidEntryPoint
class UnifiedPushReceiver: MessagingReceiver() {
Expand Down Expand Up @@ -71,14 +71,14 @@ class UnifiedPushReceiver: MessagingReceiver() {
collectionRepository.getSyncableByTopic(topic)?.let { collection ->
serviceRepository.get(collection.serviceId)?.let { service ->
val account = accountRepository.fromName(service.accountName)
OneTimeSyncWorker.enqueueAllAuthorities(context, account)
OneTimeSyncWorker.enqueueAllAuthorities(context, account, isPush = true)
}
}

} else {
logger.warning("Got push message without topic, syncing all accounts")
for (account in accountRepository.getAll())
OneTimeSyncWorker.enqueueAllAuthorities(context, account)
OneTimeSyncWorker.enqueueAllAuthorities(context, account, isPush = true)

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.work.WorkQuery
import androidx.work.WorkerParameters
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.push.PushNotificationManager
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.sync.AddressBookSyncer
import at.bitfire.davdroid.sync.CalendarSyncer
Expand All @@ -30,15 +31,15 @@ import at.bitfire.davdroid.sync.Syncer
import at.bitfire.davdroid.sync.TaskSyncer
import at.bitfire.davdroid.ui.NotificationRegistry
import at.bitfire.ical4android.TaskProvider
import java.util.Collections
import java.util.logging.Logger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.withContext
import java.util.Collections
import java.util.logging.Logger
import javax.inject.Inject

abstract class BaseSyncWorker(
context: Context,
Expand Down Expand Up @@ -137,6 +138,9 @@ abstract class BaseSyncWorker(
@Inject
lateinit var notificationRegistry: NotificationRegistry

@Inject
lateinit var pushNotificationManager: PushNotificationManager

@Inject
lateinit var syncConditionsFactory: SyncConditions.Factory

Expand All @@ -160,6 +164,9 @@ abstract class BaseSyncWorker(
return Result.success()
}

// Dismiss any pending push notification
pushNotificationManager.dismissScheduled(account, authority)

try {
val accountSettings = try {
accountSettingsFactory.create(account)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.WorkerParameters
import at.bitfire.davdroid.R
import at.bitfire.davdroid.push.PushNotificationManager
import at.bitfire.davdroid.sync.SyncDispatcher
import at.bitfire.davdroid.sync.SyncUtils
import at.bitfire.davdroid.ui.NotificationRegistry
Expand Down Expand Up @@ -80,10 +81,11 @@ class OneTimeSyncWorker @AssistedInject constructor(
account: Account,
manual: Boolean = false,
@ArgResync resync: Int = NO_RESYNC,
upload: Boolean = false
upload: Boolean = false,
isPush: Boolean = false
) {
for (authority in SyncUtils.syncAuthorities(context))
enqueue(context, account, authority, manual = manual, resync = resync, upload = upload)
enqueue(context, account, authority, manual = manual, resync = resync, upload = upload, isPush = isPush)
}

/**
Expand All @@ -95,6 +97,7 @@ class OneTimeSyncWorker @AssistedInject constructor(
* @param resync whether to request (full) re-synchronization or not
* @param upload see [ContentResolver.SYNC_EXTRAS_UPLOAD] used only for contacts sync
* and android 7 workaround
* @param isPush whether this sync is triggered by a push notification
* @return existing or newly created worker name
*/
fun enqueue(
Expand All @@ -103,7 +106,8 @@ class OneTimeSyncWorker @AssistedInject constructor(
authority: String,
manual: Boolean = false,
@ArgResync resync: Int = NO_RESYNC,
upload: Boolean = false
upload: Boolean = false,
isPush: Boolean = false
): String {
// Worker arguments
val argumentsBuilder = Data.Builder()
Expand Down Expand Up @@ -147,6 +151,13 @@ class OneTimeSyncWorker @AssistedInject constructor(
ExistingWorkPolicy.KEEP,
request
)

// Show notification if called by push
// FIXME: Inject PushNotificationManager
if (isPush) {
PushNotificationManager.notify(context, account, authority)
}

return name
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ class NotificationRegistry @Inject constructor(
logger.warning("Notifications disabled, not showing notification $id")
}


// specific common notifications

/**
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,8 @@
<string name="sync_invalid_event">Received invalid event from server</string>
<string name="sync_invalid_task">Received invalid task from server</string>
<string name="sync_invalid_resources_ignoring">Ignoring one or more invalid resources</string>
<string name="sync_notification_pending_push_title">Sync pending</string>
<string name="sync_notification_pending_push_message">Received a push notification from server. Waiting to sync…</string>
rfc2822 marked this conversation as resolved.
Show resolved Hide resolved

<!-- widgets -->
<string name="widget_sync_all">Sync all</string>
Expand Down
Loading