Browse Source

Migrated jobs to new user model

Signed-off-by: Chris Narkiewicz <hello@ezaquarii.com>
Chris Narkiewicz 5 years ago
parent
commit
0afc2645c4

+ 8 - 0
src/main/java/com/nextcloud/client/account/UserAccountManager.java

@@ -48,6 +48,14 @@ public interface UserAccountManager extends CurrentAccountProvider {
      */
     void removeAllAccounts();
 
+    /**
+     * Remove registered user.
+     *
+     * @param user user to remove
+     * @return true if account was removed successfully, false otherwise
+     */
+    boolean removeUser(User user);
+
     /**
      * Get configured NextCloud's user accounts.
      *

+ 16 - 0
src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java

@@ -23,6 +23,9 @@ package com.nextcloud.client.account;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.Activity;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
@@ -43,6 +46,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
 
+import java.io.IOException;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
@@ -81,6 +85,18 @@ public class UserAccountManagerImpl implements UserAccountManager {
         }
     }
 
+    @Override
+    public boolean removeUser(User user) {
+        try {
+            AccountManagerFuture<Boolean> result = accountManager.removeAccount(user.toPlatformAccount(),
+                                                                                null,
+                                                                                null);
+            return result.getResult();
+        } catch (OperationCanceledException| AuthenticatorException| IOException ex) {
+            return false;
+        }
+    }
+
     @Override
     @NonNull
     public Account[] getAccounts() {

+ 8 - 0
src/main/java/com/nextcloud/client/di/AppModule.java

@@ -52,6 +52,8 @@ import com.owncloud.android.ui.activities.data.files.FilesRepository;
 import com.owncloud.android.ui.activities.data.files.FilesServiceApiImpl;
 import com.owncloud.android.ui.activities.data.files.RemoteFilesRepository;
 
+import org.greenrobot.eventbus.EventBus;
+
 import java.io.File;
 
 import javax.inject.Singleton;
@@ -164,4 +166,10 @@ class AppModule {
     AudioManager audioManager(Context context) {
         return (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
     }
+
+    @Provides
+    @Singleton
+    EventBus eventBus() {
+        return EventBus.getDefault();
+    }
 }

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

@@ -84,6 +84,7 @@ import com.owncloud.android.utils.ReceiversHelper;
 import com.owncloud.android.utils.SecurityUtils;
 
 import org.conscrypt.Conscrypt;
+import org.greenrobot.eventbus.EventBus;
 
 import java.lang.reflect.Method;
 import java.security.NoSuchAlgorithmException;
@@ -166,6 +167,9 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
     @Inject
     Clock clock;
 
+    @Inject
+    EventBus eventBus;
+
     private PassCodeManager passCodeManager;
 
     @SuppressWarnings("unused")
@@ -274,7 +278,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
                 uploadsStorageManager,
                 connectivityService,
                 powerManagementService,
-                clock
+                clock,
+                eventBus
             )
         );
 

+ 82 - 81
src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java

@@ -26,8 +26,6 @@ package com.owncloud.android.jobs;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
@@ -37,9 +35,11 @@ import android.text.TextUtils;
 import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.google.gson.Gson;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.preferences.AppPreferencesImpl;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
@@ -51,6 +51,7 @@ import com.owncloud.android.datamodel.SyncedFolderProvider;
 import com.owncloud.android.datamodel.UploadsStorageManager;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManager;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.users.RemoteWipeSuccessRemoteOperation;
@@ -75,7 +76,7 @@ import static com.owncloud.android.ui.activity.ManageAccountsActivity.PENDING_FO
 /**
  * Removes account and all local files
  */
-public class AccountRemovalJob extends Job implements AccountManagerCallback<Boolean> {
+public class AccountRemovalJob extends Job {
     public static final String TAG = "AccountRemovalJob";
     public static final String ACCOUNT = "account";
     public static final String REMOTE_WIPE = "remote_wipe";
@@ -83,11 +84,16 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
     private final UploadsStorageManager uploadsStorageManager;
     private final UserAccountManager userAccountManager;
     private final Clock clock;
+    private final EventBus eventBus;
 
-    public AccountRemovalJob(UploadsStorageManager uploadStorageManager, UserAccountManager accountManager, Clock clock) {
+    public AccountRemovalJob(UploadsStorageManager uploadStorageManager,
+                             UserAccountManager accountManager,
+                             Clock clock,
+                             EventBus eventBus) {
         this.uploadsStorageManager = uploadStorageManager;
         this.userAccountManager = accountManager;
         this.clock = clock;
+        this.eventBus = eventBus;
     }
 
     @NonNull
@@ -95,80 +101,96 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
     protected Result onRunJob(@NonNull Params params) {
         Context context = MainApp.getAppContext();
         PersistableBundleCompat bundle = params.getExtras();
-        Account account = userAccountManager.getAccountByName(bundle.getString(ACCOUNT, ""));
+        String accountName = bundle.getString(ACCOUNT, "");
+        if (TextUtils.isEmpty(accountName)) {
+            // didn't receive account to delete
+            return Result.FAILURE;
+        }
+        Optional<User> optionalUser = userAccountManager.getUser(accountName);
+        if (!optionalUser.isPresent()) {
+            // trying to delete non-existing user
+            return Result.FAILURE;
+        }
         AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
+        if (accountManager == null) {
+            return Result.FAILURE;
+        }
         boolean remoteWipe = bundle.getBoolean(REMOTE_WIPE, false);
 
-        if (account != null && accountManager != null) {
-            ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
+        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
 
-            // disable contact backup job
-            ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);
+        User user = optionalUser.get();
+        // disable contact backup job
+        ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, user.toPlatformAccount());
 
-            removeAccount(account, accountManager);
+        final boolean userRemoved = userAccountManager.removeUser(user);
+        if (userRemoved) {
+            eventBus.post(new AccountRemovedEvent());
+        }
 
-            FileDataStorageManager storageManager = new FileDataStorageManager(account, context.getContentResolver());
+        FileDataStorageManager storageManager = new FileDataStorageManager(user.toPlatformAccount(), context.getContentResolver());
 
-            // remove all files
-            removeFiles(account, storageManager);
+        // remove all files
+        removeFiles(user, storageManager);
 
-            // delete all database entries
-            storageManager.deleteAllFiles();
+        // delete all database entries
+        storageManager.deleteAllFiles();
 
-            // remove contact backup job
-            ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);
+        // remove contact backup job
+        ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, user);
 
-            // disable daily backup
-            arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
-                                                        ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
-                                                        "false");
+        // disable daily backup
+        arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
+                                                    ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
+                                                    "false");
 
