Loading app/src/main/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ package="foundation.e.drive"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" tools:ignore="ProtectedPermissions" /> Loading app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java +2 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import foundation.e.drive.EdriveApplication; import foundation.e.drive.R; import foundation.e.drive.database.DbHelper; import foundation.e.drive.database.FailedSyncPrefsManager; import foundation.e.drive.synchronization.SyncProgressNotifier; import foundation.e.drive.synchronization.SyncWorker; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.DavClientProvider; Loading Loading @@ -153,7 +154,7 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver { notificationManager.cancelAll(); try { notificationManager.deleteNotificationChannel(AppConstants.notificationChannelID); notificationManager.deleteNotificationChannel(SyncWorker.NOTIF_CHANNEL_ID); notificationManager.deleteNotificationChannel(SyncProgressNotifier.NOTIF_CHANNEL_ID); } catch (Exception exception) { Timber.e(exception, "Cannot delete notification Channel"); } Loading app/src/main/java/foundation/e/drive/synchronization/SyncProgressNotifier.kt 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.synchronization import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.pm.ServiceInfo import android.os.Build import androidx.core.app.NotificationCompat import androidx.work.ForegroundInfo import foundation.e.drive.R class SyncProgressNotifier(private val context: Context) { companion object { const val NOTIFICATION_ID = 2003004 const val NOTIF_CHANNEL_ID = "syncChannelId" } private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private fun createNotification(requestCounter: Int): Notification { val text = getNotificationText(requestCounter) val title = context.getString(R.string.notif_sync_is_running_title) return NotificationCompat.Builder(context, NOTIF_CHANNEL_ID) .setOngoing(true) .setContentTitle(title) .setContentText(text) .setSmallIcon(R.drawable.ic_synchronization) .build() } fun notifyTaskFinished(requestCounter: Int) { notificationManager.notify(NOTIFICATION_ID, createNotification(requestCounter)) } fun cancelAllSyncNotifications() { notificationManager.cancel(NOTIFICATION_ID) } private fun getNotificationText(requestCount: Int): String { return context.resources .getQuantityString(R.plurals.notif_sync_is_running_txt, requestCount, requestCount) } fun createNotificationChannel() { val channelName = context.getString(R.string.notif_sync_channel_name) val importance = NotificationManager.IMPORTANCE_MIN val channel = NotificationChannel(NOTIF_CHANNEL_ID, channelName, importance) val channelDescription = context.getString(R.string.notif_sync_channel_description) channel.description = channelDescription notificationManager.createNotificationChannel(channel) } internal fun createForegroundInfo(requestCount: Int): ForegroundInfo { val notification = createNotification(requestCount) return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ForegroundInfo(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) } else { ForegroundInfo(NOTIFICATION_ID, notification) } } } app/src/main/java/foundation/e/drive/synchronization/SyncTask.kt +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ class SyncTask( private val fileName = request.syncedFileState.name private val fileLocalPath = request.syncedFileState.localPath private val syncNotifier = SyncProgressNotifier(context) override fun run() { if (!canStart()) { Loading @@ -55,6 +57,7 @@ class SyncTask( DISABLE_SYNCING -> runSyncDisabling() } syncNotifier.notifyTaskFinished(SyncWorker.pendingTaskCounter.decrementAndGet()) updateFailureCounter(request, succeed) syncManager.removeStartedRequest(fileLocalPath) Timber.d("${request.operationType.name} finished for $fileLocalPath") Loading app/src/main/java/foundation/e/drive/synchronization/SyncWorker.kt +9 −47 Original line number Diff line number Diff line Loading @@ -8,26 +8,19 @@ package foundation.e.drive.synchronization import android.accounts.Account import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.Context.NOTIFICATION_SERVICE import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC import android.os.Build import androidx.core.app.NotificationCompat import androidx.work.ForegroundInfo import androidx.work.Worker import androidx.work.WorkerParameters import com.owncloud.android.lib.common.OwnCloudClient import foundation.e.drive.EdriveApplication import foundation.e.drive.R import foundation.e.drive.account.AccountUtils import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import java.util.concurrent.Executors import java.util.concurrent.Future import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger class SyncWorker( context: Context, Loading @@ -36,20 +29,19 @@ class SyncWorker( companion object { const val UNIQUE_WORK_NAME = "syncWorker" const val NOTIF_CHANNEL_ID = "syncChannelId" const val NOTIFICATION_ID = 2003004 internal lateinit var pendingTaskCounter: AtomicInteger private const val threadAmount = 2 private val syncManager = SyncProxy as SyncManager } private var account: Account? = null private var ocClient: OwnCloudClient? = null private val notificationManager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager private var executor = Executors.newFixedThreadPool(threadAmount) private val syncNotifier = SyncProgressNotifier(applicationContext) override fun onStopped() { Timber.d("SyncWorker has been stopped") notificationManager.cancel(NOTIFICATION_ID) syncNotifier.cancelAllSyncNotifications() executor.shutdownNow() super.onStopped() Loading @@ -70,15 +62,16 @@ class SyncWorker( syncManager.startListeningFiles(applicationContext as EdriveApplication) return Result.failure() } createNotificationChannel() syncNotifier.createNotificationChannel() while (!syncManager.isQueueEmpty()) { setForegroundAsync(createForegroundInfo()) val requestCount = syncManager.getQueueSize() pendingTaskCounter = AtomicInteger(requestCount) setForegroundAsync(syncNotifier.createForegroundInfo(requestCount)) executeRequests() } notificationManager.cancel(NOTIFICATION_ID) syncNotifier.cancelAllSyncNotifications() syncManager.startListeningFiles(applicationContext as EdriveApplication) } catch (exception: Exception) { Timber.w(exception) Loading Loading @@ -120,35 +113,4 @@ class SyncWorker( executor.awaitTermination(30, TimeUnit.SECONDS) } } private fun createForegroundInfo(): ForegroundInfo { val title = applicationContext.getString(R.string.notif_sync_is_running_title) val requestCount = syncManager.getQueueSize() val text = applicationContext.resources .getQuantityString(R.plurals.notif_sync_is_running_txt, requestCount, requestCount) val notification = NotificationCompat.Builder(applicationContext, NOTIF_CHANNEL_ID) .setOngoing(true) .setContentTitle(title) .setContentText(text) .setSmallIcon(R.drawable.ic_synchronization) .build() return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ForegroundInfo(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC) } else { ForegroundInfo(NOTIFICATION_ID, notification) } } private fun createNotificationChannel() { val channelName = applicationContext.getString(R.string.notif_sync_channel_name) val importance = NotificationManager.IMPORTANCE_MIN val channel = NotificationChannel(NOTIF_CHANNEL_ID, channelName, importance) val channelDescription = applicationContext.getString(R.string.notif_sync_channel_description) channel.description = channelDescription notificationManager.createNotificationChannel(channel) } } No newline at end of file Loading
app/src/main/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ package="foundation.e.drive"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" tools:ignore="ProtectedPermissions" /> Loading
app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java +2 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import foundation.e.drive.EdriveApplication; import foundation.e.drive.R; import foundation.e.drive.database.DbHelper; import foundation.e.drive.database.FailedSyncPrefsManager; import foundation.e.drive.synchronization.SyncProgressNotifier; import foundation.e.drive.synchronization.SyncWorker; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.DavClientProvider; Loading Loading @@ -153,7 +154,7 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver { notificationManager.cancelAll(); try { notificationManager.deleteNotificationChannel(AppConstants.notificationChannelID); notificationManager.deleteNotificationChannel(SyncWorker.NOTIF_CHANNEL_ID); notificationManager.deleteNotificationChannel(SyncProgressNotifier.NOTIF_CHANNEL_ID); } catch (Exception exception) { Timber.e(exception, "Cannot delete notification Channel"); } Loading
app/src/main/java/foundation/e/drive/synchronization/SyncProgressNotifier.kt 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.synchronization import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.pm.ServiceInfo import android.os.Build import androidx.core.app.NotificationCompat import androidx.work.ForegroundInfo import foundation.e.drive.R class SyncProgressNotifier(private val context: Context) { companion object { const val NOTIFICATION_ID = 2003004 const val NOTIF_CHANNEL_ID = "syncChannelId" } private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private fun createNotification(requestCounter: Int): Notification { val text = getNotificationText(requestCounter) val title = context.getString(R.string.notif_sync_is_running_title) return NotificationCompat.Builder(context, NOTIF_CHANNEL_ID) .setOngoing(true) .setContentTitle(title) .setContentText(text) .setSmallIcon(R.drawable.ic_synchronization) .build() } fun notifyTaskFinished(requestCounter: Int) { notificationManager.notify(NOTIFICATION_ID, createNotification(requestCounter)) } fun cancelAllSyncNotifications() { notificationManager.cancel(NOTIFICATION_ID) } private fun getNotificationText(requestCount: Int): String { return context.resources .getQuantityString(R.plurals.notif_sync_is_running_txt, requestCount, requestCount) } fun createNotificationChannel() { val channelName = context.getString(R.string.notif_sync_channel_name) val importance = NotificationManager.IMPORTANCE_MIN val channel = NotificationChannel(NOTIF_CHANNEL_ID, channelName, importance) val channelDescription = context.getString(R.string.notif_sync_channel_description) channel.description = channelDescription notificationManager.createNotificationChannel(channel) } internal fun createForegroundInfo(requestCount: Int): ForegroundInfo { val notification = createNotification(requestCount) return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ForegroundInfo(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) } else { ForegroundInfo(NOTIFICATION_ID, notification) } } }
app/src/main/java/foundation/e/drive/synchronization/SyncTask.kt +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ class SyncTask( private val fileName = request.syncedFileState.name private val fileLocalPath = request.syncedFileState.localPath private val syncNotifier = SyncProgressNotifier(context) override fun run() { if (!canStart()) { Loading @@ -55,6 +57,7 @@ class SyncTask( DISABLE_SYNCING -> runSyncDisabling() } syncNotifier.notifyTaskFinished(SyncWorker.pendingTaskCounter.decrementAndGet()) updateFailureCounter(request, succeed) syncManager.removeStartedRequest(fileLocalPath) Timber.d("${request.operationType.name} finished for $fileLocalPath") Loading
app/src/main/java/foundation/e/drive/synchronization/SyncWorker.kt +9 −47 Original line number Diff line number Diff line Loading @@ -8,26 +8,19 @@ package foundation.e.drive.synchronization import android.accounts.Account import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.Context.NOTIFICATION_SERVICE import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC import android.os.Build import androidx.core.app.NotificationCompat import androidx.work.ForegroundInfo import androidx.work.Worker import androidx.work.WorkerParameters import com.owncloud.android.lib.common.OwnCloudClient import foundation.e.drive.EdriveApplication import foundation.e.drive.R import foundation.e.drive.account.AccountUtils import foundation.e.drive.utils.DavClientProvider import timber.log.Timber import java.util.concurrent.Executors import java.util.concurrent.Future import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger class SyncWorker( context: Context, Loading @@ -36,20 +29,19 @@ class SyncWorker( companion object { const val UNIQUE_WORK_NAME = "syncWorker" const val NOTIF_CHANNEL_ID = "syncChannelId" const val NOTIFICATION_ID = 2003004 internal lateinit var pendingTaskCounter: AtomicInteger private const val threadAmount = 2 private val syncManager = SyncProxy as SyncManager } private var account: Account? = null private var ocClient: OwnCloudClient? = null private val notificationManager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager private var executor = Executors.newFixedThreadPool(threadAmount) private val syncNotifier = SyncProgressNotifier(applicationContext) override fun onStopped() { Timber.d("SyncWorker has been stopped") notificationManager.cancel(NOTIFICATION_ID) syncNotifier.cancelAllSyncNotifications() executor.shutdownNow() super.onStopped() Loading @@ -70,15 +62,16 @@ class SyncWorker( syncManager.startListeningFiles(applicationContext as EdriveApplication) return Result.failure() } createNotificationChannel() syncNotifier.createNotificationChannel() while (!syncManager.isQueueEmpty()) { setForegroundAsync(createForegroundInfo()) val requestCount = syncManager.getQueueSize() pendingTaskCounter = AtomicInteger(requestCount) setForegroundAsync(syncNotifier.createForegroundInfo(requestCount)) executeRequests() } notificationManager.cancel(NOTIFICATION_ID) syncNotifier.cancelAllSyncNotifications() syncManager.startListeningFiles(applicationContext as EdriveApplication) } catch (exception: Exception) { Timber.w(exception) Loading Loading @@ -120,35 +113,4 @@ class SyncWorker( executor.awaitTermination(30, TimeUnit.SECONDS) } } private fun createForegroundInfo(): ForegroundInfo { val title = applicationContext.getString(R.string.notif_sync_is_running_title) val requestCount = syncManager.getQueueSize() val text = applicationContext.resources .getQuantityString(R.plurals.notif_sync_is_running_txt, requestCount, requestCount) val notification = NotificationCompat.Builder(applicationContext, NOTIF_CHANNEL_ID) .setOngoing(true) .setContentTitle(title) .setContentText(text) .setSmallIcon(R.drawable.ic_synchronization) .build() return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ForegroundInfo(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC) } else { ForegroundInfo(NOTIFICATION_ID, notification) } } private fun createNotificationChannel() { val channelName = applicationContext.getString(R.string.notif_sync_channel_name) val importance = NotificationManager.IMPORTANCE_MIN val channel = NotificationChannel(NOTIF_CHANNEL_ID, channelName, importance) val channelDescription = applicationContext.getString(R.string.notif_sync_channel_description) channel.description = channelDescription notificationManager.createNotificationChannel(channel) } } No newline at end of file