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

Verified Commit 3c2048a6 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

refactor: improve code organization

parent 0352d108
Loading
Loading
Loading
Loading
Loading
+5 −40
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 MURENA SAS
 * 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
@@ -22,16 +23,14 @@ import static timber.log.Timber.DebugTree;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

import androidx.annotation.NonNull;

import foundation.e.drive.account.AccountUtils;
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;
@@ -76,42 +75,8 @@ public class EdriveApplication extends Application {
    }

    private void setupEdriveRecovery() {
        final SharedPreferences prefs = getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);

        boolean isDataAlreadyRecovered = prefs.getBoolean(AppConstants.IS_DATA_ALREADY_RECOVERED, false);

        if (!isDataAlreadyRecovered) {
            Timber.d("Data recovery is needed for eDrive to sync with cloud");

            String accountName = AccountUtils.getAccount(getApplicationContext()).name;
            String accountType = getString(R.string.eelo_account_type);

            // Account removal
            Intent accountRemovedIntent = new Intent("foundation.e.drive.action.ACCOUNT_REMOVED");
            accountRemovedIntent.setComponent(new ComponentName("foundation.e.drive",
                    "foundation.e.drive.account.receivers.AccountRemoveCallbackReceiver"));

            accountRemovedIntent.putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName);
            accountRemovedIntent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);

            Timber.d("Sending foundation.e.drive.action.ACCOUNT_REMOVED for eDrive data recovery: " +
                    "account name = %s, account type = %s", accountName, accountType);
            getApplicationContext().sendBroadcast(accountRemovedIntent);

            // Account addition
            Intent accountAddedIntent = new Intent("foundation.e.drive.action.ADD_ACCOUNT");
            accountAddedIntent.setComponent(new ComponentName("foundation.e.drive",
                    "foundation.e.drive.account.receivers.AccountAddedReceiver"));

            accountAddedIntent.putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName);
            accountAddedIntent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);

            Timber.d("Sending foundation.e.drive.action.ADD_ACCOUNT for eDrive data recovery: " +
                    "account name = %s, account type = %s", accountName, accountType);
            getApplicationContext().sendBroadcast(accountAddedIntent);
        } else {
            Timber.d("Data recovery is not necessary for eDrive.");
        }
        RecoveryManager recoveryManager = new RecoveryManager(getApplicationContext());
        recoveryManager.initiateRecovery();
    }

    synchronized public void startRecursiveFileObserver() {
+12 −7
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 MURENA SAS
 * 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
@@ -23,6 +24,8 @@ import android.content.Intent
import android.content.SharedPreferences
import foundation.e.drive.R
import foundation.e.drive.account.AccountUtils
import foundation.e.drive.recovery.RecoveryManager
import foundation.e.drive.recovery.RecoveryPreferences.RecoveryStatus.RecoveryCompleted
import foundation.e.drive.utils.AppConstants
import foundation.e.drive.utils.DavClientProvider
import foundation.e.drive.work.WorkLauncher
@@ -57,13 +60,15 @@ class AccountAddedReceiver() : BroadcastReceiver() {
        if (workLauncher.enqueueSetupWorkers(context)) {
            DavClientProvider.getInstance().cleanUp()
            workLauncher.enqueuePeriodicUserInfoFetching()
            handleDataRecovery(context)
        }
}

        // Update SharedPref to not trigger future recovery
        Timber.d("Updating IS_DATA_ALREADY_RECOVERED = true in SharedPref to not trigger future recovery")
        prefs.edit()
            .putBoolean(AppConstants.IS_DATA_ALREADY_RECOVERED, true)
            .apply()
    private fun handleDataRecovery(context: Context) {
        val recoveryManager = RecoveryManager(context)
        if (recoveryManager.isRecoveryNeeded()) {
            recoveryManager.updateRecoveryStatus(RecoveryCompleted)
        }
    }

    /**
+2 −2
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 MURENA SAS
 * 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
@@ -124,7 +125,6 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver {
                    .remove(SETUP_COMPLETED)
                    .remove(INITIAL_FOLDER_NUMBER)
                    .remove(AppConstants.KEY_LAST_SCAN_TIME)
                    .remove(AppConstants.IS_DATA_ALREADY_RECOVERED)
                    .apply();
        }

+97 −0
Original line number Diff line number Diff line
/*
 * 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 <https://www.gnu.org/licenses/>.
 */

package foundation.e.drive.recovery

import android.accounts.AccountManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import foundation.e.drive.R
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,
) {

    fun initiateRecovery() {
        if (isRecoveryNeeded()) {
            val (accountName, accountType) = getUserAccountInfo(context)

            if (accountName.isNotEmpty()) {
                Timber.d("Initiating data recovery for eDrive.")
                logoutUser(accountName, accountType)
                loginUser(accountName, accountType)
            }
        }
    }

    fun updateRecoveryStatus(status: RecoveryPreferences.RecoveryStatus) {
        RecoveryPreferences.updateRecoveryStatus(context, status)
        Timber.d("Updating recovery status to $status.")
    }

    fun isRecoveryNeeded(): Boolean = when (RecoveryPreferences.isRecoveryNeeded(context)) {
        RecoveryNeeded -> true
        RecoveryCompleted -> false
    }

    private fun getUserAccountInfo(context: Context): Pair<String, String> {
        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) {
        val accountAddedIntent = Intent("foundation.e.drive.action.ADD_ACCOUNT").apply {
            setComponent(
                ComponentName(
                    "foundation.e.drive",
                    "foundation.e.drive.account.receivers.AccountAddedReceiver"
                )
            )
            putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName)
            putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType)
        }
        context.applicationContext.sendBroadcast(accountAddedIntent)

        Timber.d("Sending foundation.e.drive.action.ADD_ACCOUNT for eDrive data recovery.")
        Timber.d("Account name = $accountName, account type = $accountType")

    }

    private fun logoutUser(accountName: String, accountType: String) {
        val accountRemovedIntent = Intent("foundation.e.drive.action.ACCOUNT_REMOVED").apply {
            setComponent(
                ComponentName(
                    "foundation.e.drive",
                    "foundation.e.drive.account.receivers.AccountRemoveCallbackReceiver"
                )
            )
            putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName)
            putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType)
        }
        context.applicationContext.sendBroadcast(accountRemovedIntent)

        Timber.d("Sending foundation.e.drive.action.ACCOUNT_REMOVED for eDrive data recovery.")
        Timber.d("Account name = $accountName, account type = $accountType")
    }
}
+60 −0
Original line number Diff line number Diff line
/*
 * 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 <https://www.gnu.org/licenses/>.
 */

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
    }
}
Loading