diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java index 7266894c6e..4f4baef713 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java @@ -20,6 +20,7 @@ package com.nextcloud.client.preferences; +import com.nextcloud.client.account.User; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.utils.FileSortOrder; @@ -377,4 +378,10 @@ public interface AppPreferences { boolean isStoragePermissionRequested(); void setStoragePermissionRequested(boolean value); + + boolean isContactsBackupEnabled(final User user); + void setContactsBackupEnabled(final User user, final boolean value); + + boolean isCalendarBackupEnabled(final User user); + void setCalendarBackupEnabled(final User user, final boolean value); } diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java index 6754c379c7..5ab0d1de8b 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -24,6 +24,7 @@ package com.nextcloud.client.preferences; import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; +import android.net.Uri; import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; @@ -99,6 +100,9 @@ public final class AppPreferencesImpl implements AppPreferences { private static final String PREF__STORAGE_PERMISSION_REQUESTED = "storage_permission_requested"; + private static final String PREF__CALENDAR_BACKUP_ENABLED = "calendar_backup_enabled"; + private static final String PREF__CONTACTS_BACKUP_ENABLED = "contacts_backup_enabled"; + private final Context context; private final SharedPreferences preferences; private final CurrentAccountProvider currentAccountProvider; @@ -164,6 +168,10 @@ public final class AppPreferencesImpl implements AppPreferences { this.preferences.registerOnSharedPreferenceChangeListener(listeners); } + private String getUserScopedKey(final User user, final String originalKey) { + return Uri.encode(user.getAccountName()) + "__" + originalKey; + } + @Override public void addListener(@Nullable AppPreferences.Listener listener) { this.listeners.add(listener); @@ -708,6 +716,30 @@ public final class AppPreferencesImpl implements AppPreferences { preferences.edit().putBoolean(PREF__STORAGE_PERMISSION_REQUESTED, value).apply(); } + @Override + public boolean isContactsBackupEnabled(final User user) { + final String key = getUserScopedKey(user, PREF__CONTACTS_BACKUP_ENABLED); + return preferences.getBoolean(key, false); + } + + @Override + public void setContactsBackupEnabled(final User user, boolean value) { + final String key = getUserScopedKey(user, PREF__CONTACTS_BACKUP_ENABLED); + preferences.edit().putBoolean(key, value).apply(); + } + + @Override + public boolean isCalendarBackupEnabled(final User user) { + final String key = getUserScopedKey(user, PREF__CALENDAR_BACKUP_ENABLED); + return preferences.getBoolean(key, false); + } + + @Override + public void setCalendarBackupEnabled(final User user, boolean value) { + final String key = getUserScopedKey(user, PREF__CALENDAR_BACKUP_ENABLED); + preferences.edit().putBoolean(key, value).apply(); + } + @VisibleForTesting public int computeBruteForceDelay(int count) { return (int) Math.min(count / 3d, 10); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java index 9c70f5dea7..32cd8ff4a0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java @@ -37,6 +37,7 @@ import android.widget.Toast; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.BackgroundJobManager; +import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; import com.owncloud.android.R; import com.owncloud.android.databinding.BackupFragmentBinding; @@ -44,6 +45,7 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.ui.activity.ContactsPreferenceActivity; import com.owncloud.android.ui.activity.SettingsActivity; @@ -90,6 +92,8 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD @Inject ThemeUtils themeUtils; @Inject ThemeCheckableUtils themeCheckableUtils; @Inject ThemeButtonUtils themeButtonUtils; + @Inject ArbitraryDataProvider arbitraryDataProvider; + @Inject AppPreferences appPreferences; private Date selectedDate; private boolean calendarPickerOpen; @@ -99,7 +103,6 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD private CompoundButton.OnCheckedChangeListener dailyBackupCheckedChangeListener; private CompoundButton.OnCheckedChangeListener contactsCheckedListener; private CompoundButton.OnCheckedChangeListener calendarCheckedListener; - private ArbitraryDataProvider arbitraryDataProvider; private User user; private boolean showSidebar = true; @@ -111,6 +114,22 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD return fragment; } + private boolean isCalendarBackupEnabled() { + return appPreferences.isCalendarBackupEnabled(user); + } + + private void setCalendarBackupEnabled(final boolean enabled) { + appPreferences.setCalendarBackupEnabled(user, enabled); + } + + private boolean isContactsBackupEnabled() { + return appPreferences.isContactsBackupEnabled(user); + } + + private void setContactsBackupEnabled(final boolean enabled) { + appPreferences.setContactsBackupEnabled(user, enabled); + } + @Override public View onCreateView(@NonNull final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -140,7 +159,6 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD themeToolbarUtils.tintBackButton(actionBar, getContext()); } - arbitraryDataProvider = new ArbitraryDataProvider(getContext().getContentResolver()); themeCheckableUtils.tintSwitch(binding.contacts, themeColorUtils); themeCheckableUtils.tintSwitch(binding.calendar, themeColorUtils); @@ -148,46 +166,15 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD binding.dailyBackup.setChecked(arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)); - binding.contacts.setChecked(checkContactBackupPermission()); - binding.calendar.setChecked(checkCalendarBackupPermission(getContext())); + binding.contacts.setChecked(isContactsBackupEnabled() && checkContactBackupPermission()); + binding.calendar.setChecked(isCalendarBackupEnabled() && checkCalendarBackupPermission(getContext())); - dailyBackupCheckedChangeListener = (buttonView, isChecked) -> { - if (checkAndAskForContactsReadPermission()) { - setAutomaticBackup(isChecked); - } - }; - contactsCheckedListener = (buttonView, isChecked) -> { - if (isChecked) { - if (checkAndAskForContactsReadPermission()) { - binding.backupNow.setVisibility(View.VISIBLE); - } - } else { - if (!binding.calendar.isChecked()) { - binding.backupNow.setVisibility(View.INVISIBLE); - } - } - }; - binding.contacts.setOnCheckedChangeListener(contactsCheckedListener); + setupCheckListeners(); - calendarCheckedListener = (buttonView, isChecked) -> { - if (isChecked) { - if (checkAndAskForCalendarReadPermission()) { - binding.backupNow.setVisibility(View.VISIBLE); - } - } else { - if (!binding.contacts.isChecked()) { - binding.backupNow.setVisibility(View.INVISIBLE); - } - } - }; + setBackupNowButtonVisibility(); - binding.calendar.setOnCheckedChangeListener(calendarCheckedListener); - - binding.dailyBackup.setOnCheckedChangeListener(dailyBackupCheckedChangeListener); - binding.backupNow.setOnClickListener(v -> backup()); - binding.backupNow.setEnabled(checkBackupNowPermission()); - binding.backupNow.setVisibility(checkBackupNowPermission() ? View.VISIBLE : View.GONE); + binding.backupNow.setOnClickListener(v -> backupNow()); binding.contactsDatepicker.setOnClickListener(v -> openCleanDate()); @@ -222,6 +209,50 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD return view; } + private void setupCheckListeners() { + dailyBackupCheckedChangeListener = (buttonView, isChecked) -> { + if (checkAndAskForContactsReadPermission()) { + setAutomaticBackup(isChecked); + } + }; + binding.dailyBackup.setOnCheckedChangeListener(dailyBackupCheckedChangeListener); + + + contactsCheckedListener = (buttonView, isChecked) -> { + if (isChecked) { + if (checkAndAskForContactsReadPermission()) { + setContactsBackupEnabled(true); + } + } else { + setContactsBackupEnabled(false); + } + setBackupNowButtonVisibility(); + setAutomaticBackup(binding.dailyBackup.isChecked()); + }; + binding.contacts.setOnCheckedChangeListener(contactsCheckedListener); + + calendarCheckedListener = (buttonView, isChecked) -> { + if (isChecked) { + if (checkAndAskForCalendarReadPermission()) { + setCalendarBackupEnabled(true); + } + } else { + setCalendarBackupEnabled(false); + } + setBackupNowButtonVisibility(); + setAutomaticBackup(binding.dailyBackup.isChecked()); + }; + binding.calendar.setOnCheckedChangeListener(calendarCheckedListener); + } + + private void setBackupNowButtonVisibility() { + if (binding.contacts.isChecked() || binding.calendar.isChecked()) { + binding.backupNow.setVisibility(View.VISIBLE); + } else { + binding.backupNow.setVisibility(View.INVISIBLE); + } + } + @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -329,6 +360,7 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD if (Manifest.permission.READ_CONTACTS.equalsIgnoreCase(permissions[index])) { if (grantResults[index] >= 0) { // if approved, exit for loop + setContactsBackupEnabled(true); break; } @@ -355,21 +387,21 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD binding.calendar.setOnCheckedChangeListener(null); binding.calendar.setChecked(false); binding.calendar.setOnCheckedChangeListener(calendarCheckedListener); - - binding.backupNow.setVisibility(checkBackupNowPermission() ? View.VISIBLE : View.GONE); + } else { + setCalendarBackupEnabled(true); } } - binding.backupNow.setVisibility(checkBackupNowPermission() ? View.VISIBLE : View.GONE); - binding.backupNow.setEnabled(checkBackupNowPermission()); + setBackupNowButtonVisibility(); + setAutomaticBackup(binding.dailyBackup.isChecked()); } - public void backup() { - if (binding.contacts.isChecked() && checkAndAskForContactsReadPermission()) { + public void backupNow() { + if (isContactsBackupEnabled() && checkContactBackupPermission()) { startContactsBackupJob(); } - if (binding.calendar.isChecked() && checkAndAskForCalendarReadPermission()) { + if (isCalendarBackupEnabled() && checkCalendarBackupPermission(requireContext())) { startCalendarBackupJob(); } @@ -409,9 +441,22 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD } User user = optionalUser.get(); if (enabled) { - backgroundJobManager.schedulePeriodicContactsBackup(user); - backgroundJobManager.schedulePeriodicCalendarBackup(user); + if (isContactsBackupEnabled()) { + Log_OC.d(TAG, "Scheduling contacts backup job"); + backgroundJobManager.schedulePeriodicContactsBackup(user); + } else { + Log_OC.d(TAG, "Cancelling contacts backup job"); + backgroundJobManager.cancelPeriodicContactsBackup(user); + } + if (isCalendarBackupEnabled()) { + Log_OC.d(TAG, "Scheduling calendar backup job"); + backgroundJobManager.schedulePeriodicCalendarBackup(user); + } else { + Log_OC.d(TAG, "Cancelling calendar backup job"); + backgroundJobManager.cancelPeriodicCalendarBackup(user); + } } else { + Log_OC.d(TAG, "Cancelling all backup jobs"); backgroundJobManager.cancelPeriodicContactsBackup(user); backgroundJobManager.cancelPeriodicCalendarBackup(user); } @@ -449,11 +494,6 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD } } - private boolean checkBackupNowPermission() { - return (checkCalendarBackupPermission(getContext()) && binding.calendar.isChecked()) || - (checkContactBackupPermission() && binding.contacts.isChecked()); - } - private boolean checkCalendarBackupPermission(final Context context) { return PermissionUtil.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) && PermissionUtil.checkSelfPermission(context, Manifest.permission.WRITE_CALENDAR); }