-            // unregister push notifications
-            unregisterPushNotifications(context, account, arbitraryDataProvider);
+        // unregister push notifications
+        unregisterPushNotifications(context, user, arbitraryDataProvider);
 
-            // remove pending account removal
-            arbitraryDataProvider.deleteKeyForAccount(account.name, PENDING_FOR_REMOVAL);
+        // remove pending account removal
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), PENDING_FOR_REMOVAL);
 
-            // remove synced folders set for account
-            remoceSyncedFolders(context, account, clock);
+        // remove synced folders set for account
+        remoceSyncedFolders(context, user.toPlatformAccount(), clock);
 
-            // delete all uploads for account
-            uploadsStorageManager.removeAccountUploads(account);
+        // delete all uploads for account
+        uploadsStorageManager.removeAccountUploads(user.toPlatformAccount());
 
-            // delete stored E2E keys
-            arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PRIVATE_KEY);
-            arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PUBLIC_KEY);
+        // delete stored E2E keys
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PRIVATE_KEY);
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PUBLIC_KEY);
 
-            OwnCloudClient client = createClient(account);
-            if (remoteWipe && client != null) {
+        if (remoteWipe) {
+            Optional<OwnCloudClient> optionalClient = createClient(user);
+            if (optionalClient.isPresent()) {
+                OwnCloudClient client = optionalClient.get();
                 String authToken = client.getCredentials().getAuthToken();
                 new RemoteWipeSuccessRemoteOperation(authToken).execute(client);
             }
+        }
 
-            // notify Document Provider
-            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-                String authority = context.getResources().getString(R.string.document_provider_authority);
-                Uri rootsUri = DocumentsContract.buildRootsUri(authority);
-                context.getContentResolver().notifyChange(rootsUri, null);
-            }
-
-            return Result.SUCCESS;
-        } else {
-            return Result.FAILURE;
+        // notify Document Provider
+        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            String authority = context.getResources().getString(R.string.document_provider_authority);
+            Uri rootsUri = DocumentsContract.buildRootsUri(authority);
+            context.getContentResolver().notifyChange(rootsUri, null);
         }
-    }
 
-    private void unregisterPushNotifications(Context context, Account account, ArbitraryDataProvider arbitraryDataProvider) {
-        String arbitraryDataPushString;
+        return Result.SUCCESS;
+    }
 
