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

Fix: Since android 12, foreground service throw an exception #1030

Merged
merged 2 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions app/src/main/java/com/infomaniak/drive/data/api/UploadTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import com.infomaniak.drive.data.models.drive.Drive
import com.infomaniak.drive.data.models.upload.UploadSession
import com.infomaniak.drive.data.models.upload.ValidChunks
import com.infomaniak.drive.data.services.UploadWorker
import com.infomaniak.drive.data.services.UploadWorker.Companion.updateUploadCountNotification
import com.infomaniak.drive.data.sync.UploadNotifications.progressPendingIntent
import com.infomaniak.drive.utils.NotificationUtils.CURRENT_UPLOAD_ID
import com.infomaniak.drive.utils.NotificationUtils.ELAPSED_TIME
Expand Down Expand Up @@ -315,7 +314,6 @@ class UploadTask(
ensureActive()

if (uploadNotificationElapsedTime >= ELAPSED_TIME) {
updatePendingCountNotificationIfNeeded()
uploadNotification.apply {
setContentIntent(uploadFile.progressPendingIntent(context))
setContentText("${currentProgress}%")
Expand All @@ -336,14 +334,6 @@ class UploadTask(
)
}

private fun CoroutineScope.updatePendingCountNotificationIfNeeded() {
val latestPendingCount = UploadFile.getAllPendingUploadsCount()
if (worker.pendingCount != latestPendingCount) {
updateUploadCountNotification(context, latestPendingCount)
worker.pendingCount = latestPendingCount
}
}

private suspend fun shareProgress(progress: Int = 0, isUploaded: Boolean = false) {
worker.setProgress(
workDataOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,13 @@ import com.infomaniak.drive.data.models.UploadFile
import com.infomaniak.drive.data.services.UploadWorkerThrowable.runUploadCatching
import com.infomaniak.drive.data.sync.UploadNotifications
import com.infomaniak.drive.data.sync.UploadNotifications.NOTIFICATION_FILES_LIMIT
import com.infomaniak.drive.data.sync.UploadNotifications.setupCurrentUploadNotification
import com.infomaniak.drive.data.sync.UploadNotifications.showUploadedFilesNotification
import com.infomaniak.drive.data.sync.UploadNotifications.syncSettingsActivityPendingIntent
import com.infomaniak.drive.utils.*
import com.infomaniak.drive.utils.MediaFoldersProvider.IMAGES_BUCKET_ID
import com.infomaniak.drive.utils.MediaFoldersProvider.VIDEO_BUCKET_ID
import com.infomaniak.drive.utils.NotificationUtils.buildGeneralNotification
import com.infomaniak.drive.utils.NotificationUtils.cancelNotification
import com.infomaniak.drive.utils.NotificationUtils.uploadServiceNotification
import com.infomaniak.drive.utils.SyncUtils.syncImmediately
import com.infomaniak.lib.core.api.ApiController
import com.infomaniak.lib.core.utils.*
Expand All @@ -68,7 +66,7 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
var currentUploadFile: UploadFile? = null
var currentUploadTask: UploadTask? = null
var uploadedCount = 0
var pendingCount = 0
private var pendingCount = 0

override suspend fun doWork(): Result {

Expand All @@ -78,8 +76,6 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
// Checks if the maximum number of retry allowed is reached
if (runAttemptCount >= MAX_RETRY_COUNT) return Result.failure()

moveServiceToForeground()

return runUploadCatching {
// Check if we have the required permissions before continuing
checkPermissions()?.let { return@runUploadCatching it }
Expand All @@ -100,11 +96,10 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
}
}

private suspend fun moveServiceToForeground() {
applicationContext.uploadServiceNotification().apply {
setContentTitle(applicationContext.getString(R.string.notificationUploadServiceChannelName))
setForeground(ForegroundInfo(NotificationUtils.UPLOAD_SERVICE_ID, build()))
}
override suspend fun getForegroundInfo(): ForegroundInfo {
val pendingCount = if (this.pendingCount > 0) this.pendingCount else UploadFile.getAllPendingUploadsCount()
val currentUploadNotification = UploadNotifications.getCurrentUploadNotification(applicationContext, pendingCount)
return ForegroundInfo(NotificationUtils.UPLOAD_SERVICE_ID, currentUploadNotification.build())
}

private fun checkPermissions(): Result? {
Expand Down Expand Up @@ -144,7 +139,7 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
for (uploadFile in uploadFiles) {
Log.d(TAG, "startSyncFiles> upload ${uploadFile.fileName}")

if (uploadFile.initUpload(pendingCount)) {
if (uploadFile.initUpload()) {
successNames.add(uploadFile.fileName)
successCount++
} else {
Expand Down Expand Up @@ -178,12 +173,12 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
}
}

private suspend fun UploadFile.initUpload(pendingCount: Int) = withContext(Dispatchers.IO) {
private suspend fun UploadFile.initUpload() = withContext(Dispatchers.IO) {
val uri = getUriObject()

currentUploadFile = this@initUpload
applicationContext.cancelNotification(NotificationUtils.CURRENT_UPLOAD_ID)
updateUploadCountNotification(applicationContext, pendingCount)
updateUploadCountNotification(applicationContext)

try {
if (uri.scheme.equals(ContentResolver.SCHEME_FILE)) {
Expand Down Expand Up @@ -242,6 +237,16 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
}
}

private var uploadCountNotificationJob: Job? = null
private fun CoroutineScope.updateUploadCountNotification(context: Context) {
uploadCountNotificationJob?.cancel()
uploadCountNotificationJob = launch {
// We wait a little otherwise it is too fast and the notification may not be updated
delay(NotificationUtils.ELAPSED_TIME)
if (isActive) UploadNotifications.setupCurrentUploadNotification(context, pendingCount)
}
}

private fun UploadFile.handleException(exception: Exception) {
when (exception) {
is SecurityException, is IllegalStateException, is IllegalArgumentException -> {
Expand Down Expand Up @@ -458,15 +463,6 @@ class UploadWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
.build()
}

fun CoroutineScope.updateUploadCountNotification(context: Context, pendingCount: Int) {
launch {
// We wait a little otherwise it is too fast and the notification may not be updated
delay(NotificationUtils.ELAPSED_TIME)
ensureActive()
setupCurrentUploadNotification(context, pendingCount)
}
}

@SuppressLint("MissingPermission")
fun Context.showSyncConfigNotification() {
val pendingIntent = syncSettingsActivityPendingIntent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ object UploadWorkerThrowable {
}

private fun UploadWorker.cancelUploadNotification() {
applicationContext.cancelNotification(NotificationUtils.UPLOAD_SERVICE_ID)
applicationContext.cancelNotification(NotificationUtils.CURRENT_UPLOAD_ID)
Sentry.addBreadcrumb(Breadcrumb().apply {
category = UploadWorker.BREADCRUMB_TAG
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ object UploadNotifications {

const val NOTIFICATION_FILES_LIMIT = 5

fun getCurrentUploadNotification(context: Context, pendingCount: Int): NotificationCompat.Builder {
val pendingTitle = context.getString(R.string.uploadInProgressTitle)
val pendingDescription = context.resources.getQuantityString(
R.plurals.uploadInProgressNumberFile,
pendingCount,
pendingCount
)
val intent = Intent(context, LaunchActivity::class.java).clearStack()
val contentIntent = PendingIntent.getActivity(context, 0, intent, pendingIntentFlags)
return getNotificationBuilder(context, pendingTitle, pendingDescription, contentIntent)
}

fun setupCurrentUploadNotification(context: Context, pendingCount: Int) {
val pendingTitle = context.getString(R.string.uploadInProgressTitle)
val pendingDescription = context.resources.getQuantityString(
Expand Down Expand Up @@ -194,7 +206,18 @@ object UploadNotifications {
locateButton: Boolean = false
) {
val notificationManagerCompat = NotificationManagerCompat.from(context)
context.uploadNotification().apply {
val notificationBuilder = getNotificationBuilder(context, title, description, contentIntent, locateButton)
notificationManagerCompat.notify(notificationId, notificationBuilder.build())
}

private fun getNotificationBuilder(
context: Context,
title: String,
description: String,
contentIntent: PendingIntent? = null,
locateButton: Boolean = false
): NotificationCompat.Builder {
return context.uploadNotification().apply {
setTicker(title)
setAutoCancel(true)
setContentTitle(title)
Expand All @@ -205,7 +228,6 @@ object UploadNotifications {
NotificationCompat.Action(R.drawable.ic_export, context.getString(R.string.locateButton), contentIntent)
)
}
notificationManagerCompat.notify(notificationId, this.build())
}
}

Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/infomaniak/drive/utils/SyncUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ object SyncUtils {
if (!isSyncActive() || force) {
val request = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(UploadWorker.workConstraints())
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
}
.setInputData(data)
.build()
WorkManager.getInstance(this).enqueueUniqueWork(UploadWorker.TAG, ExistingWorkPolicy.REPLACE, request)
Expand Down
Loading