From b86b6dc685337d3418f63c8975ab28b824fe910a Mon Sep 17 00:00:00 2001 From: Elouan BOITEUX Date: Thu, 28 May 2026 14:32:20 +0200 Subject: [PATCH 1/3] feat: Set up data transfer when changing Android device --- app/src/main/AndroidManifest.xml | 5 +++-- app/src/main/res/xml/backup_rules.xml | 21 +++++++++++++++++++ .../main/res/xml/data_extraction_rules.xml | 21 ++++++++++--------- 3 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 app/src/main/res/xml/backup_rules.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ad795bd5f..815bad06bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -78,10 +78,10 @@ + + + + diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml index f87bbaca7a..665fc2d0dc 100644 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -17,17 +17,18 @@ --> - - - - - + + + - - - - - + + + + + + + + From cf06fb4fc6bdcf387e392adec7e352a8bd6b4acf Mon Sep 17 00:00:00 2001 From: Louis CAD Date: Tue, 21 Jul 2026 15:54:08 +0200 Subject: [PATCH 2/3] docs: Conform to CredentialManager update --- Core | 2 +- .../java/com/infomaniak/drive/KDriveTest.kt | 2 +- .../com/infomaniak/drive/ui/MenuUiTest.kt | 2 +- .../services/UploadWorkerErrorHandling.kt | 2 +- .../drive/data/sync/MediaObserverWorker.kt | 2 +- .../ui/menu/settings/SyncSettingsActivity.kt | 4 +- .../infomaniak/drive/utils/AccountUtils.kt | 37 +++++++++---------- .../com/infomaniak/drive/utils/SyncUtils.kt | 13 ++++--- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Core b/Core index e57d06f688..9221f79098 160000 --- a/Core +++ b/Core @@ -1 +1 @@ -Subproject commit e57d06f68869974737aa71daaffb933b3c8319fa +Subproject commit 9221f79098c35da91793b598b2f006dc4a4af938 diff --git a/app/src/androidTest/java/com/infomaniak/drive/KDriveTest.kt b/app/src/androidTest/java/com/infomaniak/drive/KDriveTest.kt index 648d7819c6..85b32d71c8 100644 --- a/app/src/androidTest/java/com/infomaniak/drive/KDriveTest.kt +++ b/app/src/androidTest/java/com/infomaniak/drive/KDriveTest.kt @@ -103,7 +103,7 @@ open class KDriveTest { if (!uiRealm.isClosed) uiRealm.close() Realm.deleteRealm(FileController.getRealmConfiguration(userDrive)) if (!Env.USE_CURRENT_USER) { - runBlocking { AccountUtils.removeUser(context, user) } + runBlocking { AccountUtils.removeUser(user.id) } } } diff --git a/app/src/androidTest/java/com/infomaniak/drive/ui/MenuUiTest.kt b/app/src/androidTest/java/com/infomaniak/drive/ui/MenuUiTest.kt index bd19196b3a..e93cfaaca2 100644 --- a/app/src/androidTest/java/com/infomaniak/drive/ui/MenuUiTest.kt +++ b/app/src/androidTest/java/com/infomaniak/drive/ui/MenuUiTest.kt @@ -45,7 +45,7 @@ class MenuUiTest : KDriveUiTest() { @DisplayName("Check UI to add a new kdrive user then log him off") fun testAddUser() { // Remove the other user if he's already in the database - runBlocking { AccountUtils.getUserById(Env.NEW_USER_ID)?.let { removeUser(context, it) } } + runBlocking { AccountUtils.getUserById(Env.NEW_USER_ID)?.let { removeUser(it.id) } } swipeDownNestedScrollView() getDeviceViewById("changeUserIcon").clickAndWaitForNewWindow() getDeviceViewById("addUser").clickAndWaitForNewWindow() diff --git a/app/src/main/java/com/infomaniak/drive/data/services/UploadWorkerErrorHandling.kt b/app/src/main/java/com/infomaniak/drive/data/services/UploadWorkerErrorHandling.kt index ea44acf0b1..66d9c7b042 100644 --- a/app/src/main/java/com/infomaniak/drive/data/services/UploadWorkerErrorHandling.kt +++ b/app/src/main/java/com/infomaniak/drive/data/services/UploadWorkerErrorHandling.kt @@ -53,7 +53,7 @@ object UploadWorkerErrorHandling { UploadFile.deleteAll(uploadFile.remoteFolder, permanently = true) if (uploadFile.isSync()) { Sentry.captureMessage("FolderNotFoundNotification: disableAutoSync") - applicationContext.disableAutoSync() + disableAutoSync() } uploadFile.folderNotFoundNotification(applicationContext) } diff --git a/app/src/main/java/com/infomaniak/drive/data/sync/MediaObserverWorker.kt b/app/src/main/java/com/infomaniak/drive/data/sync/MediaObserverWorker.kt index d21cff6858..0d057c42c7 100644 --- a/app/src/main/java/com/infomaniak/drive/data/sync/MediaObserverWorker.kt +++ b/app/src/main/java/com/infomaniak/drive/data/sync/MediaObserverWorker.kt @@ -76,7 +76,7 @@ class MediaObserverWorker(appContext: Context, params: WorkerParameters) : Corou if (syncSetting == null) { Sentry.captureMessage("$TAG: disableAutoSync") - context.disableAutoSync() + disableAutoSync() return } diff --git a/app/src/main/java/com/infomaniak/drive/ui/menu/settings/SyncSettingsActivity.kt b/app/src/main/java/com/infomaniak/drive/ui/menu/settings/SyncSettingsActivity.kt index 2cb73f5cae..56ecddb0c5 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/menu/settings/SyncSettingsActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/menu/settings/SyncSettingsActivity.kt @@ -34,10 +34,10 @@ import androidx.lifecycle.lifecycleScope import com.google.android.material.datepicker.CalendarConstraints import com.google.android.material.datepicker.DateValidatorPointBackward import com.google.android.material.datepicker.MaterialDatePicker +import com.infomaniak.core.common.extensions.isNightModeEnabled import com.infomaniak.core.common.utils.FORMAT_DATE_CLEAR_MONTH import com.infomaniak.core.common.utils.format import com.infomaniak.core.common.utils.startOfTheDay -import com.infomaniak.core.common.extensions.isNightModeEnabled import com.infomaniak.core.legacy.utils.context import com.infomaniak.core.legacy.utils.startAppSettingsConfig import com.infomaniak.core.legacy.utils.whenResultIsOk @@ -453,7 +453,7 @@ class SyncSettingsActivity : BaseActivity() { SentryLog.i(TAG, "appSettings updated") if (oldSyncSettings?.driveId != syncSettings.driveId) { UploadFile.deleteAllSyncFile() - applicationContext.cancelPeriodicSync() + cancelPeriodicSync() SentryLog.i(TAG, "New drive detected -> old sync files has been deleted") } applicationContext.activateAutoSync(syncSettings) diff --git a/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt b/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt index f204169db3..1f886be728 100644 --- a/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt +++ b/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt @@ -59,9 +59,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import okhttp3.OkHttpClient +import splitties.init.appCtx import com.infomaniak.core.network.networking.HttpClient.okHttpClient as unauthenticatedHttpClient -object AccountUtils : CredentialManager() { +object AccountUtils : CredentialManager( + userDataCleanableList = { MainApplication.userDataCleanableList } +) { private const val DISABLE_AUTO_SYNC = "AccountUtils: disableAutoSync" @@ -113,12 +116,10 @@ object AccountUtils : CredentialManager() { return currentUser } - suspend fun addUser(user: User) { + override suspend fun addUser(user: User) { currentDriveId = -1 currentUser = user - val userId = user.id.toLong() - MainApplication.userDataCleanableList.forEach { it.resetForUser(userId) } - userDatabase.userDao().insert(user) + super.addUser(user) } suspend fun updateCurrentUserAndDrives( @@ -165,7 +166,7 @@ object AccountUtils : CredentialManager() { for (driveRemoved in driveRemovedList) { if (appSyncSettings?.userId == user.id && appSyncSettings.driveId == driveRemoved.id) { Sentry.captureMessage(DISABLE_AUTO_SYNC) - context.disableAutoSync() + disableAutoSync() } if (currentDriveId == driveRemoved.id) { getFirstDrive() @@ -220,31 +221,29 @@ object AccountUtils : CredentialManager() { } } - MyKSuiteDataUtils.deleteData(user.id) - removeUser(context, user) + removeUser(user.id) } - suspend fun removeUser(context: Context, user: User) { - val userId = user.id.toLong() - MainApplication.userDataCleanableList.forEach { it.resetForUser(userId) } - userDatabase.userDao().delete(user) - FileController.deleteUserDriveFiles(user.id) + override suspend fun removeUser(userId: Int) { + MyKSuiteDataUtils.deleteData(userId) + super.removeUser(userId) + FileController.deleteUserDriveFiles(userId) - if (UploadFile.getAppSyncSettings()?.userId == user.id) { + if (UploadFile.getAppSyncSettings()?.userId == userId) { Sentry.captureMessage(DISABLE_AUTO_SYNC) - context.disableAutoSync() + disableAutoSync() } - if (currentUserId == user.id) { + if (currentUserId == userId) { requestCurrentUser() currentDriveId = -1 - resetApp(context) + resetApp(appCtx) scope.launch(Dispatchers.Main) { reloadApp?.invoke(bundleOf()) } - CloudStorageProvider.notifyRootsChanged(context) + CloudStorageProvider.notifyRootsChanged(appCtx) } } @@ -281,7 +280,7 @@ object AccountUtils : CredentialManager() { if (isEnableAppSync()) { Sentry.captureMessage(DISABLE_AUTO_SYNC) - context.disableAutoSync() + disableAutoSync() } // Delete all app data diff --git a/app/src/main/java/com/infomaniak/drive/utils/SyncUtils.kt b/app/src/main/java/com/infomaniak/drive/utils/SyncUtils.kt index becfb86975..89ba673ef2 100644 --- a/app/src/main/java/com/infomaniak/drive/utils/SyncUtils.kt +++ b/app/src/main/java/com/infomaniak/drive/utils/SyncUtils.kt @@ -32,6 +32,7 @@ import com.infomaniak.drive.data.services.PeriodicUploadWorker import com.infomaniak.drive.data.services.UploadWorker import com.infomaniak.drive.data.sync.MediaObserverWorker import kotlinx.coroutines.flow.first +import splitties.init.appCtx object SyncUtils { @@ -89,9 +90,9 @@ object SyncUtils { } } - fun Context.cancelPeriodicSync() { - WorkManager.getInstance(this).cancelUniqueWork(UploadWorker.TAG) - WorkManager.getInstance(this).cancelUniqueWork(PeriodicUploadWorker.TAG) + fun cancelPeriodicSync() { + WorkManager.getInstance(appCtx).cancelUniqueWork(UploadWorker.TAG) + WorkManager.getInstance(appCtx).cancelUniqueWork(PeriodicUploadWorker.TAG) } suspend fun Context.activateSyncIfNeeded() { @@ -112,8 +113,8 @@ object SyncUtils { } } - private fun Context.cancelContentObserver() { - MediaObserverWorker.cancelWork(applicationContext) + private fun cancelContentObserver() { + MediaObserverWorker.cancelWork(appCtx) } suspend fun Context.activateAutoSync(syncSettings: SyncSettings) { @@ -122,7 +123,7 @@ object SyncUtils { startPeriodicSync(context = this, syncSettings.syncInterval) } - fun Context.disableAutoSync() { + fun disableAutoSync() { UploadFile.removeAppSyncSettings() MediaFolder.deleteAll() cancelContentObserver() From 014480c6246cbaae89d017ff3758f7a08f9f796c Mon Sep 17 00:00:00 2001 From: Louis CAD Date: Tue, 21 Jul 2026 18:27:25 +0200 Subject: [PATCH 3/3] feat: Add support for token derivation on backup restoration --- Core | 2 +- .../com/infomaniak/drive/ui/LaunchActivity.kt | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Core b/Core index 9221f79098..799eddcd13 160000 --- a/Core +++ b/Core @@ -1 +1 @@ -Subproject commit 9221f79098c35da91793b598b2f006dc4a4af938 +Subproject commit 799eddcd13dd4471553eee6b32d54633cb535320 diff --git a/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt b/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt index f19c7b4a68..3e8688d9f3 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt @@ -23,14 +23,18 @@ import android.content.Intent import android.net.Uri import android.os.Build.VERSION.SDK_INT import android.os.Bundle +import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope +import com.infomaniak.core.auth.backup.RestoreFromBackupManager +import com.infomaniak.core.auth.backup.RestoringFromBackupFailedScreen import com.infomaniak.core.legacy.extensions.setDefaultLocaleIfNeeded import com.infomaniak.core.network.models.ApiError import com.infomaniak.core.network.models.ApiResponseStatus import com.infomaniak.core.network.models.exceptions.NetworkException import com.infomaniak.core.sentry.SentryLog +import com.infomaniak.core.ui.compose.materialthemefromxml.MaterialThemeFromXml import com.infomaniak.core.ui.view.edgetoedge.EdgeToEdgeActivity import com.infomaniak.drive.MatomoDrive.MatomoName import com.infomaniak.drive.MatomoDrive.trackDeepLink @@ -68,6 +72,8 @@ import io.sentry.Breadcrumb import io.sentry.Sentry import io.sentry.SentryLevel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.transform import kotlinx.coroutines.invoke import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -93,6 +99,7 @@ class LaunchActivity : EdgeToEdgeActivity() { trackScreen() lifecycleScope.launch { + handleRestoreFromBackup() logoutCurrentUserIfNeeded() // Rights v2 migration temporary fix handleLaunchArgs() if (deeplinkType?.isHandled == false) { @@ -107,6 +114,21 @@ class LaunchActivity : EdgeToEdgeActivity() { } } + private suspend fun handleRestoreFromBackup() { + val manager = RestoreFromBackupManager.instance + manager.state.transform { state -> + when (state) { + RestoreFromBackupManager.State.RestoringFromBackup -> { + setContentView(binding.root) + } + is RestoreFromBackupManager.State.RestoringFromBackupFailed -> { + setContent { MaterialThemeFromXml { RestoringFromBackupFailedScreen(state) } } + } + RestoreFromBackupManager.State.Settled -> emit(Unit) + } + }.first() + } + private suspend fun handleLaunchArgs() { when (val type = LaunchArgsType.from(navigationArgs, intent)) { is Deeplink -> handleDeeplink(type)