瀏覽代碼

Merge pull request #5892 from nextcloud/ezaquarii/migrate-notifcation-job-to-work-manager-api

Migrate notifcation job to work manager api
Tobias Kaminsky 5 年之前
父節點
當前提交
f477a6873b

+ 12 - 15
src/gplay/java/com/owncloud/android/services/firebase/NCFirebaseMessagingService.java

@@ -3,6 +3,7 @@
  *
  * @author Mario Danic
  * Copyright (C) 2017 Mario Danic
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -21,16 +22,17 @@ package com.owncloud.android.services.firebase;
 
 import android.text.TextUtils;
 
-import com.evernote.android.job.JobRequest;
-import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.google.firebase.messaging.FirebaseMessagingService;
 import com.google.firebase.messaging.RemoteMessage;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.jobs.BackgroundJobManager;
+import com.nextcloud.client.jobs.NotificationWork;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.R;
-import com.owncloud.android.jobs.NotificationJob;
 import com.owncloud.android.utils.PushUtils;
 
+import java.util.Map;
+
 import javax.inject.Inject;
 
 import androidx.annotation.NonNull;
@@ -39,6 +41,7 @@ import dagger.android.AndroidInjection;
 public class NCFirebaseMessagingService extends FirebaseMessagingService {
     @Inject AppPreferences preferences;
     @Inject UserAccountManager accountManager;
+    @Inject BackgroundJobManager backgroundJobManager;
 
     @Override
     public void onCreate() {
@@ -48,18 +51,12 @@ public class NCFirebaseMessagingService extends FirebaseMessagingService {
 
     @Override
     public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
-        remoteMessage.getData();
-        PersistableBundleCompat persistableBundleCompat = new PersistableBundleCompat();
-        persistableBundleCompat.putString(NotificationJob.KEY_NOTIFICATION_SUBJECT, remoteMessage.getData().get
-            (NotificationJob.KEY_NOTIFICATION_SUBJECT));
-        persistableBundleCompat.putString(NotificationJob.KEY_NOTIFICATION_SIGNATURE, remoteMessage.getData().get
-            (NotificationJob.KEY_NOTIFICATION_SIGNATURE));
-        new JobRequest.Builder(NotificationJob.TAG)
-            .addExtras(persistableBundleCompat)
-            .setUpdateCurrent(false)
-            .startNow()
-            .build()
-            .schedule();
+        final Map<String, String> data = remoteMessage.getData();
+        final String subject = data.get(NotificationWork.KEY_NOTIFICATION_SUBJECT);
+        final String signature = data.get(NotificationWork.KEY_NOTIFICATION_SIGNATURE);
+        if (subject != null && signature != null) {
+            backgroundJobManager.startNotificationJob(subject, signature);
+        }
     }
 
     @Override

+ 1 - 1
src/main/AndroidManifest.xml

@@ -141,7 +141,7 @@
             android:configChanges="orientation|screenSize|keyboardHidden" />
         <activity android:name=".ui.activity.SyncedFoldersActivity"/>
         <receiver android:name="com.nextcloud.client.jobs.MediaFoldersDetectionWork$NotificationReceiver" />
-        <receiver android:name="com.owncloud.android.jobs.NotificationJob$NotificationReceiver" />
+        <receiver android:name="com.nextcloud.client.jobs.NotificationWork$NotificationReceiver" />
         <activity android:name=".ui.activity.UploadFilesActivity" />
         <activity android:name=".ui.activity.ExternalSiteWebView"
                   android:configChanges="orientation|screenSize|keyboardHidden" />

+ 2 - 2
src/main/java/com/nextcloud/client/di/ComponentsModule.java

@@ -21,6 +21,7 @@
 package com.nextcloud.client.di;
 
 import com.nextcloud.client.etm.EtmActivity;
+import com.nextcloud.client.jobs.NotificationWork;
 import com.nextcloud.client.logger.ui.LogsActivity;
 import com.nextcloud.client.media.PlayerService;
 import com.nextcloud.client.onboarding.FirstRunActivity;
@@ -30,7 +31,6 @@ import com.owncloud.android.authentication.DeepLinkLoginActivity;
 import com.owncloud.android.files.BootupBroadcastReceiver;
 import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.jobs.NotificationJob;
 import com.owncloud.android.providers.DiskLruImageCacheFileProvider;
 import com.owncloud.android.providers.FileContentProvider;
 import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
@@ -157,7 +157,7 @@ abstract class ComponentsModule {
     @ContributesAndroidInjector abstract FileDownloader fileDownloader();
 
     @ContributesAndroidInjector abstract BootupBroadcastReceiver bootupBroadcastReceiver();
-    @ContributesAndroidInjector abstract NotificationJob.NotificationReceiver notificationJobBroadcastReceiver();
+    @ContributesAndroidInjector abstract NotificationWork.NotificationReceiver notificationWorkBroadcastReceiver();
 
     @ContributesAndroidInjector abstract FileContentProvider fileContentProvider();
     @ContributesAndroidInjector abstract UsersAndGroupsSearchProvider usersAndGroupsSearchProvider();

+ 13 - 1
src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt

@@ -19,6 +19,7 @@
  */
 package com.nextcloud.client.jobs
 
+import android.app.NotificationManager
 import android.content.ContentResolver
 import android.content.Context
 import android.content.res.Resources
@@ -56,7 +57,8 @@ class BackgroundJobFactory @Inject constructor(
     private val resources: Resources,
     private val dataProvider: ArbitraryDataProvider,
     private val uploadsStorageManager: UploadsStorageManager,
-    private val connectivityService: ConnectivityService
+    private val connectivityService: ConnectivityService,
+    private val notificationManager: NotificationManager
 ) : WorkerFactory() {
 
     override fun createWorker(
@@ -78,6 +80,7 @@ class BackgroundJobFactory @Inject constructor(
             FilesSyncWork::class -> createFilesSyncWork(context, workerParameters)
             OfflineSyncWork::class -> createOfflineSyncWork(context, workerParameters)
             MediaFoldersDetectionWork::class -> createMediaFoldersDetectionWork(context, workerParameters)
+            NotificationWork::class -> createNotificationWork(context, workerParameters)
             else -> null // caller falls back to default factory
         }
     }
@@ -160,4 +163,13 @@ class BackgroundJobFactory @Inject constructor(
             clock
         )
     }
+
+    private fun createNotificationWork(context: Context, params: WorkerParameters): NotificationWork {
+        return NotificationWork(
+            context,
+            params,
+            notificationManager,
+            accountManager
+            )
+    }
 }

+ 2 - 0
src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt

@@ -97,6 +97,8 @@ interface BackgroundJobManager {
     fun scheduleMediaFoldersDetectionJob()
     fun startMediaFoldersDetectionJob()
 
+    fun startNotificationJob(subject: String, signature: String)
+
     fun scheduleTestJob()
     fun startImmediateTestJob()
     fun cancelTestJob()

+ 14 - 0
src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

@@ -73,6 +73,7 @@ internal class BackgroundJobManagerImpl(
         const val JOB_PERIODIC_OFFLINE_SYNC = "periodic_offline_sync"
         const val JOB_PERIODIC_MEDIA_FOLDER_DETECTION = "periodic_media_folder_detection"
         const val JOB_IMMEDIATE_MEDIA_FOLDER_DETECTION = "immediate_media_folder_detection"
+        const val JOB_NOTIFICATION = "notification"
         const val JOB_TEST = "test_job"
 
         const val MAX_CONTENT_TRIGGER_DELAY_MS = 1500L
@@ -338,6 +339,19 @@ internal class BackgroundJobManagerImpl(
         )
     }
 
+    override fun startNotificationJob(subject: String, signature: String) {
+        val data = Data.Builder()
+            .putString(NotificationWork.KEY_NOTIFICATION_SUBJECT, subject)
+            .putString(NotificationWork.KEY_NOTIFICATION_SIGNATURE, signature)
+            .build()
+
+        val request = oneTimeRequestBuilder(NotificationWork::class, JOB_NOTIFICATION)
+            .setInputData(data)
+            .build()
+
+        workManager.enqueue(request)
+    }
+
     override fun scheduleTestJob() {
         val request = periodicRequestBuilder(TestJob::class, JOB_TEST)
             .setInitialDelay(DEFAULT_IMMEDIATE_JOB_DELAY_SEC, TimeUnit.SECONDS)

+ 1 - 2
src/main/java/com/nextcloud/client/jobs/MediaFoldersDetectionWork.kt

@@ -48,7 +48,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider
 import com.owncloud.android.datamodel.MediaFoldersModel
 import com.owncloud.android.datamodel.MediaProvider
 import com.owncloud.android.datamodel.SyncedFolderProvider
-import com.owncloud.android.jobs.NotificationJob
 import com.owncloud.android.lib.common.utils.Log_OC
 import com.owncloud.android.ui.activity.ManageAccountsActivity
 import com.owncloud.android.ui.activity.SyncedFoldersActivity
@@ -175,7 +174,7 @@ class MediaFoldersDetectionWork constructor(
         val intent = Intent(context, SyncedFoldersActivity::class.java)
         intent.putExtra(NOTIFICATION_ID, notificationId)
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
-        intent.putExtra(NotificationJob.KEY_NOTIFICATION_ACCOUNT, user.accountName)
+        intent.putExtra(NotificationWork.KEY_NOTIFICATION_ACCOUNT, user.accountName)
         intent.putExtra(KEY_MEDIA_FOLDER_PATH, path)
         intent.putExtra(KEY_MEDIA_FOLDER_TYPE, type)
         intent.putExtra(SyncedFoldersActivity.EXTRA_SHOW_SIDEBAR, true)

+ 317 - 0
src/main/java/com/nextcloud/client/jobs/NotificationWork.kt

@@ -0,0 +1,317 @@
+/*
+* Nextcloud application
+*
+* @author Mario Danic
+* @author Chris Narkiewicz
+* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+package com.nextcloud.client.jobs
+
+import android.accounts.AuthenticatorException
+import android.accounts.OperationCanceledException
+import android.app.Activity
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.graphics.BitmapFactory
+import android.media.RingtoneManager
+import android.os.Build
+import android.text.TextUtils
+import android.util.Base64
+import android.util.Log
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import com.google.gson.Gson
+import com.nextcloud.client.account.User
+import com.nextcloud.client.account.UserAccountManager
+import com.owncloud.android.R
+import com.owncloud.android.datamodel.DecryptedPushMessage
+import com.owncloud.android.lib.common.OwnCloudClient
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
+import com.owncloud.android.lib.common.operations.RemoteOperation
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.lib.resources.notifications.DeleteNotificationRemoteOperation
+import com.owncloud.android.lib.resources.notifications.GetNotificationRemoteOperation
+import com.owncloud.android.lib.resources.notifications.models.Notification
+import com.owncloud.android.ui.activity.FileDisplayActivity
+import com.owncloud.android.ui.activity.NotificationsActivity
+import com.owncloud.android.ui.notifications.NotificationUtils
+import com.owncloud.android.utils.PushUtils
+import com.owncloud.android.utils.ThemeUtils
+import dagger.android.AndroidInjection
+import org.apache.commons.httpclient.HttpMethod
+import org.apache.commons.httpclient.HttpStatus
+import org.apache.commons.httpclient.methods.DeleteMethod
+import org.apache.commons.httpclient.methods.GetMethod
+import org.apache.commons.httpclient.methods.PutMethod
+import org.apache.commons.httpclient.methods.Utf8PostMethod
+import java.io.IOException
+import java.security.GeneralSecurityException
+import java.security.PrivateKey
+import java.security.SecureRandom
+import javax.crypto.Cipher
+import javax.inject.Inject
+
+class NotificationWork constructor(
+    private val context: Context,
+    params: WorkerParameters,
+    private val notificationManager: NotificationManager,
+    private val accountManager: UserAccountManager
+) : Worker(context, params) {
+
+    companion object {
+        const val TAG = "NotificationJob"
+        const val KEY_NOTIFICATION_ACCOUNT = "KEY_NOTIFICATION_ACCOUNT"
+        const val KEY_NOTIFICATION_SUBJECT = "subject"
+        const val KEY_NOTIFICATION_SIGNATURE = "signature"
+        private const val KEY_NOTIFICATION_ACTION_LINK = "KEY_NOTIFICATION_ACTION_LINK"
+        private const val KEY_NOTIFICATION_ACTION_TYPE = "KEY_NOTIFICATION_ACTION_TYPE"
+        private const val PUSH_NOTIFICATION_ID = "PUSH_NOTIFICATION_ID"
+        private const val NUMERIC_NOTIFICATION_ID = "NUMERIC_NOTIFICATION_ID"
+    }
+
+    @Suppress("TooGenericExceptionCaught") // legacy code
+    override fun doWork(): Result {
+        val subject = inputData.getString(KEY_NOTIFICATION_SUBJECT) ?: ""
+        val signature = inputData.getString(KEY_NOTIFICATION_SIGNATURE) ?: ""
+        if (!TextUtils.isEmpty(subject) && !TextUtils.isEmpty(signature)) {
+            try {
+                val base64DecodedSubject = Base64.decode(subject, Base64.DEFAULT)
+                val base64DecodedSignature = Base64.decode(signature, Base64.DEFAULT)
+                val privateKey = PushUtils.readKeyFromFile(false) as PrivateKey
+                try {
+                    val signatureVerification = PushUtils.verifySignature(context,
+                        accountManager,
+                        base64DecodedSignature,
+                        base64DecodedSubject)
+                    if (signatureVerification != null && signatureVerification.isSignatureValid) {
+                        val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+                        cipher.init(Cipher.DECRYPT_MODE, privateKey)
+                        val decryptedSubject = cipher.doFinal(base64DecodedSubject)
+                        val gson = Gson()
+                        val decryptedPushMessage = gson.fromJson(String(decryptedSubject),
+                            DecryptedPushMessage::class.java)
+                        if (decryptedPushMessage.delete) {
+                            notificationManager.cancel(decryptedPushMessage.nid)
+                        } else if (decryptedPushMessage.deleteAll) {
+                            notificationManager.cancelAll()
+                        } else {
+                            val user = accountManager.getUser(signatureVerification.getAccount().name)
+                                .orElseThrow { RuntimeException() }
+                            fetchCompleteNotification(user, decryptedPushMessage)
+                        }
+                    }
+                } catch (e1: GeneralSecurityException) {
+                    Log.d(TAG, "Error decrypting message ${e1.javaClass.name} ${e1.localizedMessage}")
+                }
+            } catch (exception: Exception) {
+                Log.d(TAG, "Something went very wrong" + exception.localizedMessage)
+            }
+        }
+        return Result.success()
+    }
+
+    private fun sendNotification(notification: Notification, user: User) {
+        val randomId = SecureRandom()
+        val file = notification.subjectRichParameters["file"]
+        val intent: Intent
+        if (file == null) {
+            intent = Intent(context, NotificationsActivity::class.java)
+        } else {
+            intent = Intent(context, FileDisplayActivity::class.java)
+            intent.action = Intent.ACTION_VIEW
+            intent.putExtra(FileDisplayActivity.KEY_FILE_ID, file.id)
+        }
+        intent.putExtra(KEY_NOTIFICATION_ACCOUNT, user.accountName)
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
+        val pushNotificationId = randomId.nextInt()
+        val notificationBuilder = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH)
+            .setSmallIcon(R.drawable.notification_icon)
+            .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
+            .setColor(ThemeUtils.primaryColor(user.toPlatformAccount(), false, context))
+            .setShowWhen(true)
+            .setSubText(user.accountName)
+            .setContentTitle(notification.getSubject())
+            .setContentText(notification.getMessage())
+            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
+            .setAutoCancel(true)
+            .setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
+            .setContentIntent(pendingIntent)
+        // Remove
+        if (notification.getActions().isEmpty()) {
+            val disableDetection = Intent(context, NotificationReceiver::class.java)
+            disableDetection.putExtra(NUMERIC_NOTIFICATION_ID, notification.getNotificationId())
+            disableDetection.putExtra(PUSH_NOTIFICATION_ID, pushNotificationId)
+            disableDetection.putExtra(KEY_NOTIFICATION_ACCOUNT, user.accountName)
+            val disableIntent = PendingIntent.getBroadcast(context, pushNotificationId, disableDetection,
+                PendingIntent.FLAG_CANCEL_CURRENT)
+            notificationBuilder.addAction(NotificationCompat.Action(R.drawable.ic_close,
+                context.getString(R.string.remove_push_notification), disableIntent))
+        } else { // Actions
+            for (action in notification.getActions()) {
+                val actionIntent = Intent(context, NotificationReceiver::class.java)
+                actionIntent.putExtra(NUMERIC_NOTIFICATION_ID, notification.getNotificationId())
+                actionIntent.putExtra(PUSH_NOTIFICATION_ID, pushNotificationId)
+                actionIntent.putExtra(KEY_NOTIFICATION_ACCOUNT, user.accountName)
+                actionIntent.putExtra(KEY_NOTIFICATION_ACTION_LINK, action.link)
+                actionIntent.putExtra(KEY_NOTIFICATION_ACTION_TYPE, action.type)
+                val actionPendingIntent = PendingIntent.getBroadcast(context, randomId.nextInt(),
+                    actionIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT)
+                var icon: Int
+                icon = if (action.primary) {
+                    R.drawable.ic_check_circle
+                } else {
+                    R.drawable.ic_check_circle_outline
+                }
+                notificationBuilder.addAction(NotificationCompat.Action(icon, action.label, actionPendingIntent))
+            }
+        }
+        notificationBuilder.setPublicVersion(
+            NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH)
+                .setSmallIcon(R.drawable.notification_icon)
+                .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
+                .setColor(ThemeUtils.primaryColor(user.toPlatformAccount(), false, context))
+                .setShowWhen(true)
+                .setSubText(user.accountName)
+                .setContentTitle(context.getString(R.string.new_notification))
+                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
+                .setAutoCancel(true)
+                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+                .setContentIntent(pendingIntent).build())
+        val notificationManager = NotificationManagerCompat.from(context)
+        notificationManager.notify(notification.getNotificationId(), notificationBuilder.build())
+    }
+
+    @Suppress("TooGenericExceptionCaught") // legacy code
+    private fun fetchCompleteNotification(account: User, decryptedPushMessage: DecryptedPushMessage) {
+        val optionalUser = accountManager.getUser(account.accountName)
+        if (!optionalUser.isPresent) {
+            Log_OC.e(this, "Account may not be null")
+            return
+        }
+        val user = optionalUser.get()
+        try {
+            val client = OwnCloudClientManagerFactory.getDefaultSingleton()
+                .getClientFor(user.toOwnCloudAccount(), context)
+            val result = GetNotificationRemoteOperation(decryptedPushMessage.nid)
+                .execute(client)
+            if (result.isSuccess) {
+                val notification = result.notificationData[0]
+                sendNotification(notification, account)
+            }
+        } catch (e: Exception) {
+            Log_OC.e(this, "Error creating account", e)
+        }
+    }
+
+    class NotificationReceiver : BroadcastReceiver() {
+        private lateinit var accountManager: UserAccountManager
+
+        /**
+         * This is a workaround for a Dagger compiler bug - it cannot inject
+         * into a nested Kotlin class for some reason, but the helper
+         * works.
+         */
+        @Inject
+        fun inject(accountManager: UserAccountManager) {
+            this.accountManager = accountManager
+        }
+
+        override fun onReceive(context: Context, intent: Intent) {
+            AndroidInjection.inject(this, context)
+            val numericNotificationId = intent.getIntExtra(NUMERIC_NOTIFICATION_ID, 0)
+            val accountName = intent.getStringExtra(KEY_NOTIFICATION_ACCOUNT)
+            if (numericNotificationId != 0) {
+                Thread(Runnable {
+                    val notificationManager = context.getSystemService(
+                        Activity.NOTIFICATION_SERVICE) as NotificationManager
+                    var oldNotification: android.app.Notification? = null
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && notificationManager != null) {
+                        for (statusBarNotification in notificationManager.activeNotifications) {
+                            if (numericNotificationId == statusBarNotification.id) {
+                                oldNotification = statusBarNotification.notification
+                                break
+                            }
+                        }
+                        cancel(context, numericNotificationId)
+                    }
+                    try {
+                        val optionalUser = accountManager.getUser(accountName)
+                        if (optionalUser.isPresent) {
+                            val user = optionalUser.get()
+                            val client = OwnCloudClientManagerFactory.getDefaultSingleton()
+                                .getClientFor(user.toOwnCloudAccount(), context)
+                            val actionType = intent.getStringExtra(KEY_NOTIFICATION_ACTION_TYPE)
+                            val actionLink = intent.getStringExtra(KEY_NOTIFICATION_ACTION_LINK)
+                            val success: Boolean
+                            success = if (!TextUtils.isEmpty(actionType) && !TextUtils.isEmpty(actionLink)) {
+                                val resultCode = executeAction(actionType, actionLink, client)
+                                resultCode == HttpStatus.SC_OK || resultCode == HttpStatus.SC_ACCEPTED
+                            } else {
+                                DeleteNotificationRemoteOperation(numericNotificationId)
+                                    .execute(client).isSuccess
+                            }
+                            if (success) {
+                                if (oldNotification == null) {
+                                    cancel(context, numericNotificationId)
+                                }
+                            } else {
+                                notificationManager.notify(numericNotificationId, oldNotification)
+                            }
+                        }
+                    } catch (e: IOException) {
+                        Log_OC.e(TAG, "Error initializing client", e)
+                    } catch (e: OperationCanceledException) {
+                        Log_OC.e(TAG, "Error initializing client", e)
+                    } catch (e: AuthenticatorException) {
+                        Log_OC.e(TAG, "Error initializing client", e)
+                    }
+                }).start()
+            }
+        }
+
+        @Suppress("ReturnCount") // legacy code
+        private fun executeAction(actionType: String, actionLink: String, client: OwnCloudClient): Int {
+            val method: HttpMethod
+            method = when (actionType) {
+                "GET" -> GetMethod(actionLink)
+                "POST" -> Utf8PostMethod(actionLink)
+                "DELETE" -> DeleteMethod(actionLink)
+                "PUT" -> PutMethod(actionLink)
+                else -> return 0 // do nothing
+            }
+            method.setRequestHeader(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE)
+            try {
+                return client.executeMethod(method)
+            } catch (e: IOException) {
+                Log_OC.e(TAG, "Execution of notification action failed: $e")
+            }
+            return 0
+        }
+
+        private fun cancel(context: Context, notificationId: Int) {
+            val notificationManager = context.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
+            notificationManager.cancel(notificationId)
+        }
+    }
+}

+ 0 - 1
src/main/java/com/owncloud/android/MainApp.java

@@ -259,7 +259,6 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
 
         JobManager.create(this).addJobCreator(
             new NCJobCreator(
-                getApplicationContext(),
                 accountManager,
                 uploadsStorageManager,
                 clock,

+ 9 - 14
src/main/java/com/owncloud/android/jobs/NCJobCreator.java

@@ -25,6 +25,7 @@
 package com.owncloud.android.jobs;
 
 import android.content.Context;
+import android.text.TextUtils;
 
 import com.evernote.android.job.Job;
 import com.evernote.android.job.JobCreator;
@@ -43,7 +44,6 @@ import androidx.annotation.NonNull;
 
 public class NCJobCreator implements JobCreator {
 
-    private final Context context;
     private final UserAccountManager accountManager;
     private final UploadsStorageManager uploadsStorageManager;
     private final Clock clock;
@@ -51,14 +51,12 @@ public class NCJobCreator implements JobCreator {
     private final BackgroundJobManager backgroundJobManager;
 
     public NCJobCreator(
-        Context context,
         UserAccountManager accountManager,
         UploadsStorageManager uploadsStorageManager,
         Clock clock,
         EventBus eventBus,
         BackgroundJobManager backgroundJobManager
     ) {
-        this.context = context;
         this.accountManager = accountManager;
         this.uploadsStorageManager = uploadsStorageManager;
         this.clock = clock;
@@ -68,17 +66,14 @@ public class NCJobCreator implements JobCreator {
 
     @Override
     public Job create(@NonNull String tag) {
-        switch (tag) {
-            case AccountRemovalJob.TAG:
-                return new AccountRemovalJob(uploadsStorageManager,
-                                             accountManager,
-                                             backgroundJobManager,
-                                             clock,
-                                             eventBus);
-            case NotificationJob.TAG:
-                return new NotificationJob(context, accountManager);
-            default:
-                return null;
+        if (TextUtils.equals(tag, AccountRemovalJob.TAG)) {
+            return new AccountRemovalJob(uploadsStorageManager,
+                                         accountManager,
+                                         backgroundJobManager,
+                                         clock,
+                                         eventBus);
+        } else {
+            return null;
         }
     }
 }

+ 3 - 3
src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java

@@ -6,7 +6,7 @@
  * @author Chris Narkiewicz
  * Copyright (C) 2017 Andy Scherzinger
  * Copyright (C) 2017 Mario Danic
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as published by
@@ -38,11 +38,11 @@ import android.widget.TextView;
 import com.google.android.material.snackbar.Snackbar;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.jobs.NotificationWork;
 import com.nextcloud.client.network.ClientFactory;
 import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
-import com.owncloud.android.jobs.NotificationJob;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -124,7 +124,7 @@ public class NotificationsActivity extends FileActivity implements Notifications
 
         // use account from intent (opened via android notification can have a different account than current one)
         if (getIntent() != null && getIntent().getExtras() != null) {
-            String accountName = getIntent().getExtras().getString(NotificationJob.KEY_NOTIFICATION_ACCOUNT);
+            String accountName = getIntent().getExtras().getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT);
             if(accountName != null && optionalUser.isPresent()) {
                 User user = optionalUser.get();
                 if (user.getAccountName().equalsIgnoreCase(accountName)) {

+ 3 - 2
src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java

@@ -4,6 +4,7 @@
  * @author Andy Scherzinger
  * Copyright (C) 2016 Andy Scherzinger
  * Copyright (C) 2016 Nextcloud
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -49,6 +50,7 @@ import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.jobs.MediaFoldersDetectionWork;
+import com.nextcloud.client.jobs.NotificationWork;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.java.util.Optional;
 import com.owncloud.android.BuildConfig;
@@ -63,7 +65,6 @@ import com.owncloud.android.datamodel.SyncedFolder;
 import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
 import com.owncloud.android.datamodel.SyncedFolderProvider;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.jobs.NotificationJob;
 import com.owncloud.android.ui.adapter.SyncedFolderAdapter;
 import com.owncloud.android.ui.decoration.MediaGridItemDecoration;
 import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
@@ -155,7 +156,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         ButterKnife.bind(this);
 
         if (getIntent() != null && getIntent().getExtras() != null) {
-            final String accountName = getIntent().getExtras().getString(NotificationJob.KEY_NOTIFICATION_ACCOUNT);
+            final String accountName = getIntent().getExtras().getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT);
             Optional<User> optionalUser = getUser();
             if (optionalUser.isPresent() && accountName != null) {
                 User user = optionalUser.get();