-        if (!TextUtils.isEmpty(arbitraryDataPushString = arbitraryDataProvider.getValue(
-            account, PushUtils.KEY_PUSH)) &&
-            !TextUtils.isEmpty(context.getResources().getString(R.string.push_server_url))) {
+    private void unregisterPushNotifications(Context context,
+                                             User user,
+                                             ArbitraryDataProvider arbitraryDataProvider) {
+        final String arbitraryDataPushString = arbitraryDataProvider.getValue(user.toPlatformAccount(),
+                                                                              PushUtils.KEY_PUSH);
+        final String pushServerUrl = context.getResources().getString(R.string.push_server_url);
+        if (!TextUtils.isEmpty(arbitraryDataPushString) && !TextUtils.isEmpty(pushServerUrl)) {
             Gson gson = new Gson();
             PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
                                                                      PushConfigurationState.class);
             pushArbitraryData.setShouldBeDeleted(true);
-            arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
+            arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), PushUtils.KEY_PUSH,
                                                         gson.toJson(pushArbitraryData));
 
             PushUtils.pushRegistrationToServer(userAccountManager, pushArbitraryData.getPushToken());
@@ -198,44 +220,23 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
         }
     }
 
-    private void removeFiles(Account account, FileDataStorageManager storageManager) {
-        File tempDir = new File(FileStorageUtils.getTemporalPath(account.name));
-        File saveDir = new File(FileStorageUtils.getSavePath(account.name));
+    private void removeFiles(User user, FileDataStorageManager storageManager) {
+        File tempDir = new File(FileStorageUtils.getTemporalPath(user.getAccountName()));
+        File saveDir = new File(FileStorageUtils.getSavePath(user.getAccountName()));
 
         FileStorageUtils.deleteRecursively(tempDir, storageManager);
         FileStorageUtils.deleteRecursively(saveDir, storageManager);
     }
 
-    private void removeAccount(Account account, AccountManager accountManager) {
-        try {
-            AccountManagerFuture<Boolean> accountRemoval = accountManager.removeAccount(account, this, null);
-            boolean removal = accountRemoval.getResult();
-
-            if (!removal) {
-                Log_OC.e(this, "Account removal of " + account.name + " failed!");
-            }
-        } catch (Exception e) {
-            Log_OC.e(this, "Account removal of " + account.name + " failed!", e);
-        }
-    }
-
-    @Nullable
-    private OwnCloudClient createClient(Account account) {
-        OwnCloudClient client = null;
+    private Optional<OwnCloudClient> createClient(User user) {
         try {
-            OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
-            client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount,
-                                                                                     MainApp.getAppContext());
+            Context context = MainApp.getAppContext();
+            OwnCloudClientManager factory = OwnCloudClientManagerFactory.getDefaultSingleton();
+            OwnCloudClient client = factory.getClientFor(user.toOwnCloudAccount(), context);
+            return Optional.of(client);
         } catch (Exception e) {
             Log_OC.e(this, "Could not create client", e);
-        }
-        return client;
-    }
-
-    @Override
-    public void run(AccountManagerFuture<Boolean> future) {
-        if (future.isDone()) {
-            EventBus.getDefault().post(new AccountRemovedEvent());
+            return Optional.empty();
         }
     }
 }

+ 27 - 16
src/main/java/com/owncloud/android/jobs/ContactsBackupJob.java

@@ -21,7 +21,6 @@
 
 package com.owncloud.android.jobs;
 
-import android.accounts.Account;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.ServiceConnection;
@@ -29,11 +28,14 @@ import android.database.Cursor;
 import android.net.Uri;
 import android.os.IBinder;
 import android.provider.ContactsContract;
