Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02224377 authored by Vincent Bourgmayer's avatar Vincent Bourgmayer
Browse files

Merge branch '1751-improve-notification' into '115-epic'

introduce SyncProgressNotifier

See merge request !264
parents 0e74d035 295fb6de
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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" />
+2 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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");
        }
+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)
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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()) {
@@ -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")
+9 −47
Original line number Diff line number Diff line
@@ -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,
@@ -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()
@@ -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)
@@ -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