diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6bb8b5acc6d70b7060bcf2634d301ef100bd82d5..7639ff95c59e87023f25d8953b84e0818d3dbdfc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -125,4 +125,4 @@ android:foregroundServiceType="dataSync" tools:node="merge" /> - \ No newline at end of file + diff --git a/app/src/main/java/foundation/e/drive/EdriveApplication.java b/app/src/main/java/foundation/e/drive/EdriveApplication.java index 853607358fa03a933ba38ca35b9b328df0dcd970..ad9eb5c2b7bc959c381d7073892d36d371f70aa9 100644 --- a/app/src/main/java/foundation/e/drive/EdriveApplication.java +++ b/app/src/main/java/foundation/e/drive/EdriveApplication.java @@ -1,9 +1,19 @@ /* - * Copyright © ECORP SAS 2022-2023. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html + * Copyright (C) 2025 e Foundation + * Copyright (C) ECORP SAS 2022-2023 + * + * 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 . */ package foundation.e.drive; @@ -20,6 +30,7 @@ import androidx.annotation.NonNull; import foundation.e.drive.database.FailedSyncPrefsManager; import foundation.e.drive.fileObservers.FileObserverManager; +import foundation.e.drive.recovery.RecoveryManager; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.ReleaseTree; @@ -59,6 +70,13 @@ public class EdriveApplication extends Application { } FailedSyncPrefsManager.getInstance(getApplicationContext()).clearPreferences(); + + setupEdriveRecovery(); + } + + private void setupEdriveRecovery() { + RecoveryManager recoveryManager = new RecoveryManager(getApplicationContext()); + recoveryManager.initiateRecovery(); } synchronized public void startRecursiveFileObserver() { diff --git a/app/src/main/java/foundation/e/drive/account/AccountAdder.kt b/app/src/main/java/foundation/e/drive/account/AccountAdder.kt new file mode 100644 index 0000000000000000000000000000000000000000..0cbba53068d7bb02b3b1c3fa097be27e19c794d2 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/account/AccountAdder.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2025 e Foundation + * + * 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 . + * + */ + +package foundation.e.drive.account + +import android.accounts.AccountManager +import android.content.Context +import android.content.SharedPreferences +import foundation.e.drive.R +import foundation.e.drive.utils.AppConstants +import foundation.e.drive.utils.DavClientProvider +import foundation.e.drive.work.WorkLauncher +import timber.log.Timber + +class AccountAdder(private val context: Context) { + + private val preferences: SharedPreferences by lazy { + context.applicationContext.getSharedPreferences( + AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE + ) + } + + fun addAccount(name: String, type: String) { + if (!canStart(name, type, preferences, context)) return + + updateAccountNameOnPreference(name) + + val workLauncher = WorkLauncher.getInstance(context) + if (workLauncher.enqueueSetupWorkers(context)) { + DavClientProvider.getInstance().cleanUp() + workLauncher.enqueuePeriodicUserInfoFetching() + } + } + + private fun updateAccountNameOnPreference(name: String) { + preferences.edit() + .putString(AccountManager.KEY_ACCOUNT_NAME, name) + .apply() + } + + /** + * Check that conditions to start are met: + * - Setup has not already been done + * - AccountName is not empty + * - AccountType is /e/ account + * - the account is effectively available through accountManager + */ + private fun canStart( + accountName: String, + accountType: String, + prefs: SharedPreferences, + context: Context + ): Boolean { + if (isSetupAlreadyDone(prefs)) { + Timber.w("Set up is already done, skipping account addition.") + return false + } + + if (accountName.isEmpty()) { + Timber.w("Account name is empty, skipping account addition.") + return false + } + + if (isInvalidAccountType(accountType, context)) { + Timber.w("Account type: $accountType is invalid, skipping account addition.") + return false + } + + if (!isExistingAccount(accountName, context)) { + Timber.w("No account exists for $accountName, skipping account addition.") + return false + } + + return true + } + + private fun isSetupAlreadyDone(prefs: SharedPreferences): Boolean { + return prefs.getBoolean(AppConstants.SETUP_COMPLETED, false) + } + + private fun isInvalidAccountType(accountType: String, context: Context): Boolean { + val validAccountType = context.getString(R.string.eelo_account_type) + return accountType != validAccountType + } + + private fun isExistingAccount(accountName: String, context: Context): Boolean { + return AccountUtils.getAccount(accountName, context) != null + } +} diff --git a/app/src/main/java/foundation/e/drive/account/AccountRemover.kt b/app/src/main/java/foundation/e/drive/account/AccountRemover.kt new file mode 100644 index 0000000000000000000000000000000000000000..fe6acc51c576be4469d5d8e9c5e3a32c1cf22315 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/account/AccountRemover.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2025 e Foundation + * + * 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 . + * + */ + +package foundation.e.drive.account + +import android.accounts.AccountManager +import android.app.Application +import android.app.NotificationManager +import android.content.Context +import android.content.SharedPreferences +import androidx.work.WorkManager +import foundation.e.drive.database.DbHelper +import foundation.e.drive.database.FailedSyncPrefsManager +import foundation.e.drive.synchronization.SyncProxy +import foundation.e.drive.utils.AppConstants +import foundation.e.drive.utils.AppConstants.INITIAL_FOLDER_NUMBER +import foundation.e.drive.utils.AppConstants.SETUP_COMPLETED +import foundation.e.drive.utils.DavClientProvider +import timber.log.Timber +import java.io.File + +class AccountRemover( + private val context: Context, +) { + private val preferences: SharedPreferences by lazy { + context.applicationContext.getSharedPreferences( + AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE + ) + } + + fun removeAccount() { + cancelWorkers() + setSyncStateToIdle() + deleteDatabase() + cleanSharedPreferences() + removeCachedFiles() + deleteNotificationChannels() + cleanUpDavClient() + } + + private fun cleanUpDavClient() { + DavClientProvider.getInstance().cleanUp() + } + + private fun setSyncStateToIdle() { + SyncProxy.moveToIdle(context.applicationContext as Application) + } + + private fun cancelWorkers() { + val workManager = WorkManager.getInstance(context) + workManager.cancelAllWorkByTag(AppConstants.WORK_GENERIC_TAG) + } + + private fun deleteDatabase() { + val result = context.applicationContext.deleteDatabase(DbHelper.DATABASE_NAME) + Timber.d("Remove Database: %s", result) + } + + private fun cleanSharedPreferences() { + if (!context.applicationContext.deleteSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME)) { + //If removal failed, clear all data inside + preferences.edit().remove(AccountManager.KEY_ACCOUNT_NAME) + .remove(AccountManager.KEY_ACCOUNT_TYPE) + .remove(SETUP_COMPLETED) + .remove(INITIAL_FOLDER_NUMBER) + .remove(AppConstants.KEY_LAST_SCAN_TIME) + .apply() + } + context.applicationContext.deleteSharedPreferences(FailedSyncPrefsManager.PREF_NAME) + } + + private fun removeCachedFiles() { + try { + deleteDir(context.applicationContext.externalCacheDir) + } catch (e: SecurityException) { + Timber.e(e, "failed to delete cached file on account removal call") + } + } + + @Throws(SecurityException::class) + private fun deleteDir(dir: File?): Boolean { + if (dir == null) { + Timber.w("cache file returned null. preventing a NPE") + return false + } + + return dir.deleteRecursively() + } + + @Suppress("TooGenericExceptionCaught") + private fun deleteNotificationChannels() { + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + try { + notificationManager.cancelAll() + } catch (exception: RuntimeException) { + Timber.e(exception, "Cannot cancel all notifications") + } + } +} diff --git a/app/src/main/java/foundation/e/drive/account/receivers/AccountAddedReceiver.kt b/app/src/main/java/foundation/e/drive/account/receivers/AccountAddedReceiver.kt index b2c51e5b84ea344b3570eb9140cf1692c7fd282f..7ed75c7a128516cd4b34bd9270be7f26628e87bc 100644 --- a/app/src/main/java/foundation/e/drive/account/receivers/AccountAddedReceiver.kt +++ b/app/src/main/java/foundation/e/drive/account/receivers/AccountAddedReceiver.kt @@ -1,9 +1,19 @@ /* - * Copyright © MURENA SAS 2023-2024. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html + * Copyright (C) 2025 e Foundation + * Copyright (C) MURENA SAS 2023-2024 + * + * 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 . */ package foundation.e.drive.account.receivers @@ -11,12 +21,7 @@ import android.accounts.AccountManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.content.SharedPreferences -import foundation.e.drive.R -import foundation.e.drive.account.AccountUtils -import foundation.e.drive.utils.AppConstants -import foundation.e.drive.utils.DavClientProvider -import foundation.e.drive.work.WorkLauncher +import foundation.e.drive.account.AccountAdder import timber.log.Timber /** @@ -24,7 +29,7 @@ import timber.log.Timber * Triggered by AccountManager * @author Vincent Bourgmayer */ -class AccountAddedReceiver() : BroadcastReceiver() { +class AccountAddedReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { Timber.d("\"Account added\" intent received") @@ -33,66 +38,10 @@ class AccountAddedReceiver() : BroadcastReceiver() { val extras = intent.extras!! val accountName = extras.getString(AccountManager.KEY_ACCOUNT_NAME, "") val accountType = extras.getString(AccountManager.KEY_ACCOUNT_TYPE, "") - val prefs = context.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, - Context.MODE_PRIVATE) Timber.d("AccountAddedReceiver.onReceive with name: %s and type: %s", accountName, accountType) - if (!canStart(accountName, accountType, prefs, context)) return - - prefs.edit() - .putString(AccountManager.KEY_ACCOUNT_NAME, accountName) - .apply() - - val workLauncher = WorkLauncher.getInstance(context) - if (workLauncher.enqueueSetupWorkers(context)) { - DavClientProvider.getInstance().cleanUp() - workLauncher.enqueuePeriodicUserInfoFetching() - } -} - - /** - * Check that conditions to start are met: - * - Setup has not already been done - * - AccountName is not empty - * - AccountType is /e/ account - * - the account is effectively available through accountManager - */ - private fun canStart( - accountName: String, - accountType: String, - prefs: SharedPreferences, - context: Context - ): Boolean { - if (isSetupAlreadyDone(prefs)) { - return false - } - - if (accountName.isEmpty()) { - return false - } - - if (isInvalidAccountType(accountType, context)) { - return false - } - - if (!isExistingAccount(accountName, context)) { - Timber.w("No account exist for username: %s ", accountType, accountName) - return false - } - return true - } - - private fun isInvalidAccountType(accountType: String, context: Context): Boolean { - val validAccountType = context.getString(R.string.eelo_account_type) - return accountType != validAccountType - } - - private fun isSetupAlreadyDone(prefs: SharedPreferences): Boolean { - return prefs.getBoolean(AppConstants.SETUP_COMPLETED, false) - } - - private fun isExistingAccount(accountName: String, context: Context): Boolean { - return AccountUtils.getAccount(accountName, context) != null + val accountAdder = AccountAdder(context) + accountAdder.addAccount(accountName, accountType) } } diff --git a/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java b/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java index 4ff1ed1ef1f24ec0d7156511b9d66f0387ac3431..c8f16a69000fcd2364b837f2a1e50d5caa6a1ede 100644 --- a/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java +++ b/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java @@ -1,42 +1,42 @@ /* - * Copyright © ECORP SAS 2023. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html + * Copyright (C) 2025 e Foundation + * Copyright (C) ECORP SAS 2023 + * + * 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 . */ package foundation.e.drive.account.receivers; -import static foundation.e.drive.utils.AppConstants.INITIAL_FOLDER_NUMBER; -import static foundation.e.drive.utils.AppConstants.SETUP_COMPLETED; - import android.accounts.AccountManager; import android.annotation.SuppressLint; -import android.app.Application; -import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.work.WorkManager; - -import java.io.File; import foundation.e.drive.R; -import foundation.e.drive.database.DbHelper; -import foundation.e.drive.database.FailedSyncPrefsManager; -import foundation.e.drive.synchronization.SyncProxy; +import foundation.e.drive.account.AccountRemover; import foundation.e.drive.utils.AppConstants; -import foundation.e.drive.utils.DavClientProvider; import foundation.e.drive.utils.ViewUtils; import timber.log.Timber; public class AccountRemoveCallbackReceiver extends BroadcastReceiver { + private static final String ACTION_ACCOUNT_REMOVED = "android.accounts.action.ACCOUNT_REMOVED"; + @SuppressLint("UnsafeProtectedBroadcastReceiver") @Override public void onReceive(@NonNull Context context, @NonNull Intent intent) { @@ -50,29 +50,12 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver { return; } - cancelWorkers(applicationContext); - SyncProxy.INSTANCE.moveToIdle((Application) applicationContext); - deleteDatabase(applicationContext); - cleanSharedPreferences(applicationContext, preferences); - removeCachedFiles(applicationContext); - deleteNotificationChannels(applicationContext); - - DavClientProvider.getInstance().cleanUp(); + AccountRemover accountRemover = new AccountRemover(context); + accountRemover.removeAccount(); ViewUtils.updateWidgetView(applicationContext); } - - private void cancelWorkers(@NonNull Context context) { - final WorkManager workManager = WorkManager.getInstance(context); - workManager.cancelAllWorkByTag(AppConstants.WORK_GENERIC_TAG); - } - - private void deleteDatabase(@NonNull Context applicationContext) { - final boolean result = applicationContext.deleteDatabase(DbHelper.DATABASE_NAME); - Timber.d("Remove Database: %s", result); - } - private boolean shouldProceedWithRemoval(@NonNull Intent intent, @NonNull SharedPreferences preferences, @NonNull Context context) { if (isInvalidAction(intent) || intent.getExtras() == null) { Timber.w("Invalid account removal request"); @@ -94,61 +77,6 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver { } private boolean isInvalidAction(@NonNull Intent intent) { - return !"android.accounts.action.ACCOUNT_REMOVED".equals(intent.getAction()); - } - - private void cleanSharedPreferences(@NonNull Context applicationContext, @NonNull SharedPreferences prefs) { - if (!applicationContext.deleteSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME)) { - //If removal failed, clear all data inside - prefs.edit().remove(AccountManager.KEY_ACCOUNT_NAME) - .remove(AccountManager.KEY_ACCOUNT_TYPE) - .remove(SETUP_COMPLETED) - .remove(INITIAL_FOLDER_NUMBER) - .remove(AppConstants.KEY_LAST_SCAN_TIME) - .apply(); - } - - applicationContext.deleteSharedPreferences(FailedSyncPrefsManager.PREF_NAME); - } - - private void removeCachedFiles(@NonNull Context applicationContext) { - try { - deleteDir(applicationContext.getExternalCacheDir()); - } catch (SecurityException e) { - Timber.e(e, "failed to delete cached file on account removal call"); - } - } - - private boolean deleteDir(@Nullable File dir) throws SecurityException { - if (dir == null) { - Timber.w("cache file returned null. preventing a NPE"); - return false; - } - - if (dir.isDirectory()) { - String[] children = dir.list(); - if (children == null) { - return dir.delete(); - } - - for (String child : children) { - boolean isSuccess = deleteDir(new File(dir, child)); - if (!isSuccess) { - Timber.w("Failed to remove the cached file: %s", child); - } - } - } - - return dir.delete(); - } - - private void deleteNotificationChannels(Context context) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - - try { - notificationManager.cancelAll(); - } catch (Exception exception) { - Timber.e(exception, "Cannot cancel all notifications"); - } + return !ACTION_ACCOUNT_REMOVED.equals(intent.getAction()); } } diff --git a/app/src/main/java/foundation/e/drive/recovery/RecoveryManager.kt b/app/src/main/java/foundation/e/drive/recovery/RecoveryManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..499ec7bae73540a9553c3d4d82fc4ee36968a665 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/recovery/RecoveryManager.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2025 e Foundation + * + * 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 . + */ + +package foundation.e.drive.recovery + +import android.content.Context +import foundation.e.drive.R +import foundation.e.drive.account.AccountAdder +import foundation.e.drive.account.AccountRemover +import foundation.e.drive.account.AccountUtils.getAccount +import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryCompleted +import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryNeeded +import timber.log.Timber + +class RecoveryManager( + private val context: Context, +) { + private val accountRemover = AccountRemover(context) + private val accountAdder = AccountAdder(context) + + fun initiateRecovery() { + if (isRecoveryNeeded()) { + val (accountName, accountType) = getUserAccountInfo(context) + + if (accountName.isNotEmpty()) { + Timber.i("Initiating data recovery for eDrive.") + logoutUser() + loginUser(accountName, accountType) + updateRecoveryStatus(RecoveryCompleted) + } + } + } + + private fun updateRecoveryStatus(status: RecoveryPreferences.RecoveryStatus) { + RecoveryPreferences.updateRecoveryStatus(context, status) + Timber.i("Updating eDrive recovery status to $status.") + } + + private fun isRecoveryNeeded(): Boolean = when (RecoveryPreferences.isRecoveryNeeded(context)) { + RecoveryNeeded -> true + RecoveryCompleted -> false + } + + private fun getUserAccountInfo(context: Context): Pair { + val accountName = getAccount(context.applicationContext)?.name ?: "" + val accountType: String = context.getString(R.string.eelo_account_type) + + return Pair(accountName, accountType) + } + + private fun loginUser(accountName: String, accountType: String) { + accountAdder.addAccount(accountName, accountType) + Timber.i("Added Account($accountName, $accountType) to eDrive.") + } + + private fun logoutUser() { + accountRemover.removeAccount() + Timber.i("Account removed from eDrive.") + } +} diff --git a/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt b/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt new file mode 100644 index 0000000000000000000000000000000000000000..8824e7786599bd5419bdbf91c6bd0d80b993365f --- /dev/null +++ b/app/src/main/java/foundation/e/drive/recovery/RecoveryPreferences.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2025 e Foundation + * + * 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 . + */ + +package foundation.e.drive.recovery + +import android.content.Context +import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryCompleted +import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryNeeded + +object RecoveryPreferences { + + private const val PREFERENCES_NAME = "edrive_recovery" + private const val KEY_IS_DATA_ALREADY_RECOVERED = "is_data_already_recovered" + + @JvmStatic + fun isRecoveryNeeded(context: Context): RecoveryStatus { + val preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + val isDataAlreadyRecovered = preferences.getBoolean(KEY_IS_DATA_ALREADY_RECOVERED, false) + + return if (isDataAlreadyRecovered) { + RecoveryCompleted + } else { + RecoveryNeeded + } + } + + @JvmStatic + fun updateRecoveryStatus(context: Context, status: RecoveryStatus) { + val preferences = + context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + when (status) { + RecoveryCompleted -> { + preferences.edit().putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, true).apply() + } + + RecoveryNeeded -> { + preferences.edit().putBoolean(KEY_IS_DATA_ALREADY_RECOVERED, false).apply() + } + } + } + + enum class RecoveryStatus { + RecoveryNeeded, + RecoveryCompleted + } +} diff --git a/app/src/main/java/foundation/e/drive/utils/AppConstants.kt b/app/src/main/java/foundation/e/drive/utils/AppConstants.kt index 57a107de508581d82275b4245004088a0169fece..7daadb73103b0780f947ae513a6f5a1022c0756e 100644 --- a/app/src/main/java/foundation/e/drive/utils/AppConstants.kt +++ b/app/src/main/java/foundation/e/drive/utils/AppConstants.kt @@ -1,10 +1,20 @@ /* - * Copyright © CLEUS SAS 2018-2019. - * Copyright © MURENA SAS 2022-2023. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html + * Copyright (C) 2025 e Foundation + * Copyright (C) MURENA SAS 2022-2023 + * Copyright (C) CLEUS SAS 2018-2019 + * + * 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 . */ package foundation.e.drive.utils