+import android.text.TextUtils;
 import android.text.format.DateFormat;
 
 import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -80,14 +82,20 @@ public class ContactsBackupJob extends Job {
     protected Result onRunJob(@NonNull Params params) {
         PersistableBundleCompat bundle = params.getExtras();
 
-        final Account account = accountManager.getAccountByName(bundle.getString(ACCOUNT, ""));
-
-        if (account == null) {
+        final String accountName = bundle.getString(ACCOUNT, "");
+        if (TextUtils.isEmpty(accountName)) {
+            // no account provided
+            return Result.FAILURE;
+        }
+        final Optional<User> optionalUser = accountManager.getUser(accountName);
+        if (!optionalUser.isPresent()) {
             return Result.FAILURE;
         }
+        User user = optionalUser.get();
 
         ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContext().getContentResolver());
-        Long lastExecution = arbitraryDataProvider.getLongValue(account, PREFERENCE_CONTACTS_LAST_BACKUP);
+        Long lastExecution = arbitraryDataProvider.getLongValue(user.toPlatformAccount(),
+                                                                PREFERENCE_CONTACTS_LAST_BACKUP);
 
         boolean force = bundle.getBoolean(FORCE, false);
         if (force || (lastExecution + 24 * 60 * 60 * 1000) < Calendar.getInstance().getTimeInMillis()) {
@@ -97,16 +105,18 @@ public class ContactsBackupJob extends Job {
                     OCFile.PATH_SEPARATOR;
             Integer daysToExpire = getContext().getResources().getInteger(R.integer.contacts_backup_expire);
 
-            backupContact(account, backupFolder);
+            backupContact(user, backupFolder);
 
             // bind to Operations Service
-            operationsServiceConnection = new OperationsServiceConnection(daysToExpire, backupFolder, account);
+            operationsServiceConnection = new OperationsServiceConnection(daysToExpire,
+                                                                          backupFolder,
+                                                                          user);
 
             getContext().bindService(new Intent(getContext(), OperationsService.class), operationsServiceConnection,
                     OperationsService.BIND_AUTO_CREATE);
 
             // store execution date
-            arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
+            arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
                                                         PREFERENCE_CONTACTS_LAST_BACKUP,
                                                         Calendar.getInstance().getTimeInMillis());
         } else {
@@ -116,7 +126,7 @@ public class ContactsBackupJob extends Job {
         return Result.SUCCESS;
     }
 
-    private void backupContact(Account account, String backupFolder) {
+    private void backupContact(User user, String backupFolder) {
         ArrayList<String> vCard = new ArrayList<>();
 
         Cursor cursor = getContext().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,
@@ -162,7 +172,7 @@ public class ContactsBackupJob extends Job {
         FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
         requester.uploadNewFile(
                 getContext(),
-                account,
+                user.toPlatformAccount(),
                 file.getAbsolutePath(),
                 backupFolder + filename,
                 FileUploader.LOCAL_BEHAVIOUR_MOVE,
@@ -174,10 +184,11 @@ public class ContactsBackupJob extends Job {
         );
     }
 
-    private void expireFiles(Integer daysToExpire, String backupFolderString, Account account) {
+    private void expireFiles(Integer daysToExpire, String backupFolderString, User account) {
         // -1 disables expiration
         if (daysToExpire > -1) {
-            FileDataStorageManager storageManager = new FileDataStorageManager(account, getContext().getContentResolver());
+            FileDataStorageManager storageManager = new FileDataStorageManager(account.toPlatformAccount(),
+                                                                               getContext().getContentResolver());
             OCFile backupFolder = storageManager.getFileByPath(backupFolderString);
             Calendar cal = Calendar.getInstance();
             cal.add(Calendar.DAY_OF_YEAR, -daysToExpire);
@@ -261,12 +272,12 @@ public class ContactsBackupJob extends Job {
     private class OperationsServiceConnection implements ServiceConnection {
         private Integer daysToExpire;
         private String backupFolder;
-        private Account account;
+        private User user;
 
-        OperationsServiceConnection(Integer daysToExpire, String backupFolder, Account account) {
+        OperationsServiceConnection(Integer daysToExpire, String backupFolder, User user) {
             this.daysToExpire = daysToExpire;
             this.backupFolder = backupFolder;
-            this.account = account;
+            this.user = user;
         }
 
         @Override
@@ -276,7 +287,7 @@ public class ContactsBackupJob extends Job {
 
             if (component.equals(new ComponentName(getContext(), OperationsService.class))) {
                 operationsServiceBinder = (OperationsService.OperationsServiceBinder) service;
-                expireFiles(daysToExpire, backupFolder, account);
+                expireFiles(daysToExpire, backupFolder, user);
             }
         }
 

+ 11 - 7
src/main/java/com/owncloud/android/jobs/FilesSyncJob.java

@@ -23,7 +23,6 @@
 
 package com.owncloud.android.jobs;
 
-import android.accounts.Account;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
@@ -33,11 +32,13 @@ import android.text.TextUtils;
 
 import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
@@ -167,7 +168,12 @@ public class FilesSyncJob extends Job {
         boolean needsWifi;
         File file;
         ArbitraryDataProvider arbitraryDataProvider;
-        Account account = userAccountManager.getAccountByName(syncedFolder.getAccount());
+        String accountName = syncedFolder.getAccount();
+        Optional<User> optionalUser = userAccountManager.getUser(accountName);
+        if (!optionalUser.isPresent()) {
+            return;
+        }
+        User user = optionalUser.get();
 
         if (lightVersion) {
             arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
@@ -183,13 +189,11 @@ public class FilesSyncJob extends Job {
 
             if (lightVersion) {
                 needsCharging = resources.getBoolean(R.bool.syncedFolder_light_on_charging);
-                needsWifi = account == null || arbitraryDataProvider.getBooleanValue(account.name,
-                                                                                     SettingsActivity.SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI);
+                needsWifi = arbitraryDataProvider.getBooleanValue(accountName,
+                                                                  SettingsActivity.SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI);
                 String uploadActionString = resources.getString(R.string.syncedFolder_light_upload_behaviour);
                 uploadAction = getUploadAction(uploadActionString);
-
                 subfolderByDate = resources.getBoolean(R.bool.syncedFolder_light_use_subfolders);
-
                 remotePath = resources.getString(R.string.syncedFolder_remote_folder);
             } else {
                 needsCharging = syncedFolder.isChargingOnly();
@@ -201,7 +205,7 @@ public class FilesSyncJob extends Job {
 
             requester.uploadFileWithOverwrite(
                     context,
-                    account,
+                    user.toPlatformAccount(),
                     file.getAbsolutePath(),
                     FileStorageUtils.getInstantUploadFilePath(
                         file,

+ 32 - 23
src/main/java/com/owncloud/android/jobs/MediaFoldersDetectionJob.java

@@ -23,8 +23,6 @@
  */
 package com.owncloud.android.jobs;
 
-
-import android.accounts.Account;
 import android.app.Activity;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -38,6 +36,7 @@ import android.text.TextUtils;
 
 import com.evernote.android.job.Job;
 import com.google.gson.Gson;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.preferences.AppPreferences;
@@ -47,6 +46,7 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.MediaFolder;
 import com.owncloud.android.datamodel.MediaFoldersModel;
 import com.owncloud.android.datamodel.MediaProvider;
+import com.owncloud.android.datamodel.SyncedFolder;
 import com.owncloud.android.datamodel.SyncedFolderProvider;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.ManageAccountsActivity;
@@ -138,32 +138,41 @@ public class MediaFoldersDetectionJob extends Job {
                 videoMediaFolderPaths.removeAll(mediaFoldersModel.getVideoMediaFolders());
 
                 if (!imageMediaFolderPaths.isEmpty() || !videoMediaFolderPaths.isEmpty()) {
-                    Account[] accounts = userAccountManager.getAccounts();
-                    List<Account> accountList = new ArrayList<>();
-                    for (Account account : accounts) {
-                        if (!arbitraryDataProvider.getBooleanValue(account, ManageAccountsActivity.PENDING_FOR_REMOVAL)) {
-                            accountList.add(account);
+                    List<User> allUsers = userAccountManager.getAllUsers();
+                    List<User> activeUsers = new ArrayList<>();
+                    for (User account : allUsers) {
+                        if (!arbitraryDataProvider.getBooleanValue(account.toPlatformAccount(),
+                                                                   ManageAccountsActivity.PENDING_FOR_REMOVAL)) {
+                            activeUsers.add(account);
                         }
                     }
 
-                    for (Account account : accountList) {
+                    for (User user : activeUsers) {
                         for (String imageMediaFolder : imageMediaFolderPaths) {
-                            if (syncedFolderProvider.findByLocalPathAndAccount(imageMediaFolder, account) == null) {
-                                sendNotification(String.format(context.getString(R.string.new_media_folder_detected),
-                                    context.getString(R.string.new_media_folder_photos)),
-                                    imageMediaFolder.substring(imageMediaFolder.lastIndexOf('/') + 1
-                                    ),
-                                    account, imageMediaFolder, 1);
+                            final SyncedFolder folder = syncedFolderProvider.findByLocalPathAndAccount(imageMediaFolder,
+                                                                                                       user.toPlatformAccount());
+                            if (folder == null) {
+                                String contentTitle = String.format(context.getString(R.string.new_media_folder_detected),
+                                                                    context.getString(R.string.new_media_folder_photos));
+                                sendNotification(contentTitle,
+                                                imageMediaFolder.substring(imageMediaFolder.lastIndexOf('/') + 1),
+                                                user,
+                                                imageMediaFolder,
+                                                 1);
                             }
                         }
 
                         for (String videoMediaFolder : videoMediaFolderPaths) {
-                            if (syncedFolderProvider.findByLocalPathAndAccount(videoMediaFolder, account) == null) {
-                                sendNotification(String.format(context.getString(R.string.new_media_folder_detected),
-                                    context.getString(R.string.new_media_folder_videos)),
-                                    videoMediaFolder.substring(videoMediaFolder.lastIndexOf('/') + 1
-                                    ),
-                                    account, videoMediaFolder, 2);
+                            final SyncedFolder folder = syncedFolderProvider.findByLocalPathAndAccount(videoMediaFolder,
+                                                                                                       user.toPlatformAccount());
+                            if (folder == null) {
+                                String contentTitle = String.format(context.getString(R.string.new_media_folder_detected),
+                                                                    context.getString(R.string.new_media_folder_videos));
+                                sendNotification(contentTitle,
+                                                 videoMediaFolder.substring(videoMediaFolder.lastIndexOf('/') + 1),
+                                                 user,
+                                                 videoMediaFolder,
+                                                 2);
                             }
                         }
                     }
@@ -179,14 +188,14 @@ public class MediaFoldersDetectionJob extends Job {
         return Result.SUCCESS;
     }
 
-    private void sendNotification(String contentTitle, String subtitle, Account account, String path, int type) {
+    private void sendNotification(String contentTitle, String subtitle, User user, String path, int type) {
         int notificationId = randomId.nextInt();
 
         Context context = getContext();
         Intent intent = new Intent(getContext(), SyncedFoldersActivity.class);
         intent.putExtra(NOTIFICATION_ID, notificationId);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        intent.putExtra(NotificationJob.KEY_NOTIFICATION_ACCOUNT, account.name);
+        intent.putExtra(NotificationJob.KEY_NOTIFICATION_ACCOUNT, user.getAccountName());
         intent.putExtra(KEY_MEDIA_FOLDER_PATH, path);
         intent.putExtra(KEY_MEDIA_FOLDER_TYPE, type);
         intent.putExtra(SyncedFoldersActivity.EXTRA_SHOW_SIDEBAR, true);
@@ -197,7 +206,7 @@ public class MediaFoldersDetectionJob extends Job {
             .setSmallIcon(R.drawable.notification_icon)
             .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon))
             .setColor(ThemeUtils.primaryColor(getContext()))
-            .setSubText(account.name)
+            .setSubText(user.getAccountName())
             .setContentTitle(contentTitle)
             .setContentText(subtitle)
             .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))

+ 7 - 2
src/main/java/com/owncloud/android/jobs/NCJobCreator.java

@@ -35,6 +35,8 @@ import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.datamodel.UploadsStorageManager;
 
+import org.greenrobot.eventbus.EventBus;
+
 import androidx.annotation.NonNull;
 
 /**
@@ -50,6 +52,7 @@ public class NCJobCreator implements JobCreator {
     private final ConnectivityService connectivityService;
     private final PowerManagementService powerManagementService;
     private final Clock clock;
+    private final EventBus eventBus;
 
     public NCJobCreator(
         Context context,
@@ -58,7 +61,8 @@ public class NCJobCreator implements JobCreator {
         UploadsStorageManager uploadsStorageManager,
         ConnectivityService connectivityServices,
         PowerManagementService powerManagementService,
-        Clock clock
+        Clock clock,
+        EventBus eventBus
     ) {
         this.context = context;
         this.accountManager = accountManager;
@@ -67,6 +71,7 @@ public class NCJobCreator implements JobCreator {
         this.connectivityService = connectivityServices;
         this.powerManagementService = powerManagementService;
         this.clock = clock;
+        this.eventBus = eventBus;
     }
 
     @Override
@@ -77,7 +82,7 @@ public class NCJobCreator implements JobCreator {
             case ContactsImportJob.TAG:
                 return new ContactsImportJob();
             case AccountRemovalJob.TAG:
-                return new AccountRemovalJob(uploadsStorageManager, accountManager, clock);
+                return new AccountRemovalJob(uploadsStorageManager, accountManager, clock, eventBus);
             case FilesSyncJob.TAG:
                 return new FilesSyncJob(accountManager,
                                         preferences,

+ 23 - 24
src/main/java/com/owncloud/android/jobs/NotificationJob.java

@@ -22,7 +22,6 @@
 
 package com.owncloud.android.jobs;
 
-import android.accounts.Account;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
@@ -42,11 +41,12 @@ import android.util.Log;
 import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.google.gson.Gson;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.DecryptedPushMessage;
 import com.owncloud.android.datamodel.SignatureVerification;
-import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -140,7 +140,9 @@ public class NotificationJob extends Job {
                         } else if (decryptedPushMessage.deleteAll) {
                             notificationManager.cancelAll();
                         } else {
-                            fetchCompleteNotification(signatureVerification.getAccount(), decryptedPushMessage);
+                            final User user = accountManager.getUser(signatureVerification.getAccount().name)
+                                    .orElseThrow(RuntimeException::new);
+                            fetchCompleteNotification(user, decryptedPushMessage);
                         }
                     }
                 } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e1) {
@@ -154,7 +156,7 @@ public class NotificationJob extends Job {
         return Result.SUCCESS;
     }
 
-    private void sendNotification(Notification notification, Account account) {
+    private void sendNotification(Notification notification, User user) {
         SecureRandom randomId = new SecureRandom();
         RichObject file = notification.subjectRichParameters.get("file");
 
@@ -166,7 +168,7 @@ public class NotificationJob extends Job {
             intent.setAction(Intent.ACTION_VIEW);
             intent.putExtra(FileDisplayActivity.KEY_FILE_ID, file.id);
         }
-        intent.putExtra(KEY_NOTIFICATION_ACCOUNT, account.name);
+        intent.putExtra(KEY_NOTIFICATION_ACCOUNT, user.getAccountName());
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
         PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
@@ -176,9 +178,9 @@ public class NotificationJob extends Job {
             new NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH)
                 .setSmallIcon(R.drawable.notification_icon)
                 .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon))
-                .setColor(ThemeUtils.primaryColor(account, false, context))
+                .setColor(ThemeUtils.primaryColor(user.toPlatformAccount(), false, context))
                 .setShowWhen(true)
-                .setSubText(account.name)
+                .setSubText(user.getAccountName())
                 .setContentTitle(notification.getSubject())
                 .setContentText(notification.getMessage())
                 .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
@@ -191,7 +193,7 @@ public class NotificationJob extends Job {
             Intent disableDetection = new Intent(context, NotificationJob.NotificationReceiver.class);
             disableDetection.putExtra(NUMERIC_NOTIFICATION_ID, notification.getNotificationId());
             disableDetection.putExtra(PUSH_NOTIFICATION_ID, pushNotificationId);
-            disableDetection.putExtra(KEY_NOTIFICATION_ACCOUNT, account.name);
+            disableDetection.putExtra(KEY_NOTIFICATION_ACCOUNT, user.getAccountName());
 
             PendingIntent disableIntent = PendingIntent.getBroadcast(context, pushNotificationId, disableDetection,
                                                                      PendingIntent.FLAG_CANCEL_CURRENT);
@@ -204,7 +206,7 @@ public class NotificationJob extends Job {
                 Intent actionIntent = new Intent(context, NotificationJob.NotificationReceiver.class);
                 actionIntent.putExtra(NUMERIC_NOTIFICATION_ID, notification.getNotificationId());
                 actionIntent.putExtra(PUSH_NOTIFICATION_ID, pushNotificationId);
-                actionIntent.putExtra(KEY_NOTIFICATION_ACCOUNT, account.name);
+                actionIntent.putExtra(KEY_NOTIFICATION_ACCOUNT, user.getAccountName());
                 actionIntent.putExtra(KEY_NOTIFICATION_ACTION_LINK, action.link);
                 actionIntent.putExtra(KEY_NOTIFICATION_ACTION_TYPE, action.type);
 
@@ -228,9 +230,9 @@ public class NotificationJob extends Job {
             new NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH)
                 .setSmallIcon(R.drawable.notification_icon)
                 .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon))
-                .setColor(ThemeUtils.primaryColor(account, false, context))
+                .setColor(ThemeUtils.primaryColor(user.toPlatformAccount(), false, context))
                 .setShowWhen(true)
-                .setSubText(account.name)
+                .setSubText(user.getAccountName())
                 .setContentTitle(context.getString(R.string.new_notification))
                 .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                 .setAutoCancel(true)
@@ -241,18 +243,18 @@ public class NotificationJob extends Job {
         notificationManager.notify(notification.getNotificationId(), notificationBuilder.build());
     }
 
-    private void fetchCompleteNotification(Account account, DecryptedPushMessage decryptedPushMessage) {
-        Account currentAccount = accountManager.getAccountByName(account.name);
+    private void fetchCompleteNotification(User account, DecryptedPushMessage decryptedPushMessage) {
+        Optional<User> optionalUser = accountManager.getUser(account.getAccountName());
 
-        if (currentAccount == null) {
+        if (!optionalUser.isPresent()) {
             Log_OC.e(this, "Account may not be null");
             return;
         }
+        User user = optionalUser.get();
 
         try {
-            OwnCloudAccount ocAccount = new OwnCloudAccount(currentAccount, context);
             OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton()
-                .getClientFor(ocAccount, context);
+                .getClientFor(user.toOwnCloudAccount(), context);
 
             RemoteOperationResult result = new GetNotificationRemoteOperation(decryptedPushMessage.nid)
                 .execute(client);
@@ -295,16 +297,14 @@ public class NotificationJob extends Job {
                     }
 
                     try {
-                        Account currentAccount = accountManager.getAccountByName(accountName);
-
-                        if (currentAccount == null) {
+                        Optional<User> optionalUser = accountManager.getUser(accountName);
+                        if (!optionalUser.isPresent()) {
                             Log_OC.e(this, "Account may not be null");
                             return;
                         }
-
-                        OwnCloudAccount ocAccount = new OwnCloudAccount(currentAccount, context);
+                        User user = optionalUser.get();
                         OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton()
-                            .getClientFor(ocAccount, context);
+                            .getClientFor(user.toOwnCloudAccount(), context);
 
                         String actionType = intent.getStringExtra(KEY_NOTIFICATION_ACTION_TYPE);
                         String actionLink = intent.getStringExtra(KEY_NOTIFICATION_ACTION_LINK);
@@ -325,8 +325,7 @@ public class NotificationJob extends Job {
                         } else if (notificationManager != null) {
                             notificationManager.notify(numericNotificationId, oldNotification);
                         }
-                    } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException |
-                        IOException | OperationCanceledException | AuthenticatorException e) {
+                    } catch (IOException | OperationCanceledException | AuthenticatorException e) {
                         Log_OC.e(TAG, "Error initializing client", e);
                     }
                 }).start();

+ 11 - 10
src/main/java/com/owncloud/android/jobs/OfflineSyncJob.java

@@ -21,7 +21,6 @@
  */
 package com.owncloud.android.jobs;
 
-import android.accounts.Account;
 import android.content.Context;
 import android.os.Build;
 import android.os.PowerManager;
@@ -29,6 +28,7 @@ import android.os.PowerManager;
 import com.evernote.android.job.Job;
 import com.evernote.android.job.JobManager;
 import com.evernote.android.job.JobRequest;
+import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.network.ConnectivityService;
@@ -42,6 +42,7 @@ import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 
 import java.io.File;
+import java.util.List;
 import java.util.Set;
 
 import androidx.annotation.NonNull;
@@ -89,10 +90,10 @@ public class OfflineSyncJob extends Job {
                 }
             }
 
-            Account[] accounts = userAccountManager.getAccounts();
+            List<User> users = userAccountManager.getAllUsers();
 
-            for (Account account : accounts) {
-                FileDataStorageManager storageManager = new FileDataStorageManager(account,
+            for (User user : users) {
+                FileDataStorageManager storageManager = new FileDataStorageManager(user.toPlatformAccount(),
                         getContext().getContentResolver());
 
                 OCFile ocRoot = storageManager.getFileByPath(ROOT_PATH);
@@ -101,7 +102,7 @@ public class OfflineSyncJob extends Job {
                     break;
                 }
 
-                recursive(new File(ocRoot.getStoragePath()), storageManager, account);
+                recursive(new File(ocRoot.getStoragePath()), storageManager, user);
             }
 
             if (wakeLock != null) {
@@ -112,8 +113,8 @@ public class OfflineSyncJob extends Job {
         return Result.SUCCESS;
     }
 
-    private void recursive(File folder, FileDataStorageManager storageManager, Account account) {
-        String downloadFolder = FileStorageUtils.getSavePath(account.name);
+    private void recursive(File folder, FileDataStorageManager storageManager, User user) {
+        String downloadFolder = FileStorageUtils.getSavePath(user.getAccountName());
         String folderName = folder.getAbsolutePath().replaceFirst(downloadFolder, "") + PATH_SEPARATOR;
         Log_OC.d(TAG, folderName + ": enter");
 
@@ -128,7 +129,7 @@ public class OfflineSyncJob extends Job {
         // check for etag change, if false, skip
         CheckEtagRemoteOperation checkEtagOperation = new CheckEtagRemoteOperation(ocFolder.getRemotePath(),
                                                                                    ocFolder.getEtagOnServer());
-        RemoteOperationResult result = checkEtagOperation.execute(account, getContext());
+        RemoteOperationResult result = checkEtagOperation.execute(user.toPlatformAccount(), getContext());
 
         // eTag changed, sync file
         switch (result.getCode()) {
@@ -156,7 +157,7 @@ public class OfflineSyncJob extends Job {
             for (File file : files) {
                 OCFile ocFile = storageManager.getFileByLocalPath(file.getPath());
                 SynchronizeFileOperation synchronizeFileOperation = new SynchronizeFileOperation(ocFile.getRemotePath(),
-                        account, true, getContext());
+                        user.toPlatformAccount(), true, getContext());
 
                 synchronizeFileOperation.execute(storageManager, getContext());
             }
@@ -167,7 +168,7 @@ public class OfflineSyncJob extends Job {
 
         if (subfolders != null) {
             for (File subfolder : subfolders) {
-                recursive(subfolder, storageManager, account);
+                recursive(subfolder, storageManager, user);
             }
         }
 

+ 6 - 0
src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java

@@ -29,6 +29,7 @@ import android.os.Bundle;
 import com.evernote.android.job.JobManager;
 import com.evernote.android.job.JobRequest;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
+import com.nextcloud.client.account.User;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
@@ -133,6 +134,11 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
         }
     }
 
+    public static void cancelContactBackupJobForAccount(Context context, User user) {
+        cancelContactBackupJobForAccount(context, user.toPlatformAccount());
+    }
+
+    @Deprecated
     public static void cancelContactBackupJobForAccount(Context context, Account account) {
         Log_OC.d(TAG, "disabling contacts backup job for account: " + account.name);