From a008eb0d04c545abb33f21c0e14f5610c41135e3 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Mon, 6 Mar 2023 15:34:25 +0100 Subject: [PATCH 01/53] Removed adding GD project from the ManualProjectCreatorDialog --- .../projects/ManualProjectCreatorDialog.kt | 72 ------------------- .../manual_project_creator_dialog_layout.xml | 34 --------- 2 files changed, 106 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/projects/ManualProjectCreatorDialog.kt b/collect_app/src/main/java/org/odk/collect/android/projects/ManualProjectCreatorDialog.kt index e5abccfe4fc..997a28ad381 100644 --- a/collect_app/src/main/java/org/odk/collect/android/projects/ManualProjectCreatorDialog.kt +++ b/collect_app/src/main/java/org/odk/collect/android/projects/ManualProjectCreatorDialog.kt @@ -1,15 +1,10 @@ package org.odk.collect.android.projects -import android.accounts.AccountManager -import android.app.Activity import android.content.Context -import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.activity.result.ActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.widget.Toolbar import androidx.core.widget.doOnTextChanged import org.odk.collect.analytics.Analytics @@ -19,18 +14,14 @@ import org.odk.collect.android.activities.MainMenuActivity import org.odk.collect.android.analytics.AnalyticsEvents import org.odk.collect.android.configure.qr.AppConfigurationGenerator import org.odk.collect.android.databinding.ManualProjectCreatorDialogLayoutBinding -import org.odk.collect.android.gdrive.GoogleAccountsManager import org.odk.collect.android.injection.DaggerUtils import org.odk.collect.android.projects.DuplicateProjectConfirmationKeys.MATCHING_PROJECT import org.odk.collect.android.projects.DuplicateProjectConfirmationKeys.SETTINGS_JSON import org.odk.collect.android.utilities.SoftKeyboardController -import org.odk.collect.androidshared.system.IntentLauncher import org.odk.collect.androidshared.ui.DialogFragmentUtils import org.odk.collect.androidshared.ui.ToastUtils import org.odk.collect.androidshared.utils.Validator import org.odk.collect.material.MaterialFullScreenDialogFragment -import org.odk.collect.permissions.PermissionListener -import org.odk.collect.permissions.PermissionsProvider import org.odk.collect.projects.ProjectsRepository import org.odk.collect.settings.SettingsProvider import javax.inject.Inject @@ -51,55 +42,16 @@ class ManualProjectCreatorDialog : @Inject lateinit var currentProjectProvider: CurrentProjectProvider - @Inject - lateinit var permissionsProvider: PermissionsProvider - - @Inject - lateinit var googleAccountsManager: GoogleAccountsManager - @Inject lateinit var projectsRepository: ProjectsRepository @Inject lateinit var settingsProvider: SettingsProvider - @Inject - lateinit var intentLauncher: IntentLauncher - lateinit var settingsConnectionMatcher: SettingsConnectionMatcher private lateinit var binding: ManualProjectCreatorDialogLayoutBinding - val googleAccountResultLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - val resultData = result.data - - if (result.resultCode == Activity.RESULT_OK && resultData != null && resultData.extras != null) { - val accountName = resultData.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) - googleAccountsManager.selectAccount(accountName) - - val settingsJson = - appConfigurationGenerator.getAppConfigurationAsJsonWithGoogleDriveDetails( - accountName - ) - - settingsConnectionMatcher.getProjectWithMatchingConnection(settingsJson) - ?.let { uuid -> - val confirmationArgs = Bundle() - confirmationArgs.putString(SETTINGS_JSON, settingsJson) - confirmationArgs.putString(MATCHING_PROJECT, uuid) - DialogFragmentUtils.showIfNotShowing( - DuplicateProjectConfirmationDialog::class.java, - confirmationArgs, - childFragmentManager - ) - } ?: run { - Analytics.log(AnalyticsEvents.GOOGLE_ACCOUNT_PROJECT) - createProject(settingsJson) - } - } - } - override fun onAttach(context: Context) { super.onAttach(context) DaggerUtils.getComponent(context).inject(this) @@ -134,10 +86,6 @@ class ManualProjectCreatorDialog : binding.addButton.setOnClickListener { handleAddingNewProject() } - - binding.gdrive.setOnClickListener { - configureGoogleAccount() - } } override fun onCloseClicked() { @@ -182,26 +130,6 @@ class ManualProjectCreatorDialog : } } - private fun configureGoogleAccount() { - permissionsProvider.requestGetAccountsPermission( - requireActivity(), - object : PermissionListener { - override fun granted() { - val intent: Intent = googleAccountsManager.accountChooserIntent - intentLauncher.launchForResult(googleAccountResultLauncher, intent) { - ToastUtils.showShortToast( - requireContext(), - getString( - R.string.activity_not_found, - getString(R.string.choose_account) - ) - ) - } - } - } - ) - } - override fun createProject(settingsJson: String) { projectCreator.createNewProject(settingsJson) ActivityUtils.startActivityAndCloseAllOthers(activity, MainMenuActivity::class.java) diff --git a/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml b/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml index a7a53be2fc8..ce1370e5b6c 100644 --- a/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml +++ b/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml @@ -96,7 +96,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/margin_standard" - app:layout_constraintBottom_toTopOf="@+id/gdrive" app:layout_constraintTop_toBottomOf="@+id/password"> - - - - - - - From 8df9c8518840c7ef1820645f89b9dc9e5485babf Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Mon, 6 Mar 2023 15:44:25 +0100 Subject: [PATCH 02/53] Removed redundant tests --- .../feature/projects/AddNewProjectTest.kt | 16 ---------------- .../settings/FormManagementSettingsTest.kt | 18 ------------------ .../feature/settings/ServerSettingsTest.java | 14 -------------- .../ManualProjectCreatorDialogTest.kt | 19 ------------------- 4 files changed, 67 deletions(-) diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/AddNewProjectTest.kt b/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/AddNewProjectTest.kt index a2faf394a18..064b2f5ad13 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/AddNewProjectTest.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/AddNewProjectTest.kt @@ -35,22 +35,6 @@ class AddNewProjectTest { .assertInactiveProject("Demo project", "demo.getodk.org") } - @Test - fun addingGdriveProjectManually_addsNewProject() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) - - rule.startAtMainMenu() - .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) - - .openProjectSettingsDialog() - .assertCurrentProject(googleAccount, "$googleAccount / Google Drive") - .assertInactiveProject("Demo project", "demo.getodk.org") - } - @Test fun addingProjectFromQrCode_addsNewProject() { val page = rule.startAtMainMenu() diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/FormManagementSettingsTest.kt b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/FormManagementSettingsTest.kt index b8d640b2fe1..9a1a80f8338 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/FormManagementSettingsTest.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/FormManagementSettingsTest.kt @@ -78,22 +78,4 @@ class FormManagementSettingsTest { assertThat(deferredTasks[0].tag, `is`(previouslyDownloadedTag)) assertThat(deferredTasks[0].repeatPeriod, `is`(1000L * 60 * 60)) } - - @Test - fun whenGoogleDriveUsingAsServer_disablesPrefsAndOnlyAllowsManualUpdates() { - testDependencies.googleAccountPicker.setDeviceAccount("steph@curry.basket") - - MainMenuPage().assertOnPage() - .enablePreviouslyDownloadedOnlyUpdates() // Enabled a different mode before setting up Google - .setGoogleAccount("steph@curry.basket") - .openProjectSettingsDialog() - .clickSettings() - .clickFormManagement() - .assertDisabled(R.string.form_update_mode_title) - .assertDisabled(R.string.form_update_frequency_title) - .assertDisabled(R.string.automatic_download) - .assertText(R.string.manual) - - assertThat(testDependencies.scheduler.deferredTasks.size, `is`(0)) - } } diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java index f8433cbcbf4..dde4d24fbe9 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java @@ -1,8 +1,5 @@ package org.odk.collect.android.feature.settings; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Rule; @@ -78,15 +75,4 @@ public void selectingGoogleAccount_showsGoogleAccountSettings() { .assertText(R.string.selected_google_account_text) .assertText(R.string.google_sheets_url); } - - @Test - public void selectingGoogleAccount_disablesAutomaticUpdates() { - MainMenuPage mainMenu = new MainMenuPage().assertOnPage() - .enablePreviouslyDownloadedOnlyUpdates(); - assertThat(testDependencies.scheduler.getDeferredTasks().size(), is(1)); - - testDependencies.googleAccountPicker.setDeviceAccount("steph@curry.basket"); - mainMenu.setGoogleAccount("steph@curry.basket"); - assertThat(testDependencies.scheduler.getDeferredTasks().size(), is(0)); - } } diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ManualProjectCreatorDialogTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ManualProjectCreatorDialogTest.kt index b72ceaeef0b..4e003033092 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ManualProjectCreatorDialogTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ManualProjectCreatorDialogTest.kt @@ -1,12 +1,9 @@ package org.odk.collect.android.projects -import android.content.Context -import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.pressBack import androidx.test.espresso.action.ViewActions.replaceText -import androidx.test.espresso.action.ViewActions.scrollTo import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers @@ -29,13 +26,11 @@ import org.odk.collect.android.activities.MainMenuActivity import org.odk.collect.android.injection.config.AppDependencyModule import org.odk.collect.android.support.CollectHelpers import org.odk.collect.android.support.Matchers.isPasswordHidden -import org.odk.collect.androidshared.system.IntentLauncher import org.odk.collect.fragmentstest.FragmentScenarioLauncherRule import org.odk.collect.projects.Project import org.odk.collect.projects.ProjectsRepository import org.odk.collect.settings.ODKAppSettingsImporter import org.odk.collect.settings.SettingsProvider -import org.odk.collect.testshared.ErrorIntentLauncher import org.robolectric.shadows.ShadowToast @RunWith(AndroidJUnit4::class) @@ -163,18 +158,4 @@ class ManualProjectCreatorDialogTest { Intents.release() } } - - @Test - fun `If activity to choose google account is not found the app should not crash`() { - CollectHelpers.overrideAppDependencyModule(object : AppDependencyModule() { - override fun providesIntentLauncher(): IntentLauncher { - return ErrorIntentLauncher() - } - }) - - launcherRule.launch(ManualProjectCreatorDialog::class.java) - onView(withText(R.string.gdrive_configure)).inRoot(isDialog()).perform(scrollTo(), click()) - val context = ApplicationProvider.getApplicationContext() - assertThat(ShadowToast.getTextOfLatestToast(), `is`(context.getString(R.string.activity_not_found, context.getString(R.string.choose_account)))) - } } From 42af6cf6d05cfa5f065736f5ac47d583ce42f8a1 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Mon, 6 Mar 2023 15:44:40 +0100 Subject: [PATCH 03/53] Removed unused strings --- strings/src/main/res/values-cs/strings.xml | 5 ----- strings/src/main/res/values-de/strings.xml | 5 ----- strings/src/main/res/values-es/strings.xml | 5 ----- strings/src/main/res/values-fa/strings.xml | 5 ----- strings/src/main/res/values-fi/strings.xml | 5 ----- strings/src/main/res/values-fr/strings.xml | 5 ----- strings/src/main/res/values-in/strings.xml | 5 ----- strings/src/main/res/values-it/strings.xml | 5 ----- strings/src/main/res/values-pt/strings.xml | 5 ----- strings/src/main/res/values-rw/strings.xml | 5 ----- strings/src/main/res/values-sw/strings.xml | 3 --- strings/src/main/res/values-tr/strings.xml | 4 ---- strings/src/main/res/values-zh/strings.xml | 5 ----- strings/src/main/res/values/strings.xml | 5 ----- 14 files changed, 67 deletions(-) diff --git a/strings/src/main/res/values-cs/strings.xml b/strings/src/main/res/values-cs/strings.xml index 3ada2ba258d..3262f0b2d78 100644 --- a/strings/src/main/res/values-cs/strings.xml +++ b/strings/src/main/res/values-cs/strings.xml @@ -196,7 +196,6 @@ Soubor SVG neexistuje! Udělat fotku Vyberte obrázek - Zvolte účet Vybraný soubor není platný obrázek Klepnutím na obrazovku udělejte snímek Přední fotoaparát není v tomto zařízení k dispozici @@ -934,10 +933,6 @@ Ručně zadejte podrobnosti projektu Po přidání projektu jej můžete nakonfigurovat v části Nastavení - - Můj projekt používá Google Drive. - - Konfigurovat Ještě nemáte žádný projekt? diff --git a/strings/src/main/res/values-de/strings.xml b/strings/src/main/res/values-de/strings.xml index 6c765eec6a8..4041bdba11f 100644 --- a/strings/src/main/res/values-de/strings.xml +++ b/strings/src/main/res/values-de/strings.xml @@ -198,7 +198,6 @@ SVG-Datei existiert nicht! Foto machen Bild auswählen - Konto auswählen Ausgewählte Datei ist kein gültiges Bild. Bildschirm berühren um ein Foto aufzunehmen Frontkamera bei diesem Gerät nicht verfügbar @@ -930,10 +929,6 @@ Projektdetails manuell eingeben Nachdem Sie Ihr Projekt hinzugefügt haben, können Sie es in den konfigurieren. - - Mein Projekt benutzt Google Drive. - - Konfigurieren Noch kein eigenes Projekt? diff --git a/strings/src/main/res/values-es/strings.xml b/strings/src/main/res/values-es/strings.xml index b4bd65b2a1b..36f972e72ab 100644 --- a/strings/src/main/res/values-es/strings.xml +++ b/strings/src/main/res/values-es/strings.xml @@ -196,7 +196,6 @@ Archivo SVG no existe Tomar la Foto Escoja la Imagen - Elegir cuenta El archivo seleccionado no es una imagen válida Toca la pantalla para tomar una foto Este dispositivo no tiene Cámara frontal disponible @@ -932,10 +931,6 @@ Ingrese manualmente los detalles del proyecto Después de agregar su proyecto, puede configurarlo en Configuración - - Mi proyecto usa Google Drive. - - Configurar ¿Aún no tienes un proyecto? diff --git a/strings/src/main/res/values-fa/strings.xml b/strings/src/main/res/values-fa/strings.xml index c690d0a93f3..ad88fab6710 100644 --- a/strings/src/main/res/values-fa/strings.xml +++ b/strings/src/main/res/values-fa/strings.xml @@ -196,7 +196,6 @@ فایل SVG موجود نیست! گرفتن عکس انتخاب تصویر - حساب را انتخاب کنید فایل انتخاب شده تصویر قابل اعتبار ندارد برای گرفتن عکس روی صفحه ضربه بزنید این دستگاه دوربین جلو موجود نیست @@ -882,10 +881,6 @@ جزئیات پروژه را به صورت دستی وارد کنید پس از اینکه پروژه خود را اضافه کردید، می توانید آن را در تنظیمات تنظیم کنید - - پروژه من از Google Drive استفاده می کند. - - تنظیم کردن هنوز پروژه ای ندارید؟ diff --git a/strings/src/main/res/values-fi/strings.xml b/strings/src/main/res/values-fi/strings.xml index ab3fba321e1..a03b766bddf 100644 --- a/strings/src/main/res/values-fi/strings.xml +++ b/strings/src/main/res/values-fi/strings.xml @@ -198,7 +198,6 @@ SVG-tiedosto puuttuu! Ota kuva Valitse kuva - Valitse tili Valittu tiedosto ei ole kelvollinen kuva Napsauta näyttöä ottaaksesi kuvan Etukamera ei ole käytettävissä tällä laitteella @@ -930,10 +929,6 @@ Syötä projektin yksityiskohdat manuaalisesti Lisättyäsi projektin voit konfiguroida sen Asetuksissa. - - Projektini käyttää Google Drive -palvelua. - - Asetukset Puuttuuko projekti vielä? diff --git a/strings/src/main/res/values-fr/strings.xml b/strings/src/main/res/values-fr/strings.xml index 1e19a8296c1..6a4fdc6e710 100644 --- a/strings/src/main/res/values-fr/strings.xml +++ b/strings/src/main/res/values-fr/strings.xml @@ -198,7 +198,6 @@ Le fichier SVG n\'existe pas ! Prendre une photo Choisir une Image - Choisir compte Le fichier choisi n\'est pas une image valide Toucher l\'écran pour prendre une photo Caméra frontale non disponible sur cet appareil @@ -933,10 +932,6 @@ Saisir les détails du projet Après avoir ajouté un projet, vous pouvez le configurer dans les Paramètres - - Mon projet utilise Google Drive. - - Configurer Pas encore de projet? diff --git a/strings/src/main/res/values-in/strings.xml b/strings/src/main/res/values-in/strings.xml index 8086ed89e6e..bc0b684285b 100644 --- a/strings/src/main/res/values-in/strings.xml +++ b/strings/src/main/res/values-in/strings.xml @@ -194,7 +194,6 @@ Berkas SVG tidak ada. Ambil Foto Pilih Gambar - Pilih akun Berkas terpilih bukan gambar yang valid Sentuh layar untuk ambil gambar Kamera depan tidak tersedia dalam perangkat ini. @@ -894,10 +893,6 @@ Konfigurasi dengan QR kode Masukkan rincian proyek secara manual - - Proyek saya menggunakan Google Drive - - Konfigurasi Belum memliki proyek? diff --git a/strings/src/main/res/values-it/strings.xml b/strings/src/main/res/values-it/strings.xml index d76b7141d2c..d6167029b59 100644 --- a/strings/src/main/res/values-it/strings.xml +++ b/strings/src/main/res/values-it/strings.xml @@ -194,7 +194,6 @@ Il file SVG non esiste! Scatta Foto Seleziona Foto - Scegli l\'account Il file selezionato non è una valida immagine Tocca lo schermo per scattare una foto Fotocamera frontale non disponibile in questo dispositivo @@ -919,10 +918,6 @@ Inserisci manualmente i dettagli del progetto Dopo aver aggiunto il progetto, puoi configurarlo in Impostazioni - - Il mio progetto utilizza Google Drive. - - Configurare Non hai ancora un Progetto? diff --git a/strings/src/main/res/values-pt/strings.xml b/strings/src/main/res/values-pt/strings.xml index 9df66b20bc0..80193d3bd8b 100644 --- a/strings/src/main/res/values-pt/strings.xml +++ b/strings/src/main/res/values-pt/strings.xml @@ -194,7 +194,6 @@ O arquivo SVG não existe! Tirar Foto Escolher Imagem - Escolher conta O arquivo selecionado não é uma imagem válida Toque na tela para tirar uma fotografia A câmera da frente não está disponível neste dispositivo @@ -919,10 +918,6 @@ Entrar com os detalhes do projeto manualmente Após adicionar o seu projeto, você pode configurá-lo em Configurações - - Meu projeto usa o Google Drive - - Configurar Não tem ainda um projeto? diff --git a/strings/src/main/res/values-rw/strings.xml b/strings/src/main/res/values-rw/strings.xml index b8978079bdb..cfc3e68a43f 100644 --- a/strings/src/main/res/values-rw/strings.xml +++ b/strings/src/main/res/values-rw/strings.xml @@ -195,7 +195,6 @@ N\'ukomea guhura n\'iki kibazo, wakigeza kuwa gusabye gukusanya amakuru.Ububiko bwa SVG ntabwo buboneka! Fata ifoto Hitamo Ishusho - Hitamo konti Ifoto wahisemo mububiko si ifoto yukuri Kora kuri screen ufate ifoto Ifoto y\'imbere ntabwo iboneka kuri iki gikoresho @@ -864,10 +863,6 @@ Birashoboka ko ari zimwe zashyizwemo mubihe bitandukanye cgw ziturutse ahatanduk Byihuze hifashishijwe kode ya QR Ukoresheje amaboko injiza amakuru kuri project - - Poroje yanjye ikoresha Google Drive - - Hindura Nta poroje ufitemo diff --git a/strings/src/main/res/values-sw/strings.xml b/strings/src/main/res/values-sw/strings.xml index e891fe86be6..f573d23c463 100644 --- a/strings/src/main/res/values-sw/strings.xml +++ b/strings/src/main/res/values-sw/strings.xml @@ -194,7 +194,6 @@ Kabrasha la SVG halipo Chukua picha Chagua picha - Chagua akaunti Faili lillilochaguliwa sio picha sahihi Bofya kioo kuchukua picha Kamera ya mbele haipo katika kifaa hiki @@ -751,8 +750,6 @@ select the wording and where to put the \n for maximum impact in your language.--> - - Mradi wangu unatumia Google Drive. diff --git a/strings/src/main/res/values-tr/strings.xml b/strings/src/main/res/values-tr/strings.xml index d905c510b39..2e3a4c71f5d 100644 --- a/strings/src/main/res/values-tr/strings.xml +++ b/strings/src/main/res/values-tr/strings.xml @@ -396,10 +396,6 @@ QR kod ile kurulum yap Proje detaylarını manuel ekle - - Projem Google Drive kullanıyor. - - Ayarla Hala projeniz yok mu? diff --git a/strings/src/main/res/values-zh/strings.xml b/strings/src/main/res/values-zh/strings.xml index 2dbbbfc180d..92d4d3da0d4 100644 --- a/strings/src/main/res/values-zh/strings.xml +++ b/strings/src/main/res/values-zh/strings.xml @@ -198,7 +198,6 @@ SVG文件不存在! 照相 选择图片 - 选择帐户 所选文件不是有效图像 点击屏幕拍照 前置摄像头在此设备上不可用 @@ -928,10 +927,6 @@ 手动输入项目详细信息 添加项目后,可以在“设置”中对其进行配置 - - 我的项目使用Google Drive。 - - 配置 还没有项目? diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index 905e9987279..b50d53bebcb 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -253,7 +253,6 @@ Take Picture Choose Image - Choose account Selected file is not a valid image Tap the screen to take a picture Front camera not available on this device @@ -1134,10 +1133,6 @@ Manually enter project details After you add your project, you can configure it in Settings - - My project uses Google Drive. - - Configure Don\'t have a project yet? From 1f094521de6c03b04ad135ec916b506c4499065e Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Mon, 6 Mar 2023 16:55:47 +0100 Subject: [PATCH 04/53] Fixed tests that use GD projects --- .../SendFinalizedFormTest.java | 19 ++++-- .../GoogleDriveDeprecationBannerTest.kt | 58 +++++++++---------- .../collect/android/support/CollectHelpers.kt | 21 +++++++ .../pages/ManualProjectCreatorDialogPage.kt | 22 ------- 4 files changed, 65 insertions(+), 55 deletions(-) diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/instancemanagement/SendFinalizedFormTest.java b/collect_app/src/androidTest/java/org/odk/collect/android/feature/instancemanagement/SendFinalizedFormTest.java index 61bb191eff0..939c41ef3f6 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/instancemanagement/SendFinalizedFormTest.java +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/instancemanagement/SendFinalizedFormTest.java @@ -7,6 +7,7 @@ import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.odk.collect.android.R; +import org.odk.collect.android.support.CollectHelpers; import org.odk.collect.android.support.TestDependencies; import org.odk.collect.android.support.pages.MainMenuPage; import org.odk.collect.android.support.pages.OkDialog; @@ -15,6 +16,7 @@ import org.odk.collect.android.support.rules.CollectTestRule; import org.odk.collect.android.support.rules.TestRuleChain; import org.odk.collect.androidtest.RecordedIntentsRule; +import org.odk.collect.projects.Project; @RunWith(AndroidJUnit4.class) public class SendFinalizedFormTest { @@ -101,12 +103,21 @@ public void whenDeleteAfterSendIsEnabled_deletesFilledForm() { @Test public void whenGoogleUsedAsServer_sendsSubmissionToSheet() { - testDependencies.googleAccountPicker.setDeviceAccount("dani@davey.com"); - testDependencies.googleApi.setAccount("dani@davey.com"); + CollectHelpers.addGDProject( + new Project.Saved( + "1", + "GD Project", + "G", + "#3e9fcc" + ), + "dani@davey.com", + testDependencies + ); rule.startAtMainMenu() - .setGoogleAccount("dani@davey.com") - .copyForm("one-question-google.xml") + .openProjectSettingsDialog() + .selectProject("GD Project") + .copyForm("one-question-google.xml", null, false, "GD Project") .startBlankForm("One Question Google") .answerQuestion("what is your age", "47") .swipeToEndScreen() diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/GoogleDriveDeprecationBannerTest.kt b/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/GoogleDriveDeprecationBannerTest.kt index 38850bda0ed..0edf59e66ef 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/GoogleDriveDeprecationBannerTest.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/projects/GoogleDriveDeprecationBannerTest.kt @@ -9,14 +9,16 @@ import org.junit.Test import org.junit.rules.RuleChain import org.odk.collect.android.R import org.odk.collect.android.activities.WebViewActivity +import org.odk.collect.android.support.CollectHelpers import org.odk.collect.android.support.TestDependencies import org.odk.collect.android.support.pages.MainMenuPage import org.odk.collect.android.support.rules.CollectTestRule import org.odk.collect.android.support.rules.TestRuleChain import org.odk.collect.androidtest.RecordedIntentsRule +import org.odk.collect.projects.Project class GoogleDriveDeprecationBannerTest { - val rule = CollectTestRule() + private val rule = CollectTestRule() private val testDependencies = TestDependencies() @get:Rule @@ -24,6 +26,20 @@ class GoogleDriveDeprecationBannerTest { .around(RecordedIntentsRule()) .around(rule) + private val gdProject1 = Project.Saved( + "1", + "GD Project 1", + "G", + "#3e9fcc" + ) + + private val gdProject2 = Project.Saved( + "2", + "GD Project 2", + "G", + "#3e9fcc" + ) + @Test fun bannerIsNotVisibleInNonGoogleDriveProjects() { rule @@ -33,27 +49,21 @@ class GoogleDriveDeprecationBannerTest { @Test fun bannerIsVisibleInGoogleDriveProjects() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) + CollectHelpers.addGDProject(gdProject1, "steph@curry.basket", testDependencies) rule.startAtMainMenu() .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) + .selectProject("GD Project 1") .assertText(R.string.google_drive_deprecation_message) } @Test fun forumThreadIsOpenedAfterClickingLearnMore() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) + CollectHelpers.addGDProject(gdProject1, "steph@curry.basket", testDependencies) rule.startAtMainMenu() .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) + .selectProject("GD Project 1") .clickOnString(R.string.learn_more_button_text) intended( @@ -66,14 +76,11 @@ class GoogleDriveDeprecationBannerTest { @Test fun dismissButtonIsVisibleOnlyAfterClickingLearnMore() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) + CollectHelpers.addGDProject(gdProject1, "steph@curry.basket", testDependencies) rule.startAtMainMenu() .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) + .selectProject("GD Project 1") .assertTextDoesNotExist(R.string.dismiss_button_text) .clickOnString(R.string.learn_more_button_text) .pressBack(MainMenuPage()) @@ -82,14 +89,11 @@ class GoogleDriveDeprecationBannerTest { @Test fun afterClickingDismissTheBannerDisappears() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) + CollectHelpers.addGDProject(gdProject1, "steph@curry.basket", testDependencies) rule.startAtMainMenu() .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) + .selectProject("GD Project 1") .clickOnString(R.string.learn_more_button_text) .pressBack(MainMenuPage()) .clickOnString(R.string.dismiss_button_text) @@ -100,22 +104,18 @@ class GoogleDriveDeprecationBannerTest { @Test fun dismissingTheBannerInOneProjectDoesNotAffectOtherProjects() { - val googleAccount = "steph@curry.basket" - testDependencies.googleAccountPicker.setDeviceAccount(googleAccount) + CollectHelpers.addGDProject(gdProject1, "steph@curry.basket", testDependencies) + CollectHelpers.addGDProject(gdProject2, "john@curry.basket", testDependencies) rule.startAtMainMenu() .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount) + .selectProject("GD Project 1") .clickOnString(R.string.learn_more_button_text) .pressBack(MainMenuPage()) .clickOnString(R.string.dismiss_button_text) .assertTextDoesNotExist(R.string.google_drive_deprecation_message) .openProjectSettingsDialog() - .clickAddProject() - .switchToManualMode() - .openGooglePickerAndSelect(googleAccount, true) + .selectProject("GD Project 2") .assertText(R.string.google_drive_deprecation_message) } } diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/support/CollectHelpers.kt b/collect_app/src/androidTest/java/org/odk/collect/android/support/CollectHelpers.kt index b82fef518f3..55e65b69a81 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/support/CollectHelpers.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/support/CollectHelpers.kt @@ -1,10 +1,14 @@ package org.odk.collect.android.support +import android.app.Application import androidx.test.core.app.ApplicationProvider import org.odk.collect.android.application.Collect +import org.odk.collect.android.injection.DaggerUtils import org.odk.collect.android.injection.config.AppDependencyComponent import org.odk.collect.android.injection.config.AppDependencyModule import org.odk.collect.android.injection.config.DaggerAppDependencyComponent +import org.odk.collect.projects.Project +import org.odk.collect.settings.keys.ProjectKeys object CollectHelpers { fun overrideAppDependencyModule(appDependencyModule: AppDependencyModule): AppDependencyComponent { @@ -16,4 +20,21 @@ object CollectHelpers { application.component = testComponent return testComponent } + + @JvmStatic + fun addGDProject(gdProject: Project.Saved, accountName: String, testDependencies: TestDependencies) { + testDependencies.googleAccountPicker.setDeviceAccount(accountName) + testDependencies.googleApi.setAccount(accountName) + + val project = DaggerUtils.getComponent(ApplicationProvider.getApplicationContext()) + .projectsRepository().save(gdProject) + + DaggerUtils + .getComponent(ApplicationProvider.getApplicationContext()) + .settingsProvider().getUnprotectedSettings(project.uuid) + .also { + it.save(ProjectKeys.KEY_PROTOCOL, ProjectKeys.PROTOCOL_GOOGLE_SHEETS) + it.save(ProjectKeys.KEY_SELECTED_GOOGLE_ACCOUNT, accountName) + } + } } diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ManualProjectCreatorDialogPage.kt b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ManualProjectCreatorDialogPage.kt index aeebbcd63f7..d3896b8ed94 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ManualProjectCreatorDialogPage.kt +++ b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ManualProjectCreatorDialogPage.kt @@ -1,14 +1,7 @@ package org.odk.collect.android.support.pages -import android.accounts.AccountManager -import android.app.Activity -import android.app.Instrumentation -import android.content.Intent import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.action.ViewActions.scrollTo -import androidx.test.espresso.intent.Intents.intending -import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction import androidx.test.espresso.matcher.ViewMatchers.withText import org.odk.collect.android.R @@ -33,21 +26,6 @@ class ManualProjectCreatorDialogPage : Page() { return this } - fun openGooglePickerAndSelect(googleAccount: String, duplicate: Boolean = false): MainMenuPage { - val data = Intent() - data.putExtra(AccountManager.KEY_ACCOUNT_NAME, googleAccount) - val activityResult = Instrumentation.ActivityResult(Activity.RESULT_OK, data) - intending(hasAction("com.google.android.gms.common.account.CHOOSE_ACCOUNT")).respondWith(activityResult) - - onView(withText(R.string.gdrive_configure)).perform(scrollTo(), click()) - - if (duplicate) { - addDuplicateProject() - } - - return MainMenuPage().assertOnPage() - } - fun addProject(): MainMenuPage { onView(withText(R.string.add)).perform(click()) return MainMenuPage().assertOnPage() From ab042a07877b011888f1830ef644ea810d91ec54 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 7 Mar 2023 13:35:04 +0100 Subject: [PATCH 05/53] Removed unused method from MainMenuPage --- .../android/support/pages/MainMenuPage.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MainMenuPage.java b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MainMenuPage.java index aa4ee25d33c..aa542a2a0bc 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MainMenuPage.java +++ b/collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MainMenuPage.java @@ -4,8 +4,6 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.scrollTo; import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.intent.Intents.intending; -import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; import static androidx.test.espresso.matcher.ViewMatchers.isClickable; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; @@ -14,11 +12,6 @@ import static org.hamcrest.core.AllOf.allOf; import static org.hamcrest.core.StringContains.containsString; -import android.accounts.AccountManager; -import android.app.Activity; -import android.app.Instrumentation; -import android.content.Intent; - import org.odk.collect.android.R; import org.odk.collect.android.support.WaitFor; @@ -170,22 +163,6 @@ public MainMenuPage enableAutoSend() { .pressBack(new MainMenuPage()); } - public MainMenuPage setGoogleAccount(String account) { - Intent data = new Intent(); - data.putExtra(AccountManager.KEY_ACCOUNT_NAME, account); - Instrumentation.ActivityResult activityResult = new Instrumentation.ActivityResult(Activity.RESULT_OK, data); - intending(hasAction("com.google.android.gms.common.account.CHOOSE_ACCOUNT")).respondWith(activityResult); - - return openProjectSettingsDialog() - .clickSettings() - .clickServerSettings() - .clickOnServerType() - .clickOnString(R.string.server_platform_google_sheets) - .clickOnString(R.string.selected_google_account_text) - .pressBack(new ProjectSettingsPage()) - .pressBack(new MainMenuPage()); - } - public MainMenuPage addAndSwitchToProject(String serverUrl) { return openProjectSettingsDialog() .clickAddProject() From abdfd73d9d5eb2f1e11e89290ac553690d8334a5 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 7 Mar 2023 14:30:22 +0100 Subject: [PATCH 06/53] =?UTF-8?q?When=20deleting=20Google=20Drive/Sheets?= =?UTF-8?q?=20project=20warn=20that=20it=20can=E2=80=99t=20be=20created=20?= =?UTF-8?q?again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectManagementPreferencesFragment.kt | 18 ++++++++++++------ strings/src/main/res/values/strings.xml | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/preferences/screens/ProjectManagementPreferencesFragment.kt b/collect_app/src/main/java/org/odk/collect/android/preferences/screens/ProjectManagementPreferencesFragment.kt index ad04c520ae5..7f1f7aabce2 100644 --- a/collect_app/src/main/java/org/odk/collect/android/preferences/screens/ProjectManagementPreferencesFragment.kt +++ b/collect_app/src/main/java/org/odk/collect/android/preferences/screens/ProjectManagementPreferencesFragment.kt @@ -20,6 +20,7 @@ import org.odk.collect.android.projects.DeleteProjectResult import org.odk.collect.android.projects.ProjectDeleter import org.odk.collect.androidshared.ui.ToastUtils import org.odk.collect.androidshared.ui.multiclicksafe.MultiClickGuard +import org.odk.collect.settings.keys.ProjectKeys import javax.inject.Inject class ProjectManagementPreferencesFragment : @@ -65,12 +66,17 @@ class ProjectManagementPreferencesFragment : val pref = Intent(activity, QRCodeTabsActivity::class.java) startActivity(pref) } - DELETE_PROJECT_KEY -> MaterialAlertDialogBuilder(requireActivity()) - .setTitle(R.string.delete_project) - .setMessage(R.string.delete_project_confirm_message) - .setNegativeButton(R.string.delete_project_no) { _: DialogInterface?, _: Int -> } - .setPositiveButton(R.string.delete_project_yes) { _: DialogInterface?, _: Int -> deleteProject() } - .show() + DELETE_PROJECT_KEY -> { + val isGDProject = ProjectKeys.PROTOCOL_GOOGLE_SHEETS == settingsProvider.getUnprotectedSettings().getString(ProjectKeys.KEY_PROTOCOL) + val message = if (isGDProject) R.string.delete_google_drive_project_confirm_message else R.string.delete_project_confirm_message + + MaterialAlertDialogBuilder(requireActivity()) + .setTitle(R.string.delete_project) + .setMessage(message) + .setNegativeButton(R.string.delete_project_no) { _: DialogInterface?, _: Int -> } + .setPositiveButton(R.string.delete_project_yes) { _: DialogInterface?, _: Int -> deleteProject() } + .show() + } } return true } diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index b50d53bebcb..a0e48e6ec6a 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -1111,6 +1111,7 @@ Switch to %s All blank forms, submissions and settings will be permanently deleted. + This is a Google Drive/Sheets project. Once you delete it, you will not be able to create it again.\n\nAll blank forms, submissions and settings will be permanently deleted. Yes No Project can\'t be deleted From 30dfa7e155ff200a5ca2519cca99182e7be2f050 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 7 Mar 2023 14:38:30 +0100 Subject: [PATCH 07/53] Do not allow to set server type in settings --- .../feature/settings/ServerSettingsTest.java | 14 ++------------ .../src/main/res/xml/server_preferences.xml | 1 + 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java index dde4d24fbe9..3f33352ee19 100644 --- a/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java +++ b/collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java @@ -7,11 +7,9 @@ import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.odk.collect.android.R; -import org.odk.collect.android.gdrive.sheets.DriveHelper; import org.odk.collect.android.support.TestDependencies; import org.odk.collect.android.support.pages.MainMenuPage; import org.odk.collect.android.support.pages.ProjectSettingsPage; -import org.odk.collect.android.support.pages.ServerSettingsPage; import org.odk.collect.android.support.rules.CollectTestRule; import org.odk.collect.android.support.rules.TestRuleChain; import org.odk.collect.androidtest.RecordedIntentsRule; @@ -58,21 +56,13 @@ public void whenUsingODKServer_canAddCredentialsForServer() { .clickOKOnDialog(new MainMenuPage()); } - /** - * This test could definitely be extended to cover form download/submit with the creation - * of a stub - * {@link DriveHelper} and - * {@link org.odk.collect.android.gdrive.GoogleAccountsManager} - */ @Test - public void selectingGoogleAccount_showsGoogleAccountSettings() { + public void selectingServerTypeIsDisabled() { new MainMenuPage().assertOnPage() .openProjectSettingsDialog() .clickSettings() .clickServerSettings() .clickOnServerType() - .clickOnButtonInDialog(R.string.server_platform_google_sheets, new ServerSettingsPage()) - .assertText(R.string.selected_google_account_text) - .assertText(R.string.google_sheets_url); + .assertTextDoesNotExist(R.string.cancel); } } diff --git a/collect_app/src/main/res/xml/server_preferences.xml b/collect_app/src/main/res/xml/server_preferences.xml index a91a3b261b5..1dfbf741061 100644 --- a/collect_app/src/main/res/xml/server_preferences.xml +++ b/collect_app/src/main/res/xml/server_preferences.xml @@ -8,5 +8,6 @@ android:entryValues="@array/protocol_entry_values" android:key="protocol" android:title="@string/type" + android:enabled="false" app:iconSpaceReserved="false" /> \ No newline at end of file From d2a0c1e839070a68c8f03004699134fd41feef43 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 7 Mar 2023 15:38:19 +0100 Subject: [PATCH 08/53] Added SettingsImportingResult to be returned instead of boolean after importing settings --- .../qr/QRCodeActivityResultDelegate.kt | 3 ++- .../configure/qr/QRCodeScannerFragment.kt | 5 +++-- .../android/projects/ProjectCreator.kt | 5 +++-- .../qr/QRCodeActivityResultDelegateTest.kt | 9 +++++---- .../android/projects/ProjectCreatorTest.kt | 11 +++++----- .../settings/ODKAppSettingsImporter.kt | 5 +++-- .../settings/importing/SettingsImporter.kt | 6 +++--- .../importing/SettingsImportingResult.kt | 6 ++++++ .../settings/ODKAppSettingsImporterTest.kt | 11 +++++----- .../importing/SettingsImporterTest.kt | 20 +++++++++---------- 10 files changed, 47 insertions(+), 34 deletions(-) create mode 100644 settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt diff --git a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt index 106f711769a..49c430ef680 100644 --- a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt +++ b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt @@ -11,6 +11,7 @@ import org.odk.collect.android.analytics.AnalyticsEvents import org.odk.collect.projects.Project.Saved import org.odk.collect.qrcode.QRCodeDecoder import org.odk.collect.settings.ODKAppSettingsImporter +import org.odk.collect.settings.importing.SettingsImportingResult import java.io.FileNotFoundException import java.io.InputStream @@ -32,7 +33,7 @@ class QRCodeActivityResultDelegate( } try { val response = qrCodeDecoder.decode(imageStream) - if (settingsImporter.fromJSON(response, project)) { + if (settingsImporter.fromJSON(response, project) == SettingsImportingResult.SUCCESS) { log(AnalyticsEvents.RECONFIGURE_PROJECT) showToast(R.string.successfully_imported_settings) ActivityUtils.startActivityAndCloseAllOthers( diff --git a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt index 4188c1adcb7..1e80ab73b4d 100644 --- a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt +++ b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt @@ -15,6 +15,7 @@ import org.odk.collect.android.storage.StoragePathProvider import org.odk.collect.androidshared.ui.ToastUtils.showLongToast import org.odk.collect.androidshared.utils.CompressionUtils import org.odk.collect.settings.ODKAppSettingsImporter +import org.odk.collect.settings.importing.SettingsImportingResult import java.io.File import java.io.IOException import java.util.zip.DataFormatException @@ -40,12 +41,12 @@ class QRCodeScannerFragment : BarCodeScannerFragment() { override fun handleScanningResult(result: BarcodeResult) { val oldProjectName = currentProjectProvider.getCurrentProject().name - val importSuccess = settingsImporter.fromJSON( + val settingsImportingResult = settingsImporter.fromJSON( CompressionUtils.decompress(result.text), currentProjectProvider.getCurrentProject() ) - if (importSuccess) { + if (settingsImportingResult == SettingsImportingResult.SUCCESS) { Analytics.log(AnalyticsEvents.RECONFIGURE_PROJECT) val newProjectName = currentProjectProvider.getCurrentProject().name diff --git a/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt b/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt index b0b16c1ee70..d6a7154e23c 100644 --- a/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt +++ b/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt @@ -4,6 +4,7 @@ import org.odk.collect.projects.Project import org.odk.collect.projects.ProjectsRepository import org.odk.collect.settings.ODKAppSettingsImporter import org.odk.collect.settings.SettingsProvider +import org.odk.collect.settings.importing.SettingsImportingResult class ProjectCreator( private val projectsRepository: ProjectsRepository, @@ -14,9 +15,9 @@ class ProjectCreator( fun createNewProject(settingsJson: String): Boolean { val savedProject = projectsRepository.save(Project.New("", "", "")) - val settingsImportedSuccessfully = settingsImporter.fromJSON(settingsJson, savedProject) + val settingsImportingResult = settingsImporter.fromJSON(settingsJson, savedProject) - return if (settingsImportedSuccessfully) { + return if (settingsImportingResult == SettingsImportingResult.SUCCESS) { currentProjectProvider.setCurrentProject(savedProject.uuid) true } else { diff --git a/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt b/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt index ceb01c46e65..ac256f77628 100644 --- a/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt @@ -20,6 +20,7 @@ import org.odk.collect.android.support.CollectHelpers import org.odk.collect.projects.Project.Saved import org.odk.collect.qrcode.QRCodeDecoder import org.odk.collect.settings.ODKAppSettingsImporter +import org.odk.collect.settings.importing.SettingsImportingResult import org.robolectric.Robolectric import org.robolectric.Shadows import org.robolectric.shadows.ShadowToast @@ -63,7 +64,7 @@ class QRCodeActivityResultDelegateTest { val delegate = QRCodeActivityResultDelegate(context, settingsImporter, fakeQRDecoder, project) val data = intentWithData("file://qr", "qr") fakeQRDecoder.register("qr", "data") - whenever(settingsImporter.fromJSON("data", project)).thenReturn(true) + whenever(settingsImporter.fromJSON("data", project)).thenReturn(SettingsImportingResult.SUCCESS) delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) } @@ -77,7 +78,7 @@ class QRCodeActivityResultDelegateTest { val delegate = QRCodeActivityResultDelegate(context, settingsImporter, fakeQRDecoder, project) val data = intentWithData("file://qr", "qr") fakeQRDecoder.register("qr", "data") - whenever(settingsImporter.fromJSON("data", project)).thenReturn(false) + whenever(settingsImporter.fromJSON("data", project)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) } @@ -91,7 +92,7 @@ class QRCodeActivityResultDelegateTest { val delegate = QRCodeActivityResultDelegate(context, settingsImporter, fakeQRDecoder, project) val data = intentWithData("file://qr", "qr") fakeQRDecoder.failsWith(QRCodeDecoder.QRCodeInvalidException()) - whenever(settingsImporter.fromJSON("data", project)).thenReturn(false) + whenever(settingsImporter.fromJSON("data", project)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) } @@ -105,7 +106,7 @@ class QRCodeActivityResultDelegateTest { val delegate = QRCodeActivityResultDelegate(context, settingsImporter, fakeQRDecoder, project) val data = intentWithData("file://qr", "qr") fakeQRDecoder.failsWith(QRCodeDecoder.QRCodeNotFoundException()) - whenever(settingsImporter.fromJSON("data", project)).thenReturn(false) + whenever(settingsImporter.fromJSON("data", project)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) } diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt index 093cdfde606..c9d5bf40afc 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt @@ -12,6 +12,7 @@ import org.odk.collect.projects.Project import org.odk.collect.projects.ProjectsRepository import org.odk.collect.settings.ODKAppSettingsImporter import org.odk.collect.settings.SettingsProvider +import org.odk.collect.settings.importing.SettingsImportingResult import org.odk.collect.shared.settings.Settings class ProjectCreatorTest { @@ -56,7 +57,7 @@ class ProjectCreatorTest { @Test fun `When importing settings failed createNewProject() should return false`() { - whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(false) + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) projectCreator.createNewProject(json) assertThat(projectCreator.createNewProject(json), `is`(false)) @@ -64,7 +65,7 @@ class ProjectCreatorTest { @Test fun `When importing settings succeeded createNewProject() should return true`() { - whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(true) + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.SUCCESS) projectCreator.createNewProject(json) assertThat(projectCreator.createNewProject(json), `is`(true)) @@ -72,7 +73,7 @@ class ProjectCreatorTest { @Test fun `When importing settings failed should created project be deleted`() { - whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(false) + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) projectCreator.createNewProject(json) verify(projectsRepository).delete(savedProject.uuid) @@ -80,7 +81,7 @@ class ProjectCreatorTest { @Test fun `When importing settings failed should prefs be cleared`() { - whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(false) + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) projectCreator.createNewProject(json) @@ -90,7 +91,7 @@ class ProjectCreatorTest { @Test fun `New project id should be set`() { - whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(true) + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.SUCCESS) projectCreator.createNewProject(json) verify(currentProjectProvider).setCurrentProject("1") diff --git a/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt b/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt index bf4c3a777b9..16e73b73ed5 100644 --- a/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt +++ b/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt @@ -6,6 +6,7 @@ import org.odk.collect.projects.ProjectsRepository import org.odk.collect.settings.importing.ProjectDetailsCreatorImpl import org.odk.collect.settings.importing.SettingsChangeHandler import org.odk.collect.settings.importing.SettingsImporter +import org.odk.collect.settings.importing.SettingsImportingResult import org.odk.collect.settings.validation.JsonSchemaSettingsValidator class ODKAppSettingsImporter( @@ -29,11 +30,11 @@ class ODKAppSettingsImporter( ProjectDetailsCreatorImpl(projectColors, generalDefaults) ) - fun fromJSON(json: String, project: Project.Saved): Boolean { + fun fromJSON(json: String, project: Project.Saved): SettingsImportingResult { return try { settingsImporter.fromJSON(json, project, deviceUnsupportedSettings) } catch (e: Throwable) { - false + SettingsImportingResult.INVALID_SETTINGS } } } diff --git a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt index 4de64b11fc5..9c6b8e7f38c 100644 --- a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt +++ b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt @@ -20,9 +20,9 @@ internal class SettingsImporter( private val projectDetailsCreator: ProjectDetailsCreator ) { - fun fromJSON(json: String, project: Project.Saved, deviceUnsupportedSettings: JSONObject): Boolean { + fun fromJSON(json: String, project: Project.Saved, deviceUnsupportedSettings: JSONObject): SettingsImportingResult { if (!settingsValidator.isValid(json)) { - return false + return SettingsImportingResult.INVALID_SETTINGS } val generalSettings = settingsProvider.getUnprotectedSettings(project.uuid) @@ -65,7 +65,7 @@ internal class SettingsImporter( settingsChangedHandler.onSettingsChanged(project.uuid) - return true + return SettingsImportingResult.SUCCESS } private fun importToPrefs( diff --git a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt new file mode 100644 index 00000000000..e4be0e8785e --- /dev/null +++ b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt @@ -0,0 +1,6 @@ +package org.odk.collect.settings.importing + +enum class SettingsImportingResult { + SUCCESS, + INVALID_SETTINGS +} diff --git a/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt b/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt index f61760b6f10..e9d7884828c 100644 --- a/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt +++ b/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt @@ -10,6 +10,7 @@ import org.mockito.kotlin.whenever import org.odk.collect.projects.InMemProjectsRepository import org.odk.collect.projects.Project import org.odk.collect.settings.importing.SettingsChangeHandler +import org.odk.collect.settings.importing.SettingsImportingResult import org.odk.collect.settings.support.SettingsUtils.assertSettingsEmpty import java.lang.RuntimeException @@ -39,7 +40,7 @@ class ODKAppSettingsImporterTest { "}", projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) ) - assertThat(result, equalTo(true)) + assertThat(result, equalTo(SettingsImportingResult.SUCCESS)) } @Test @@ -48,7 +49,7 @@ class ODKAppSettingsImporterTest { "{ \"admin\": {}}", projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) ) - assertThat(result, equalTo(false)) + assertThat(result, equalTo(SettingsImportingResult.INVALID_SETTINGS)) assertSettingsEmpty(settingsProvider.getUnprotectedSettings()) assertSettingsEmpty(settingsProvider.getProtectedSettings()) } @@ -59,7 +60,7 @@ class ODKAppSettingsImporterTest { "{ \"general\": {}}", projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) ) - assertThat(result, equalTo(false)) + assertThat(result, equalTo(SettingsImportingResult.INVALID_SETTINGS)) assertSettingsEmpty(settingsProvider.getUnprotectedSettings()) assertSettingsEmpty(settingsProvider.getProtectedSettings()) } @@ -70,7 +71,7 @@ class ODKAppSettingsImporterTest { "{\"general\":{*},\"admin\":{}}", projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) ) - assertThat(result, equalTo(false)) + assertThat(result, equalTo(SettingsImportingResult.INVALID_SETTINGS)) assertSettingsEmpty(settingsProvider.getUnprotectedSettings()) assertSettingsEmpty(settingsProvider.getProtectedSettings()) } @@ -88,6 +89,6 @@ class ODKAppSettingsImporterTest { "}", projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) ) - assertThat(result, equalTo(false)) + assertThat(result, equalTo(SettingsImportingResult.INVALID_SETTINGS)) } } diff --git a/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt b/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt index 24aef318005..65348874eab 100644 --- a/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt +++ b/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt @@ -66,9 +66,9 @@ class SettingsImporterTest { } @Test - fun whenJSONSettingsAreInvalid_returnsFalse() { + fun `when JSON settings are invalid returns 'INVALID_SETTINGS'`() { whenever(settingsValidator.isValid(emptySettings())).thenReturn(false) - assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(false)) + assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(SettingsImportingResult.INVALID_SETTINGS)) } @Test @@ -86,7 +86,7 @@ class SettingsImporterTest { JSONObject().put("key3", 5) ) - assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) assertThat(generalSettings.contains("key3"), `is`(false)) assertThat(adminSettings.contains("key3"), `is`(false)) @@ -122,7 +122,7 @@ class SettingsImporterTest { importer.fromJSON( json.toString(), currentProject, deviceUnsupportedSettings ), - `is`(true) + `is`(SettingsImportingResult.SUCCESS) ) assertThat(generalSettings.contains("key3"), `is`(true)) @@ -133,7 +133,7 @@ class SettingsImporterTest { @Test fun `for supported settings that do not exist in json save defaults`() { - assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) assertSettings( generalSettings, "key1", "default", @@ -160,7 +160,7 @@ class SettingsImporterTest { JSONObject().put("key1", 6) ) - assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) assertSettings( generalSettings, "key1", "default", @@ -183,7 +183,7 @@ class SettingsImporterTest { adminSettings, "key1", 0 ) - assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) assertSettings( generalSettings, "key1", "default", @@ -213,7 +213,7 @@ class SettingsImporterTest { projectsRepository, projectDetailsCreator ) - assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) } @Test // Migrations might use old keys that are "unknown" to the app @@ -239,7 +239,7 @@ class SettingsImporterTest { projectsRepository, projectDetailsCreator ) - assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(json.toString(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) } @Test @@ -254,7 +254,7 @@ class SettingsImporterTest { projectsRepository, projectDetailsCreator ) - assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(true)) + assertThat(importer.fromJSON(emptySettings(), currentProject, JSONObject()), `is`(SettingsImportingResult.SUCCESS)) verify(settingsChangeHandler).onSettingsChanged("1") verifyNoMoreInteractions(settingsChangeHandler) } From dcd107d10f1b7e05912638683653a5c37b683d7b Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 7 Mar 2023 21:20:34 +0100 Subject: [PATCH 09/53] Do not allow to scan qr codes with google drive protocol --- .../qr/QRCodeActivityResultDelegate.kt | 21 ++++++----- .../configure/qr/QRCodeScannerFragment.kt | 30 ++++++++------- .../android/projects/ProjectCreator.kt | 6 +-- .../projects/QrCodeProjectCreatorDialog.kt | 29 ++++++++------- .../qr/QRCodeActivityResultDelegateTest.kt | 11 ++++++ .../android/projects/ProjectCreatorTest.kt | 24 ++++++++++-- .../QrCodeProjectCreatorDialogTest.kt | 37 +++++++++++++++++++ .../settings/importing/SettingsImporter.kt | 10 +++++ .../importing/SettingsImportingResult.kt | 3 +- .../settings/ODKAppSettingsImporterTest.kt | 17 +++++++++ .../importing/SettingsImporterTest.kt | 19 ++-------- strings/src/main/res/values/strings.xml | 1 + 12 files changed, 148 insertions(+), 60 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt index 49c430ef680..a7ae00898b3 100644 --- a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt +++ b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegate.kt @@ -33,15 +33,18 @@ class QRCodeActivityResultDelegate( } try { val response = qrCodeDecoder.decode(imageStream) - if (settingsImporter.fromJSON(response, project) == SettingsImportingResult.SUCCESS) { - log(AnalyticsEvents.RECONFIGURE_PROJECT) - showToast(R.string.successfully_imported_settings) - ActivityUtils.startActivityAndCloseAllOthers( - activity, - MainMenuActivity::class.java - ) - } else { - showToast(R.string.invalid_qrcode) + + when (settingsImporter.fromJSON(response, project)) { + SettingsImportingResult.SUCCESS -> { + log(AnalyticsEvents.RECONFIGURE_PROJECT) + showToast(R.string.successfully_imported_settings) + ActivityUtils.startActivityAndCloseAllOthers( + activity, + MainMenuActivity::class.java + ) + } + SettingsImportingResult.INVALID_SETTINGS -> showToast(R.string.invalid_qrcode) + SettingsImportingResult.GD_PROJECT -> showToast(R.string.settings_with_gd_protocol) } } catch (e: QRCodeDecoder.QRCodeInvalidException) { showToast(R.string.invalid_qrcode) diff --git a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt index 1e80ab73b4d..311031eeab3 100644 --- a/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt +++ b/collect_app/src/main/java/org/odk/collect/android/configure/qr/QRCodeScannerFragment.kt @@ -46,22 +46,24 @@ class QRCodeScannerFragment : BarCodeScannerFragment() { currentProjectProvider.getCurrentProject() ) - if (settingsImportingResult == SettingsImportingResult.SUCCESS) { - Analytics.log(AnalyticsEvents.RECONFIGURE_PROJECT) + when (settingsImportingResult) { + SettingsImportingResult.SUCCESS -> { + Analytics.log(AnalyticsEvents.RECONFIGURE_PROJECT) - val newProjectName = currentProjectProvider.getCurrentProject().name - if (newProjectName != oldProjectName) { - File(storagePathProvider.getProjectRootDirPath() + File.separator + oldProjectName).delete() - File(storagePathProvider.getProjectRootDirPath() + File.separator + newProjectName).createNewFile() - } + val newProjectName = currentProjectProvider.getCurrentProject().name + if (newProjectName != oldProjectName) { + File(storagePathProvider.getProjectRootDirPath() + File.separator + oldProjectName).delete() + File(storagePathProvider.getProjectRootDirPath() + File.separator + newProjectName).createNewFile() + } - showLongToast(requireContext(), getString(R.string.successfully_imported_settings)) - ActivityUtils.startActivityAndCloseAllOthers( - requireActivity(), - MainMenuActivity::class.java - ) - } else { - showLongToast(requireContext(), getString(R.string.invalid_qrcode)) + showLongToast(requireContext(), getString(R.string.successfully_imported_settings)) + ActivityUtils.startActivityAndCloseAllOthers( + requireActivity(), + MainMenuActivity::class.java + ) + } + SettingsImportingResult.INVALID_SETTINGS -> showLongToast(requireContext(), getString(R.string.invalid_qrcode)) + SettingsImportingResult.GD_PROJECT -> showLongToast(requireContext(), getString(R.string.settings_with_gd_protocol)) } } diff --git a/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt b/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt index d6a7154e23c..2f967e13ce3 100644 --- a/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt +++ b/collect_app/src/main/java/org/odk/collect/android/projects/ProjectCreator.kt @@ -13,18 +13,18 @@ class ProjectCreator( private val settingsProvider: SettingsProvider ) { - fun createNewProject(settingsJson: String): Boolean { + fun createNewProject(settingsJson: String): SettingsImportingResult { val savedProject = projectsRepository.save(Project.New("", "", "")) val settingsImportingResult = settingsImporter.fromJSON(settingsJson, savedProject) return if (settingsImportingResult == SettingsImportingResult.SUCCESS) { currentProjectProvider.setCurrentProject(savedProject.uuid) - true + settingsImportingResult } else { settingsProvider.getUnprotectedSettings(savedProject.uuid).clear() settingsProvider.getProtectedSettings(savedProject.uuid).clear() projectsRepository.delete(savedProject.uuid) - false + settingsImportingResult } } } diff --git a/collect_app/src/main/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialog.kt b/collect_app/src/main/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialog.kt index 8f442972e9c..97f2c20c251 100644 --- a/collect_app/src/main/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialog.kt +++ b/collect_app/src/main/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialog.kt @@ -35,6 +35,7 @@ import org.odk.collect.projects.ProjectsRepository import org.odk.collect.qrcode.QRCodeDecoder import org.odk.collect.settings.ODKAppSettingsImporter import org.odk.collect.settings.SettingsProvider +import org.odk.collect.settings.importing.SettingsImportingResult import timber.log.Timber import javax.inject.Inject @@ -274,21 +275,21 @@ class QrCodeProjectCreatorDialog : } override fun createProject(settingsJson: String) { - val projectCreatedSuccessfully = projectCreator.createNewProject(settingsJson) - - if (projectCreatedSuccessfully) { - Analytics.log(AnalyticsEvents.QR_CREATE_PROJECT) - - ActivityUtils.startActivityAndCloseAllOthers(activity, MainMenuActivity::class.java) - ToastUtils.showLongToast( - requireContext(), - getString( - R.string.switched_project, - currentProjectProvider.getCurrentProject().name + when (projectCreator.createNewProject(settingsJson)) { + SettingsImportingResult.SUCCESS -> { + Analytics.log(AnalyticsEvents.QR_CREATE_PROJECT) + + ActivityUtils.startActivityAndCloseAllOthers(activity, MainMenuActivity::class.java) + ToastUtils.showLongToast( + requireContext(), + getString( + R.string.switched_project, + currentProjectProvider.getCurrentProject().name + ) ) - ) - } else { - ToastUtils.showLongToast(requireContext(), getString(R.string.invalid_qrcode)) + } + SettingsImportingResult.INVALID_SETTINGS -> ToastUtils.showLongToast(requireContext(), getString(R.string.invalid_qrcode)) + SettingsImportingResult.GD_PROJECT -> ToastUtils.showLongToast(requireContext(), getString(R.string.settings_with_gd_protocol)) } } diff --git a/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt b/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt index ac256f77628..fec1400cb3f 100644 --- a/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/configure/qr/QRCodeActivityResultDelegateTest.kt @@ -82,6 +82,17 @@ class QRCodeActivityResultDelegateTest { delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) } + @Test + fun forSelectPhotoWithGoogleDriveProtocol_whenImporting_showsInvalidToast() { + val delegate = QRCodeActivityResultDelegate(context, settingsImporter, fakeQRDecoder, project) + val data = intentWithData("file://qr", "qr") + fakeQRDecoder.register("qr", "data") + whenever(settingsImporter.fromJSON("data", project)).thenReturn(SettingsImportingResult.GD_PROJECT) + delegate.onActivityResult(QRCodeMenuDelegate.SELECT_PHOTO, Activity.RESULT_OK, data) + + assertThat(ShadowToast.getTextOfLatestToast(), equalTo(context.getString(R.string.settings_with_gd_protocol))) + } + @Test fun forSelectPhoto_whenQRCodeDecodeFailsWithInvalid_showsInvalidToast() { importSettingsFromQrCode_withInvalidQrCode() diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt index c9d5bf40afc..3202ef38235 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/ProjectCreatorTest.kt @@ -56,19 +56,27 @@ class ProjectCreatorTest { } @Test - fun `When importing settings failed createNewProject() should return false`() { + fun `When importing settings failed createNewProject() should return 'INVALID_SETTINGS'`() { whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) projectCreator.createNewProject(json) - assertThat(projectCreator.createNewProject(json), `is`(false)) + assertThat(projectCreator.createNewProject(json), `is`(SettingsImportingResult.INVALID_SETTINGS)) } @Test - fun `When importing settings succeeded createNewProject() should return true`() { + fun `When importing settings contain GD protocol createNewProject() should return 'GD_PROJECT'`() { + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.GD_PROJECT) + + projectCreator.createNewProject(json) + assertThat(projectCreator.createNewProject(json), `is`(SettingsImportingResult.GD_PROJECT)) + } + + @Test + fun `When importing settings succeeded createNewProject() should return 'SUCCESS'`() { whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.SUCCESS) projectCreator.createNewProject(json) - assertThat(projectCreator.createNewProject(json), `is`(true)) + assertThat(projectCreator.createNewProject(json), `is`(SettingsImportingResult.SUCCESS)) } @Test @@ -79,6 +87,14 @@ class ProjectCreatorTest { verify(projectsRepository).delete(savedProject.uuid) } + @Test + fun `When importing settings contain GD protocol should created project be deleted`() { + whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.GD_PROJECT) + + projectCreator.createNewProject(json) + verify(projectsRepository).delete(savedProject.uuid) + } + @Test fun `When importing settings failed should prefs be cleared`() { whenever(settingsImporter.fromJSON(json, savedProject)).thenReturn(SettingsImportingResult.INVALID_SETTINGS) diff --git a/collect_app/src/test/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialogTest.kt b/collect_app/src/test/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialogTest.kt index 64e6205db11..e3fb2ac2fa9 100644 --- a/collect_app/src/test/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialogTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/projects/QrCodeProjectCreatorDialogTest.kt @@ -180,4 +180,41 @@ class QrCodeProjectCreatorDialogTest { ) verifyNoInteractions(projectCreator) } + + @Test + fun `When QR code contains GD protocol a toast should be displayed`() { + val projectCreator = mock() + + CollectHelpers.overrideAppDependencyModule(object : AppDependencyModule() { + override fun providesBarcodeViewDecoder(): BarcodeViewDecoder { + val barcodeResult = mock { + `when`(it.text).thenReturn( + CompressionUtils.compress( + "{\n" + + " \"general\": {\n" + + " \"protocol\" : \"google_sheets\"" + + " },\n" + + " \"admin\": {\n" + + " }\n" + + "}" + ) + ) + } + + return mock { + `when`(it.waitForBarcode(any())).thenReturn(MutableLiveData(barcodeResult)) + } + } + }) + + launcherRule.launch(QrCodeProjectCreatorDialog::class.java) + assertThat( + ShadowToast.getTextOfLatestToast(), + `is`( + ApplicationProvider.getApplicationContext() + .getString(R.string.settings_with_gd_protocol) + ) + ) + verifyNoInteractions(projectCreator) + } } diff --git a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt index 9c6b8e7f38c..07459bafb06 100644 --- a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt +++ b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt @@ -33,6 +33,10 @@ internal class SettingsImporter( val jsonObject = JSONObject(json) + if (isGDProject(jsonObject)) { + return SettingsImportingResult.GD_PROJECT + } + // Import unprotected settings importToPrefs(jsonObject, AppConfigurationKeys.GENERAL, generalSettings, deviceUnsupportedSettings) @@ -68,6 +72,12 @@ internal class SettingsImporter( return SettingsImportingResult.SUCCESS } + private fun isGDProject(jsonObject: JSONObject): Boolean { + val generalSettings = jsonObject.getJSONObject(AppConfigurationKeys.GENERAL) + return generalSettings.has(ProjectKeys.KEY_PROTOCOL) && + generalSettings.get(ProjectKeys.KEY_PROTOCOL) == ProjectKeys.PROTOCOL_GOOGLE_SHEETS + } + private fun importToPrefs( mainJsonObject: JSONObject, childJsonObjectName: String, diff --git a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt index e4be0e8785e..f8f78519ae7 100644 --- a/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt +++ b/settings/src/main/java/org/odk/collect/settings/importing/SettingsImportingResult.kt @@ -2,5 +2,6 @@ package org.odk.collect.settings.importing enum class SettingsImportingResult { SUCCESS, - INVALID_SETTINGS + INVALID_SETTINGS, + GD_PROJECT } diff --git a/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt b/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt index e9d7884828c..a95fe4b43e1 100644 --- a/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt +++ b/settings/src/test/java/org/odk/collect/settings/ODKAppSettingsImporterTest.kt @@ -91,4 +91,21 @@ class ODKAppSettingsImporterTest { ) assertThat(result, equalTo(SettingsImportingResult.INVALID_SETTINGS)) } + + @Test + fun `rejects JSON with google_sheets protocol`() { + val result = settingsImporter.fromJSON( + "{\n" + + " \"general\": {\n" + + " \"protocol\" : \"google_sheets\"" + + " },\n" + + " \"admin\": {\n" + + " }\n" + + "}", + projectsRepository.save(Project.New("Flat", "AS", "#ff0000")) + ) + assertThat(result, equalTo(SettingsImportingResult.GD_PROJECT)) + assertSettingsEmpty(settingsProvider.getUnprotectedSettings()) + assertSettingsEmpty(settingsProvider.getProtectedSettings()) + } } diff --git a/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt b/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt index 65348874eab..5bed761c6f4 100644 --- a/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt +++ b/settings/src/test/java/org/odk/collect/settings/importing/SettingsImporterTest.kt @@ -315,25 +315,14 @@ class SettingsImporterTest { } @Test - fun `when protocol is Google Drive and project name not set, project name falls back to Google account`() { - val generalJson = JSONObject() - .put(ProjectKeys.KEY_PROTOCOL, ProjectKeys.PROTOCOL_GOOGLE_SHEETS) - .put(ProjectKeys.KEY_SELECTED_GOOGLE_ACCOUNT, "foo@bar.baz") + fun `when protocol is Google Drive returns GD_PROJECT`() { + val generalJson = JSONObject().put(ProjectKeys.KEY_PROTOCOL, ProjectKeys.PROTOCOL_GOOGLE_SHEETS) + val settings = JSONObject() .put(AppConfigurationKeys.GENERAL, generalJson) .put(AppConfigurationKeys.ADMIN, JSONObject()) - whenever( - projectDetailsCreator.createProjectFromDetails( - any(), - any(), - any(), - any() - ) - ).thenReturn(Project.New("A", "B", "C")) - - importer.fromJSON(settings.toString(), currentProject, JSONObject()) - verify(projectDetailsCreator).createProjectFromDetails("", "", "", "foo@bar.baz") + assertThat(importer.fromJSON(settings.toString(), currentProject, JSONObject()), `is`(SettingsImportingResult.GD_PROJECT)) } private fun emptySettings(): String { diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index a0e48e6ec6a..374949e6608 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -1049,6 +1049,7 @@ QR code does not contain valid settings QR Code not found in the selected image Current settings are corrupt. From project management settings, reset settings or import working ones. + Google Drive/Sheets projects can no longer be created