diff --git a/app/src/main/java/com/infomaniak/drive/ApplicationMain.kt b/app/src/main/java/com/infomaniak/drive/ApplicationMain.kt index b89ee68464..c85092d7ce 100644 --- a/app/src/main/java/com/infomaniak/drive/ApplicationMain.kt +++ b/app/src/main/java/com/infomaniak/drive/ApplicationMain.kt @@ -39,9 +39,11 @@ import com.infomaniak.drive.data.models.UiSettings import com.infomaniak.drive.data.services.MqttClientWrapper import com.infomaniak.drive.data.sync.UploadNotifications.pendingIntentFlags import com.infomaniak.drive.ui.LaunchActivity -import com.infomaniak.drive.utils.* +import com.infomaniak.drive.utils.AccountUtils +import com.infomaniak.drive.utils.KDriveHttpClient import com.infomaniak.drive.utils.NotificationUtils.initNotificationChannel import com.infomaniak.drive.utils.NotificationUtils.showGeneralNotification +import com.infomaniak.drive.utils.clearStack import com.infomaniak.lib.core.InfomaniakCore import com.infomaniak.lib.core.auth.TokenAuthenticator import com.infomaniak.lib.core.auth.TokenInterceptor @@ -54,10 +56,12 @@ import io.sentry.SentryEvent import io.sentry.SentryOptions import io.sentry.android.core.SentryAndroid import io.sentry.android.core.SentryAndroidOptions -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.OkHttpClient -import org.eclipse.paho.client.mqttv3.* import java.util.* class ApplicationMain : Application(), ImageLoaderFactory { @@ -91,8 +95,11 @@ class ApplicationMain : Application(), ImageLoaderFactory { runBlocking { initRealm() } - AccountUtils.reloadApp = { - startActivity(Intent(this, LaunchActivity::class.java).clearStack()) + AccountUtils.reloadApp = { bundle -> + val intent = Intent(this, LaunchActivity::class.java) + .apply { putExtras(bundle) } + .clearStack() + startActivity(intent) } InfomaniakCore.init( diff --git a/app/src/main/java/com/infomaniak/drive/data/cache/FileMigration.kt b/app/src/main/java/com/infomaniak/drive/data/cache/FileMigration.kt index a2c3c4c73d..0ef7e4d182 100644 --- a/app/src/main/java/com/infomaniak/drive/data/cache/FileMigration.kt +++ b/app/src/main/java/com/infomaniak/drive/data/cache/FileMigration.kt @@ -17,18 +17,23 @@ */ package com.infomaniak.drive.data.cache +import androidx.core.os.bundleOf import com.infomaniak.drive.data.models.File import com.infomaniak.drive.data.models.FileCategory import com.infomaniak.drive.data.models.Rights +import com.infomaniak.drive.utils.AccountUtils import io.realm.DynamicRealm import io.realm.FieldAttribute import io.realm.RealmMigration +import io.realm.RealmSchema import io.sentry.Sentry import java.util.* class FileMigration : RealmMigration { companion object { const val bddVersion = 3L // Must be bumped when the schema changes + + const val LOGOUT_CURRENT_USER_TAG = "logout_current_user_tag" } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -74,26 +79,37 @@ class FileMigration : RealmMigration { } // Rights migration with sentry logs val sentryLogs = arrayListOf>() + var countOfflineFiles = 0 runCatching { schema.get(Rights::class.java.simpleName)?.transform { // apply for each right val fileId = it.getInt("fileId") val file = realm.where(File::class.java.simpleName).equalTo(File::id.name, fileId).findFirst() - if (file == null) it.deleteFromRealm() // Delete if it's orphan - sentryLogs.add(fileId to "right is orphan ${file == null}") + if (file == null) { + it.deleteFromRealm() // Delete if it's orphan + sentryLogs.add(fileId to "right is orphan true") + } + // Count offline files for sentry log + if (file?.getBoolean(File::isOffline.name) == true) countOfflineFiles++ }?.apply { removePrimaryKey() removeField("fileId") isEmbedded = true } + }.onFailure { exception -> exception.printStackTrace() // On some clients, it happens that isEmbedded is added in an orphan file without knowing why // So we add these sentry logs to have more info + // We have an issue here: https://github.com/realm/realm-java/issues/7642 Sentry.withScope { scope -> scope.setExtra("oldVersion", "$oldVersion") + scope.setExtra("count orphan files", "${sentryLogs.count()}") + scope.setExtra("count offline files", "$countOfflineFiles") scope.setExtra("logs", sentryLogs.toString()) Sentry.captureException(exception) } + + temporaryMigrationFixToV2(realm, schema) } oldVersionTemp++ @@ -120,4 +136,19 @@ class FileMigration : RealmMigration { override fun hashCode(): Int { return javaClass.hashCode() } + + private fun temporaryMigrationFixToV2(realm: DynamicRealm, schema: RealmSchema) { + val offlineFile = realm.where(File::class.java.simpleName).equalTo(File::isOffline.name, true).findFirst() + + // Delete all realm DB + realm.deleteAll() + // Continue migration + schema.get(Rights::class.java.simpleName)?.isEmbedded = true + + // Logout the current user if there is at least one offline file + offlineFile?.let { + // Logout current user + AccountUtils.reloadApp?.invoke(bundleOf(LOGOUT_CURRENT_USER_TAG to true)) + } + } } 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 fdded756aa..b3b235682c 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/LaunchActivity.kt @@ -22,18 +22,24 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import com.infomaniak.drive.data.cache.DriveInfosController +import com.infomaniak.drive.data.cache.FileMigration import com.infomaniak.drive.data.models.AppSettings import com.infomaniak.drive.ui.login.LoginActivity import com.infomaniak.drive.ui.login.MigrationActivity import com.infomaniak.drive.ui.login.MigrationActivity.Companion.getOldkDriveUser import com.infomaniak.drive.utils.AccountUtils import com.infomaniak.drive.utils.isKeyguardSecure +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class LaunchActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { + + logoutCurrentUserIfNeeded() // Rights v2 migration temporary fix + when { AccountUtils.requestCurrentUser() == null -> { if (getOldkDriveUser().isEmpty) { @@ -63,4 +69,13 @@ class LaunchActivity : AppCompatActivity() { super.onPause() overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) } + + private suspend fun logoutCurrentUserIfNeeded() = withContext(Dispatchers.IO) { + intent.extras?.getBoolean(FileMigration.LOGOUT_CURRENT_USER_TAG)?.let { needLogoutCurrentUser -> + if (needLogoutCurrentUser) { + if (AccountUtils.currentUser == null) AccountUtils.requestCurrentUser() + AccountUtils.currentUser?.let { AccountUtils.removeUser(this@LaunchActivity, it) } + } + } + } } diff --git a/app/src/main/java/com/infomaniak/drive/ui/SwitchDriveDialog.kt b/app/src/main/java/com/infomaniak/drive/ui/SwitchDriveDialog.kt index b4bcd95996..e5b241117f 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/SwitchDriveDialog.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/SwitchDriveDialog.kt @@ -47,7 +47,7 @@ class SwitchDriveDialog : SelectBottomSheetDialog() { } else { AccountUtils.currentDriveId = drive.id (activity as? MainActivity)?.saveLastNavigationItemSelected() - AccountUtils.reloadApp?.invoke() + AccountUtils.reloadApp?.invoke(bundleOf()) } } } diff --git a/app/src/main/java/com/infomaniak/drive/ui/SwitchUserActivity.kt b/app/src/main/java/com/infomaniak/drive/ui/SwitchUserActivity.kt index 71e4bd467a..fe3c19aad5 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/SwitchUserActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/SwitchUserActivity.kt @@ -20,6 +20,7 @@ package com.infomaniak.drive.ui import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.core.os.bundleOf import com.infomaniak.drive.R import com.infomaniak.drive.ui.login.LoginActivity import com.infomaniak.drive.ui.menu.UserAdapter @@ -41,7 +42,7 @@ class SwitchUserActivity : AppCompatActivity() { usersRecyclerView.adapter = UserAdapter(users as ArrayList) { user -> AccountUtils.currentUser = user AccountUtils.currentDriveId = -1 - AccountUtils.reloadApp?.invoke() + AccountUtils.reloadApp?.invoke(bundleOf()) } } diff --git a/app/src/main/java/com/infomaniak/drive/ui/login/MigrationActivity.kt b/app/src/main/java/com/infomaniak/drive/ui/login/MigrationActivity.kt index 6ac44e4200..003d484857 100644 --- a/app/src/main/java/com/infomaniak/drive/ui/login/MigrationActivity.kt +++ b/app/src/main/java/com/infomaniak/drive/ui/login/MigrationActivity.kt @@ -42,7 +42,6 @@ import com.infomaniak.lib.core.models.User import com.infomaniak.lib.core.networking.HttpClient import com.infomaniak.lib.login.ApiToken import com.infomaniak.lib.login.InfomaniakLogin -import kotlinx.android.synthetic.main.activity_login.* import kotlinx.android.synthetic.main.activity_migration.* import kotlinx.android.synthetic.main.fragment_intro.view.* import kotlinx.coroutines.Dispatchers 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 093071f67c..6db831825e 100644 --- a/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt +++ b/app/src/main/java/com/infomaniak/drive/utils/AccountUtils.kt @@ -18,7 +18,9 @@ package com.infomaniak.drive.utils import android.content.Context +import android.os.Bundle import android.util.Log +import androidx.core.os.bundleOf import androidx.lifecycle.LiveData import com.facebook.stetho.okhttp3.StethoInterceptor import com.infomaniak.drive.BuildConfig @@ -54,7 +56,7 @@ import java.util.concurrent.TimeUnit object AccountUtils : CredentialManager { private lateinit var userDatabase: UserDatabase - var reloadApp: (() -> Unit)? = null + var reloadApp: ((bundle: Bundle) -> Unit)? = null fun init(context: Context) { userDatabase = UserDatabase.getDatabase(context) @@ -128,7 +130,7 @@ object AccountUtils : CredentialManager { if (currentDriveId == driveRemoved.id) { getFirstDrive() GlobalScope.launch(Dispatchers.Main) { - reloadApp?.invoke() + reloadApp?.invoke(bundleOf()) } } FileController.deleteUserDriveFiles(user.id, driveRemoved.id) @@ -137,13 +139,13 @@ object AccountUtils : CredentialManager { if (fromMaintenance) { if (driveInfo.drives.main.any { drive -> !drive.maintenance }) { GlobalScope.launch(Dispatchers.Main) { - reloadApp?.invoke() + reloadApp?.invoke(bundleOf()) } } } else if (driveInfo.drives.main.all { drive -> drive.maintenance } || driveInfo.drives.main.any { drive -> drive.maintenance && drive.id == currentDriveId }) { GlobalScope.launch(Dispatchers.Main) { - reloadApp?.invoke() + reloadApp?.invoke(bundleOf()) } } @@ -187,7 +189,7 @@ object AccountUtils : CredentialManager { resetApp(context) GlobalScope.launch(Dispatchers.Main) { - reloadApp?.invoke() + reloadApp?.invoke(bundleOf()) } CloudStorageProvider.notifyRootsChanged(context)