From 235e6372305803457a1568d0f2cf48fac67603ab Mon Sep 17 00:00:00 2001 From: karntrehan Date: Tue, 11 Apr 2023 15:53:10 +0530 Subject: [PATCH] [#39] Update integration in Readme and Move to extension settings. --- README.md | 51 ++++++++++++-- .../android/activities/FormEntryActivity.java | 25 +++---- .../activities/InstanceChooserList.java | 11 +-- .../InstanceUploaderListActivity.java | 11 +-- .../initialization/ApplicationInitializer.kt | 2 +- .../collect/android/formentry/ODKView.java | 4 +- .../injection/config/AppDependencyModule.java | 24 ++++--- .../collect/android/preferences/Defaults.kt | 25 +++++-- .../SharedPreferencesSettingsProvider.kt | 9 +++ .../android/utilities/AndroidUserAgent.java | 14 ++-- .../collect/android/utilities/MediaUtils.kt | 15 ++-- .../android/widgets/AnnotateWidget.java | 12 +++- .../collect/android/widgets/ImageWidget.java | 4 +- .../android/widgets/WidgetFactory.java | 8 ++- .../collect/utilities/UserAgentProvider.java | 4 +- .../android/widgets/WidgetFactoryTest.java | 2 +- .../collect/settings/InMemSettingsProvider.kt | 4 ++ .../settings/ODKAppSettingsImporter.kt | 6 ++ .../odk/collect/settings/SettingsProvider.kt | 4 ++ .../settings/importing/SettingsImporter.kt | 37 ++++++++-- .../settings/keys/AppConfigurationKeys.kt | 1 + .../collect/settings/keys/ExtensionKeys.kt | 16 +++++ .../odk/collect/settings/keys/ProjectKeys.kt | 9 --- .../resources/client-settings.schema.json | 58 ++++++++++------ sample/.gitignore | 2 +- .../oce_sample/ODKFeatureTesterActivity.kt | 34 ++++++---- sample/src/main/res/raw/sample_settings.txt | 68 +++++++++++++++++++ 27 files changed, 343 insertions(+), 117 deletions(-) create mode 100644 odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ExtensionKeys.kt create mode 100644 sample/src/main/res/raw/sample_settings.txt diff --git a/README.md b/README.md index 197b366f32c..140eb0a5b91 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ We have also built a bunch of additional features on top of ODK collect: * **Custom theming on form screens**: This feature allows the module to customize the look and feel of the forms by providing a settings file that can be used to modify the form screens according to the user's needs. -* **Callbacks on form submission**: This feature allows the module to receive callbacks when a user +* **Callbacks on form submission**: This feature allows the module to receive callbacks when a + user submits a form, which can be used to perform custom actions based on the form submission. * **Configuration to submit results to a custom server**: This feature allows the module to send form submission results to a custom server, which is useful when integrating with other systems. @@ -52,10 +53,19 @@ embed ODK directly into them. ## Integration -### via Module +### Step 1: Setup ODK Central -1. Download - the [ODK module](https://github.com/Samagra-Development/odk-collect-extension/tree/main/odk). +To integrate ODK into your existing Android application you would also need to +setup [ODK Central](https://docs.getodk.org/central-intro/) on +a remote server that would host your ODK forms, manage them and contain submissions from users. + +More on ODK Central Installation [here](https://docs.getodk.org/central-install/) + +### Step 2: Integrate ODK Extensions + +#### via Module + +1. Download the [ODK module](/odk). 2. Copy the directory in your project folder. 3. Update your app's `settings.gradle` to include the ODK modules. @@ -103,10 +113,41 @@ implementation project(':odk:extension') 5. Build your project -### via Gradle dependency +#### via Gradle dependency **Coming soon** +### Step 3: Configure ODK + +Configure settings for ODK to work for you. Duplicate +the [sample-settings.txt](sample/src/main/res/raw/sample-settings.txt) as `settings.json` +in the same folder with the necessary fields. You can then pass the json file to setup ODK as +follows: + +```kotlin +ODKInteractor.setupODK( + settingsJson = IOUtils.toString(resources.openRawResource(R.raw.settings)), + ...) +``` + +Note: Don't forget to remove all the comments in sample-settings.txt + +All ODK settings can be +found [here](https://docs.getodk.org/collect-import-export/#list-of-keys-for-all-settings) + +All extension configurations are inside the `extension` object. + +### Step 4: Add google-services.json + +ODK Extension supports downloading all the forms as a zip and extracting them to the correct +location. In the current form the zip is downloaded only if a new zip is created. This is done by +saving the hash of the zip on firebase and comparing with the existing zip hash. Hence we need to +create a project on firebase and add it's google-services.json to our project. Detailed +steps [here](https://alphatech.technology/Blog-Entry-srk/Google-Services-Json-bek/). + +We are working on making this +optional [here](https://github.com/Samagra-Development/odk-collect-extension/issues/43). + ## Usage Wiki coming soon diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java index 8d69f222f1f..b85adcacba4 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java @@ -188,6 +188,7 @@ import org.odk.collect.material.MaterialProgressDialogFragment; import org.odk.collect.permissions.PermissionListener; import org.odk.collect.permissions.PermissionsChecker; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.ProjectKeys; import org.odk.collect.settings.keys.ProtectedProjectKeys; import org.odk.collect.shared.strings.Md5; @@ -415,9 +416,9 @@ public void onCreate(Bundle savedInstanceState) { buttonHolder = findViewById(R.id.buttonholder); // WARNING: ODK Custom Change - getWindow().setStatusBarColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_PRIMARY_COLOR))); + getWindow().setStatusBarColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_PRIMARY_COLOR))); initToolbar(); - buttonHolder.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_FOOTER_COLOR))); + buttonHolder.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_FOOTER_COLOR))); formIndexAnimationHandler = new FormIndexAnimationHandler(this); menuDelegate = new FormEntryMenuDelegate( @@ -436,8 +437,8 @@ public void onCreate(Bundle savedInstanceState) { onSwipeForward(); }); // WARNING: ODK Custom changes - nextButton.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR))); - nextButton.setTextColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR))); + nextButton.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR))); + nextButton.setTextColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR))); nextButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -445,7 +446,7 @@ public void onGlobalLayout() { Drawable nextArrow = nextButton.getCompoundDrawables()[2]; if (nextArrow != null) { nextArrow.setColorFilter( - getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR)), + getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR)), PorterDuff.Mode.SRC_IN ); } @@ -458,8 +459,8 @@ public void onGlobalLayout() { onSwipeBackward(); }); // WARNING: ODK Custom changes - backButton.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR))); - backButton.setTextColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR))); + backButton.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR))); + backButton.setTextColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR))); backButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -467,7 +468,7 @@ public void onGlobalLayout() { Drawable backArrow = backButton.getCompoundDrawables()[0]; if (backArrow != null) { backArrow.setColorFilter( - getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR)), + getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR)), PorterDuff.Mode.SRC_IN ); } @@ -795,12 +796,12 @@ private int getColor(String hash) { private void initToolbar() { Toolbar toolbar = findViewById(R.id.toolbar); // WARNING: ODK Custom Change - toolbar.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); - toolbar.setTitleTextColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + toolbar.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); + toolbar.setTitleTextColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); Drawable drawable = toolbar.getOverflowIcon(); if (drawable != null) { drawable = DrawableCompat.wrap(drawable); - DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); toolbar.setOverflowIcon(drawable); } setSupportActionBar(toolbar); @@ -1019,7 +1020,7 @@ public boolean onCreateOptionsMenu(Menu menu) { Drawable menuIcon = menu.getItem(i).getIcon(); if (menuIcon != null) { menu.getItem(i).getIcon().setColorFilter( - getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), + getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), PorterDuff.Mode.SRC_IN ); } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceChooserList.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceChooserList.java index deb9f9945b1..2486cf8fbd9 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceChooserList.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceChooserList.java @@ -52,6 +52,7 @@ import org.odk.collect.androidshared.ui.multiclicksafe.MultiClickGuard; import org.odk.collect.forms.Form; import org.odk.collect.forms.instances.Instance; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.ProjectKeys; import java.util.Arrays; @@ -85,15 +86,15 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.form_chooser_list); // WARNING: Custom ODK changes - getWindow().setStatusBarColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_PRIMARY_COLOR))); + getWindow().setStatusBarColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_PRIMARY_COLOR))); Toolbar toolbar = findViewById(R.id.toolbar); if (toolbar != null) { - toolbar.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); - toolbar.setTitleTextColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + toolbar.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); + toolbar.setTitleTextColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); Drawable drawable = toolbar.getOverflowIcon(); if (drawable != null) { drawable = DrawableCompat.wrap(drawable); - DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); toolbar.setOverflowIcon(drawable); } } @@ -165,7 +166,7 @@ public boolean onCreateOptionsMenu(Menu menu) { Drawable menuIcon = menu.getItem(i).getIcon(); if (menuIcon != null) { menu.getItem(i).getIcon().setColorFilter( - getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), + getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), PorterDuff.Mode.SRC_IN ); } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceUploaderListActivity.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceUploaderListActivity.java index 97f496b697b..4496a737290 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceUploaderListActivity.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/activities/InstanceUploaderListActivity.java @@ -59,6 +59,7 @@ import org.odk.collect.android.utilities.PlayServicesChecker; import org.odk.collect.androidshared.ui.ToastUtils; import org.odk.collect.androidshared.ui.multiclicksafe.MultiClickGuard; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.ProjectKeys; import java.util.Arrays; @@ -115,15 +116,15 @@ public void onCreate(Bundle savedInstanceState) { binding = InstanceUploaderListBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); // WARNING: Custom ODK changes - getWindow().setStatusBarColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_PRIMARY_COLOR))); + getWindow().setStatusBarColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_PRIMARY_COLOR))); Toolbar toolbar = findViewById(R.id.toolbar); if (toolbar != null) { - toolbar.setBackgroundColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); - toolbar.setTitleTextColor(getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + toolbar.setBackgroundColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR))); + toolbar.setTitleTextColor(getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); Drawable drawable = toolbar.getOverflowIcon(); if (drawable != null) { drawable = DrawableCompat.wrap(drawable); - DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); + DrawableCompat.setTint(drawable.mutate(), getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR))); toolbar.setOverflowIcon(drawable); } } @@ -270,7 +271,7 @@ public boolean onCreateOptionsMenu(Menu menu) { Drawable menuIcon = menu.getItem(i).getIcon(); if (menuIcon != null) { menu.getItem(i).getIcon().setColorFilter( - getColor(settingsProvider.getUnprotectedSettings().getString(ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), + getColor(settingsProvider.getExtensionSettings().getString(ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR)), PorterDuff.Mode.SRC_IN ); } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt b/odk/collect/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt index 437184ed540..6ec2ce2db7b 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt @@ -112,7 +112,7 @@ class ApplicationInitializer( // This has to happen on the main thread but we might call `initialize` from tests MapView(context).onCreate(null) } - OsmDroidInitializer.initialize(userAgentProvider.userAgent) + OsmDroidInitializer.initialize(userAgentProvider.getUserAgent(settingsProvider)) } catch (ignore: Exception) { // ignored } catch (ignore: Error) { diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java index 49806582e3c..a086d2d1920 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java @@ -187,8 +187,8 @@ public ODKView(ComponentActivity context, final FormEntryPrompt[] questionPrompt viewLifecycle, new FileRequesterImpl(intentLauncher, externalAppIntentProvider, formController), new StringRequesterImpl(intentLauncher, externalAppIntentProvider, formController), - formController - ); + formController, + settingsProvider); widgets = new ArrayList<>(); widgetsList = findViewById(R.id.widgets); diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyModule.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyModule.java index c184fbd8a44..4ff9ab1a41d 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyModule.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyModule.java @@ -146,6 +146,7 @@ import org.odk.collect.settings.SettingsProvider; import org.odk.collect.settings.importing.ProjectDetailsCreatorImpl; import org.odk.collect.settings.importing.SettingsChangeHandler; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.MetaKeys; import org.odk.collect.settings.keys.ProjectKeys; import org.odk.collect.shared.strings.UUIDGenerator; @@ -186,11 +187,11 @@ UserAgentProvider providesUserAgent() { @Provides @Singleton - public OpenRosaHttpInterface provideHttpInterface(MimeTypeMap mimeTypeMap, UserAgentProvider userAgentProvider) { + public OpenRosaHttpInterface provideHttpInterface(MimeTypeMap mimeTypeMap, UserAgentProvider userAgentProvider, SettingsProvider settingsProvider) { return new OkHttpConnection( new OkHttpOpenRosaServerClientProvider(new OkHttpClient()), new CollectThenSystemContentTypeMapper(mimeTypeMap), - userAgentProvider.getUserAgent() + userAgentProvider.getUserAgent(settingsProvider) ); } @@ -284,15 +285,17 @@ public QRCodeGenerator providesQRCodeGenerator(Context context) { } @Provides - public VersionInformation providesVersionInformation() { - //TODO pass from apps - return new VersionInformation(() -> "1"); + public VersionInformation providesVersionInformation(SettingsProvider settingsProvider) { + return new VersionInformation(() -> settingsProvider.getExtensionSettings().getString(ExtensionKeys.APP_VERSION)); } @Provides - public FileProvider providesFileProvider(Context context) { - //TODO pass from apps - return filePath -> getUriForFile(context, ProjectKeys.APP_PROVIDER + ".provider", new File(filePath)); + public FileProvider providesFileProvider(Context context, SettingsProvider settingsProvider) { + return filePath -> getUriForFile( + context, + settingsProvider.getExtensionSettings().getString(ExtensionKeys.APP_PROVIDER) + ".provider", + new File(filePath) + ); } @Provides @@ -328,6 +331,7 @@ public ODKAppSettingsImporter providesODKAppSettingsImporter(Context context, Pr settingsProvider, Defaults.getUnprotected(), Defaults.getProtected(), + Defaults.getExtension(), asList(context.getResources().getStringArray(R.array.project_colors)), settingsChangeHandler ); @@ -635,8 +639,8 @@ public LocationClient providesFusedLocationClient(Application application) { } @Provides - public MediaUtils providesMediaUtils(IntentLauncher intentLauncher) { - return new MediaUtils(intentLauncher, new ContentUriProvider()); + public MediaUtils providesMediaUtils(IntentLauncher intentLauncher, SettingsProvider settingsProvider) { + return new MediaUtils(intentLauncher, new ContentUriProvider(), settingsProvider); } @Provides diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt b/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt index 12cc9afc5b2..c4fead2d429 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt @@ -4,6 +4,7 @@ import com.google.android.gms.maps.GoogleMap import org.odk.collect.android.R import org.odk.collect.android.application.Collect import org.odk.collect.android.utilities.QuestionFontSizeUtils +import org.odk.collect.settings.keys.ExtensionKeys import org.odk.collect.settings.keys.ProjectKeys import org.odk.collect.settings.keys.ProtectedProjectKeys @@ -44,7 +45,8 @@ object Defaults { // server_preferences.xml hashMap[ProjectKeys.KEY_PROTOCOL] = ProjectKeys.PROTOCOL_SERVER // user_interface_preferences.xml - hashMap[ProjectKeys.KEY_APP_THEME] = Collect.getInstance().getString(R.string.app_theme_system) + hashMap[ProjectKeys.KEY_APP_THEME] = + Collect.getInstance().getString(R.string.app_theme_system) hashMap[ProjectKeys.KEY_APP_LANGUAGE] = "" hashMap[ProjectKeys.KEY_FONT_SIZE] = QuestionFontSizeUtils.DEFAULT_FONT_SIZE.toString() hashMap[ProjectKeys.KEY_NAVIGATION] = ProjectKeys.NAVIGATION_BOTH @@ -55,15 +57,24 @@ object Defaults { hashMap[ProjectKeys.KEY_USGS_MAP_STYLE] = "topographic" hashMap[ProjectKeys.KEY_GOOGLE_MAP_STYLE] = GoogleMap.MAP_TYPE_NORMAL.toString() hashMap[ProjectKeys.KEY_MAPBOX_MAP_STYLE] = "mapbox://styles/mapbox/streets-v11" - hashMap[ProjectKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR] = "#ffffff" - hashMap[ProjectKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR] = "#000000" - hashMap[ProjectKeys.FORM_ACTIVITY_PRIMARY_COLOR] = "#ffffff" - hashMap[ProjectKeys.FORM_ACTIVITY_FOOTER_COLOR] = "#ffffff" - hashMap[ProjectKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR] = "#00ffffff" - hashMap[ProjectKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR] = "#000000" return hashMap } + @JvmStatic + val extension: HashMap + get() { + return hashMapOf( + ExtensionKeys.FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR to "#ffffff", + ExtensionKeys.FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR to "#000000", + ExtensionKeys.FORM_ACTIVITY_PRIMARY_COLOR to "#ffffff", + ExtensionKeys.FORM_ACTIVITY_FOOTER_COLOR to "#ffffff", + ExtensionKeys.FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR to "#00ffffff", + ExtensionKeys.FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR to "#000000", + ExtensionKeys.APP_PROVIDER to "org.odk.collect.android", + ExtensionKeys.APP_VERSION to "1" + ) + } + @JvmStatic val protected: Map get() { diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/source/SharedPreferencesSettingsProvider.kt b/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/source/SharedPreferencesSettingsProvider.kt index 3cf4e5e9a38..65b0e415e73 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/source/SharedPreferencesSettingsProvider.kt +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/preferences/source/SharedPreferencesSettingsProvider.kt @@ -32,6 +32,14 @@ class SharedPreferencesSettingsProvider(private val context: Context) : Settings } } + override fun getExtensionSettings(projectId: String?): Settings { + val settingsId = getSettingsId(EXTENSION_SETTINGS_NAME, projectId) + + return settings.getOrPut(settingsId) { + SharedPreferencesSettings(getSharedPrefs(settingsId), Defaults.extension) + } + } + override fun clearAll(projectIds: List) { projectIds.forEach { getUnprotectedSettings(it).clear() @@ -57,5 +65,6 @@ class SharedPreferencesSettingsProvider(private val context: Context) : Settings private const val META_SETTINGS_NAME = "meta" private const val GENERAL_SETTINGS_NAME = "general_prefs" private const val ADMIN_SETTINGS_NAME = "admin_prefs" + private const val EXTENSION_SETTINGS_NAME = "extension_prefs" } } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/AndroidUserAgent.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/AndroidUserAgent.java index 565c3418a14..f94e4a4f701 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/AndroidUserAgent.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/AndroidUserAgent.java @@ -1,17 +1,21 @@ package org.odk.collect.android.utilities; import org.odk.collect.android.BuildConfig; +import org.odk.collect.settings.SettingsProvider; +import org.odk.collect.settings.keys.ExtensionKeys; +import org.odk.collect.settings.keys.ProjectKeys; +import org.odk.collect.shared.settings.Settings; import org.odk.collect.utilities.UserAgentProvider; public final class AndroidUserAgent implements UserAgentProvider { + @Override - public String getUserAgent() { - //TODO pass from Apps + public String getUserAgent(SettingsProvider settingsProvider) { + Settings settings = settingsProvider.getUnprotectedSettings(); return String.format("%s/%s %s", - "org.odk.collect.collect_app", - 1, + settings.getString(ExtensionKeys.APP_PROVIDER), + settings.getString(ExtensionKeys.APP_VERSION), System.getProperty("http.agent")); } - } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/MediaUtils.kt b/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/MediaUtils.kt index dc0ab9d5b8b..19f4d84884e 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/MediaUtils.kt +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/utilities/MediaUtils.kt @@ -20,6 +20,7 @@ import org.odk.collect.android.BuildConfig import org.odk.collect.android.R import org.odk.collect.androidshared.system.IntentLauncher import org.odk.collect.androidshared.ui.ToastUtils +import org.odk.collect.settings.SettingsProvider import org.odk.collect.settings.keys.ProjectKeys import timber.log.Timber import java.io.File @@ -36,7 +37,11 @@ import java.io.File * @author mitchellsundt@gmail.com * @author paulburke */ -class MediaUtils(private val intentLauncher: IntentLauncher, private val contentUriProvider: ContentUriProvider) { +class MediaUtils( + private val intentLauncher: IntentLauncher, + private val contentUriProvider: ContentUriProvider, + private val settingsProvider: SettingsProvider +) { fun deleteMediaFile(imageFile: String) { FileUtils.deleteAndReport(File(imageFile)) } @@ -51,13 +56,15 @@ class MediaUtils(private val intentLauncher: IntentLauncher, private val content val contentUri = contentUriProvider.getUriForFile( context, - //TODO pass from apps - ProjectKeys.APP_PROVIDER + ".provider", + settingsProvider.getUnprotectedSettings().getString(ProjectKeys.APP_PROVIDER) + ".provider", file ) if (contentUri == null) { - ToastUtils.showLongToast(context, "Can't open file. If you are on a Huawei device, this is expected and will not be fixed.") + ToastUtils.showLongToast( + context, + "Can't open file. If you are on a Huawei device, this is expected and will not be fixed." + ) return } diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/AnnotateWidget.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/AnnotateWidget.java index f8205664dee..2b9dd48366f 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/AnnotateWidget.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/AnnotateWidget.java @@ -35,6 +35,8 @@ import org.odk.collect.android.utilities.QuestionMediaManager; import org.odk.collect.android.widgets.interfaces.ButtonClickListener; import org.odk.collect.android.widgets.utilities.WaitingForDataRegistry; +import org.odk.collect.settings.SettingsProvider; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.ProjectKeys; import java.io.File; @@ -61,7 +63,12 @@ public class AnnotateWidget extends BaseImageWidget implements ButtonClickListen Button chooseButton; Button annotateButton; - public AnnotateWidget(Context context, QuestionDetails prompt, QuestionMediaManager questionMediaManager, WaitingForDataRegistry waitingForDataRegistry, String tmpImageFilePath) { + public AnnotateWidget(Context context, + QuestionDetails prompt, + QuestionMediaManager questionMediaManager, + WaitingForDataRegistry waitingForDataRegistry, + String tmpImageFilePath, + SettingsProvider settingsProvider) { super(context, prompt, questionMediaManager, waitingForDataRegistry, tmpImageFilePath); render(); @@ -173,9 +180,8 @@ private void captureImage() { // the size. boo. try { - //TODO pass from apps Uri uri = new ContentUriProvider().getUriForFile(getContext(), - ProjectKeys.APP_PROVIDER + ".provider", + settingsProvider.getExtensionSettings().getString(ExtensionKeys.APP_PROVIDER) + ".provider", new File(tmpImageFilePath)); // if this gets modified, the onActivityResult in // FormEntyActivity will also need to be updated. diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/ImageWidget.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/ImageWidget.java index 2a897b76d5c..d6d0f50a3a3 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/ImageWidget.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/ImageWidget.java @@ -39,6 +39,7 @@ import org.odk.collect.android.widgets.utilities.WaitingForDataRegistry; import org.odk.collect.androidshared.system.CameraUtils; import org.odk.collect.selfiecamera.CaptureSelfieActivity; +import org.odk.collect.settings.keys.ExtensionKeys; import org.odk.collect.settings.keys.ProjectKeys; import java.io.File; @@ -163,9 +164,8 @@ private void captureImage() { // the size. boo. try { - //TODO f Uri uri = new ContentUriProvider().getUriForFile(getContext(), - ProjectKeys.APP_PROVIDER + ".provider", + settingsProvider.getExtensionSettings().getString(ExtensionKeys.APP_PROVIDER) + ".provider", new File(tmpImageFilePath)); // if this gets modified, the onActivityResult in // FormEntyActivity will also need to be updated. diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java index 8ac968f6be9..93779b58d3b 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java @@ -64,6 +64,7 @@ import org.odk.collect.androidshared.system.IntentLauncherImpl; import org.odk.collect.audiorecorder.recording.AudioRecorder; import org.odk.collect.permissions.PermissionsProvider; +import org.odk.collect.settings.SettingsProvider; /** * Convenience class that handles creation of widgets. @@ -87,6 +88,7 @@ public class WidgetFactory { private final FileRequester fileRequester; private final StringRequester stringRequester; private final FormController formController; + private final SettingsProvider settingsProvider; public WidgetFactory(Activity activity, boolean readOnlyOverride, @@ -100,7 +102,8 @@ public WidgetFactory(Activity activity, LifecycleOwner viewLifecycle, FileRequester fileRequester, StringRequester stringRequester, - FormController formController) { + FormController formController, + SettingsProvider settingsProvider) { this.activity = activity; this.readOnlyOverride = readOnlyOverride; this.useExternalRecorder = useExternalRecorder; @@ -114,6 +117,7 @@ public WidgetFactory(Activity activity, this.fileRequester = fileRequester; this.stringRequester = stringRequester; this.formController = formController; + this.settingsProvider = settingsProvider; } public QuestionWidget createWidgetFromPrompt(FormEntryPrompt prompt, PermissionsProvider permissionsProvider) { @@ -202,7 +206,7 @@ public QuestionWidget createWidgetFromPrompt(FormEntryPrompt prompt, Permissions if (appearance.equals(Appearances.SIGNATURE)) { questionWidget = new SignatureWidget(activity, questionDetails, questionMediaManager, waitingForDataRegistry, new StoragePathProvider().getTmpImageFilePath()); } else if (appearance.contains(Appearances.ANNOTATE)) { - questionWidget = new AnnotateWidget(activity, questionDetails, questionMediaManager, waitingForDataRegistry, new StoragePathProvider().getTmpImageFilePath()); + questionWidget = new AnnotateWidget(activity, questionDetails, questionMediaManager, waitingForDataRegistry, new StoragePathProvider().getTmpImageFilePath(),settingsProvider); } else if (appearance.equals(Appearances.DRAW)) { questionWidget = new DrawWidget(activity, questionDetails, questionMediaManager, waitingForDataRegistry, new StoragePathProvider().getTmpImageFilePath()); } else if (appearance.startsWith(Appearances.EX)) { diff --git a/odk/collect/collect_app/src/main/java/org/odk/collect/utilities/UserAgentProvider.java b/odk/collect/collect_app/src/main/java/org/odk/collect/utilities/UserAgentProvider.java index 31576d2709b..646637422d6 100644 --- a/odk/collect/collect_app/src/main/java/org/odk/collect/utilities/UserAgentProvider.java +++ b/odk/collect/collect_app/src/main/java/org/odk/collect/utilities/UserAgentProvider.java @@ -1,7 +1,9 @@ package org.odk.collect.utilities; +import org.odk.collect.settings.SettingsProvider; + public interface UserAgentProvider { - String getUserAgent(); + String getUserAgent(SettingsProvider settingsProvider); } diff --git a/odk/collect/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java b/odk/collect/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java index 0ae9c41cf30..2df7e5ef1a7 100644 --- a/odk/collect/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java +++ b/odk/collect/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java @@ -37,7 +37,7 @@ public class WidgetFactoryTest { @Before public void setup() { Activity activity = CollectHelpers.buildThemedActivity(WidgetTestActivity.class).get(); - widgetFactory = new WidgetFactory(activity, false, false, null, null, null, null, mock(FormEntryViewModel.class), null, null, null, null, null); + widgetFactory = new WidgetFactory(activity, false, false, null, null, null, null, mock(FormEntryViewModel.class), null, null, null, null, null, settingsProvider); } @Test diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/InMemSettingsProvider.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/InMemSettingsProvider.kt index cb28ff58232..a914d9acdb1 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/InMemSettingsProvider.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/InMemSettingsProvider.kt @@ -20,6 +20,10 @@ class InMemSettingsProvider : SettingsProvider { return settings.getOrPut("admin:$projectId") { InMemSettings() } } + override fun getExtensionSettings(projectId: String?): Settings { + return settings.getOrPut("extension:$projectId") { InMemSettings() } + } + override fun clearAll(projectIds: List) { settings.values.forEach { it.clear() } settings.clear() diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt index f15f3402b04..9b683b03242 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/ODKAppSettingsImporter.kt @@ -1,17 +1,21 @@ package org.odk.collect.settings +import android.util.Log import org.odk.collect.projects.Project 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.validation.JsonSchemaSettingsValidator +import java.security.cert.Extension +import kotlin.math.log class ODKAppSettingsImporter( projectsRepository: ProjectsRepository, settingsProvider: SettingsProvider, generalDefaults: Map, adminDefaults: Map, + extensionDefaults: Map, projectColors: List, settingsChangedHandler: SettingsChangeHandler ) { @@ -22,6 +26,7 @@ class ODKAppSettingsImporter( JsonSchemaSettingsValidator { javaClass.getResourceAsStream("/client-settings.schema.json")!! }, generalDefaults, adminDefaults, + extensionDefaults, settingsChangedHandler, projectsRepository, ProjectDetailsCreatorImpl(projectColors, generalDefaults) @@ -31,6 +36,7 @@ class ODKAppSettingsImporter( return try { settingsImporter.fromJSON(json, project) } catch (e: Throwable) { + Log.e("ODKAppSettingsImporter", "fromJSON: " + e.printStackTrace(), e) false } } diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/SettingsProvider.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/SettingsProvider.kt index 55d4414ef86..f26ce9a0dde 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/SettingsProvider.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/SettingsProvider.kt @@ -14,5 +14,9 @@ interface SettingsProvider { fun getProtectedSettings(): Settings = getProtectedSettings(null) + fun getExtensionSettings(projectId: String?): Settings + + fun getExtensionSettings(): Settings = getExtensionSettings(null) + fun clearAll(projectIds: List) } diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt index 80ed1d91ebd..dc6047bf316 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/importing/SettingsImporter.kt @@ -14,6 +14,7 @@ internal class SettingsImporter( private val settingsValidator: SettingsValidator, private val generalDefaults: Map, private val adminDefaults: Map, + private val extensionDefaults: Map, private val settingsChangedHandler: SettingsChangeHandler, private val projectsRepository: ProjectsRepository, private val projectDetailsCreator: ProjectDetailsCreator @@ -26,9 +27,11 @@ internal class SettingsImporter( val generalSettings = settingsProvider.getUnprotectedSettings(project.uuid) val adminSettings = settingsProvider.getProtectedSettings(project.uuid) + val extensionSettings = settingsProvider.getExtensionSettings(project.uuid) generalSettings.clear() adminSettings.clear() + extensionSettings.clear() val jsonObject = JSONObject(json) @@ -38,6 +41,9 @@ internal class SettingsImporter( // Import protected settings importToPrefs(jsonObject, AppConfigurationKeys.ADMIN, adminSettings) + // Import the extensions settings + importToPrefs(jsonObject, AppConfigurationKeys.EXTENSION, extensionSettings) + // Import project details val projectDetails = if (jsonObject.has(AppConfigurationKeys.PROJECT)) { jsonObject.getJSONObject(AppConfigurationKeys.PROJECT) @@ -45,7 +51,9 @@ internal class SettingsImporter( JSONObject() } - val connectionIdentifier = if (generalSettings.getString(ProjectKeys.KEY_PROTOCOL).equals(ProjectKeys.PROTOCOL_GOOGLE_SHEETS)) { + val connectionIdentifier = if (generalSettings.getString(ProjectKeys.KEY_PROTOCOL) + .equals(ProjectKeys.PROTOCOL_GOOGLE_SHEETS) + ) { generalSettings.getString(ProjectKeys.KEY_SELECTED_GOOGLE_ACCOUNT) ?: "" } else { generalSettings.getString(ProjectKeys.KEY_SERVER_URL) ?: "" @@ -61,13 +69,18 @@ internal class SettingsImporter( loadDefaults(generalSettings, generalDefaults) loadDefaults(adminSettings, adminDefaults) + loadDefaults(extensionSettings, extensionDefaults) settingsChangedHandler.onSettingsChanged(project.uuid) return true } - private fun importToPrefs(mainJsonObject: JSONObject, childJsonObjectName: String, preferences: Settings) { + private fun importToPrefs( + mainJsonObject: JSONObject, + childJsonObjectName: String, + preferences: Settings + ) { val childJsonObject = mainJsonObject.getJSONObject(childJsonObjectName) childJsonObject.keys().forEach { @@ -88,7 +101,11 @@ internal class SettingsImporter( } } - private fun importProjectDetails(project: Project.Saved, projectJson: JSONObject, connectionIdentifier: String) { + private fun importProjectDetails( + project: Project.Saved, + projectJson: JSONObject, + connectionIdentifier: String + ) { val projectName = if (projectJson.has(AppConfigurationKeys.PROJECT_NAME)) { projectJson.getString(AppConfigurationKeys.PROJECT_NAME) } else { @@ -105,7 +122,12 @@ internal class SettingsImporter( "" } - val newProject = projectDetailsCreator.createProjectFromDetails(projectName, projectIcon, projectColor, connectionIdentifier) + val newProject = projectDetailsCreator.createProjectFromDetails( + projectName, + projectIcon, + projectColor, + connectionIdentifier + ) projectsRepository.save( project.copy( @@ -136,5 +158,10 @@ internal fun interface SettingsMigrator { } interface ProjectDetailsCreator { - fun createProjectFromDetails(name: String = "", icon: String = "", color: String = "", connectionIdentifier: String = ""): Project + fun createProjectFromDetails( + name: String = "", + icon: String = "", + color: String = "", + connectionIdentifier: String = "" + ): Project } diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/AppConfigurationKeys.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/AppConfigurationKeys.kt index 9eb911cbea0..ce7fb9fdd00 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/AppConfigurationKeys.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/AppConfigurationKeys.kt @@ -4,6 +4,7 @@ object AppConfigurationKeys { const val GENERAL = "general" const val ADMIN = "admin" const val PROJECT = "project" + const val EXTENSION = "extension" const val PROJECT_NAME = "name" const val PROJECT_ICON = "icon" diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ExtensionKeys.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ExtensionKeys.kt new file mode 100644 index 00000000000..8fa6fcebae4 --- /dev/null +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ExtensionKeys.kt @@ -0,0 +1,16 @@ +package org.odk.collect.settings.keys + +object ExtensionKeys { + + // Custom UI settings + const val FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR = "form_activity_toolbar_background_color" + const val FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR = "form_activity_toolbar_foreground_color" + const val FORM_ACTIVITY_PRIMARY_COLOR = "form_activity_primary_color" + const val FORM_ACTIVITY_FOOTER_COLOR = "form_activity_footer_color" + const val FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR = "form_activity_navigation_button_background_color" + const val FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR = "form_activity_navigation_button_foreground_color" + + //Integrating app config + const val APP_PROVIDER = "app_provider" + const val APP_VERSION = "app_version" +} diff --git a/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt index f0bdbbc06ee..301494a993c 100644 --- a/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt +++ b/odk/collect/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt @@ -74,13 +74,4 @@ object ProjectKeys { const val BASEMAP_SOURCE_STAMEN = "stamen" const val BASEMAP_SOURCE_CARTO = "carto" - // Custom UI settings - const val FORM_ACTIVITY_TOOLBAR_BACKGROUND_COLOR = "form_activity_toolbar_background_color" - const val FORM_ACTIVITY_TOOLBAR_FOREGROUND_COLOR = "form_activity_toolbar_foreground_color" - const val FORM_ACTIVITY_PRIMARY_COLOR = "form_activity_primary_color" - const val FORM_ACTIVITY_FOOTER_COLOR = "form_activity_footer_color" - const val FORM_ACTIVITY_NAVIGATION_BACKGROUND_COLOR = "form_activity_navigation_button_background_color" - const val FORM_ACTIVITY_NAVIGATION_FOREGROUND_COLOR = "form_activity_navigation_button_foreground_color" - - const val APP_PROVIDER = ""; } diff --git a/odk/collect/settings/src/main/resources/client-settings.schema.json b/odk/collect/settings/src/main/resources/client-settings.schema.json index 07acaa717be..f80d176b2d2 100644 --- a/odk/collect/settings/src/main/resources/client-settings.schema.json +++ b/odk/collect/settings/src/main/resources/client-settings.schema.json @@ -210,24 +210,6 @@ }, "background_recording": { "type": "boolean" - }, - "form_activity_toolbar_background_color": { - "type": "string" - }, - "form_activity_toolbar_foreground_color": { - "type": "string" - }, - "form_activity_primary_color": { - "type": "string" - }, - "form_activity_footer_color": { - "type": "string" - }, - "form_activity_navigation_button_background_color": { - "type": "string" - }, - "form_activity_navigation_button_foreground_color": { - "type": "string" } } }, @@ -333,6 +315,17 @@ "save_mid": { "type": "boolean" }, + "save_as": { + "type": "boolean" + }, + "mark_as_finalized": { + "type": "boolean" + } + } + }, + "extension": { + "type": "object", + "properties": { "save_by_default": { "type": "boolean" }, @@ -342,11 +335,32 @@ "exit_on_back": { "type": "boolean" }, - "save_as": { - "type": "boolean" + "form_activity_toolbar_background_color": { + "type": "string" }, - "mark_as_finalized": { - "type": "boolean" + "form_activity_toolbar_title_color": { + "type": "string" + }, + "form_activity_toolbar_foreground_color": { + "type": "string" + }, + "form_activity_primary_color": { + "type": "string" + }, + "form_activity_footer_color": { + "type": "string" + }, + "form_activity_navigation_button_background_color": { + "type": "string" + }, + "form_activity_navigation_button_foreground_color": { + "type": "string" + }, + "app_provider": { + "type": "string" + }, + "app_version": { + "type": "string" } } } diff --git a/sample/.gitignore b/sample/.gitignore index 8e27838e353..8be554c9cb6 100644 --- a/sample/.gitignore +++ b/sample/.gitignore @@ -1,3 +1,3 @@ /build -/src/main/res/raw/* \ No newline at end of file +/src/main/res/raw/*.json \ No newline at end of file diff --git a/sample/src/main/java/io/samagra/oce_sample/ODKFeatureTesterActivity.kt b/sample/src/main/java/io/samagra/oce_sample/ODKFeatureTesterActivity.kt index 0ae2bc385c7..4bdf727a694 100644 --- a/sample/src/main/java/io/samagra/oce_sample/ODKFeatureTesterActivity.kt +++ b/sample/src/main/java/io/samagra/oce_sample/ODKFeatureTesterActivity.kt @@ -68,20 +68,24 @@ class ODKFeatureTesterActivity : AppCompatActivity(), View.OnClickListener { ODKProvider.init(application) odkInteractor = ODKProvider.getOdkInteractor() progressBar.visibility = View.VISIBLE - odkInteractor.setupODK(IOUtils.toString(resources.openRawResource(R.raw.settings)), false, object : - ODKProcessListener { - override fun onProcessComplete() { - val currentProjectProvider = DaggerAppDependencyComponent.builder().application(application).build().currentProjectProvider() - currentProjectProvider.getCurrentProject().name - formsDatabaseInteractor = ODKProvider.getFormsDatabaseInteractor() - networkInteractor = ODKProvider.getFormsNetworkInteractor() - progressBar.visibility = View.INVISIBLE - } - override fun onProcessingError(exception: Exception) { - exception.printStackTrace() - progressBar.visibility = View.INVISIBLE - } - }) + odkInteractor.setupODK( + settingsJson = IOUtils.toString(resources.openRawResource(R.raw.settings)), + lazyDownload = false, + listener = object : + ODKProcessListener { + override fun onProcessComplete() { + val currentProjectProvider = DaggerAppDependencyComponent.builder().application(application).build().currentProjectProvider() + currentProjectProvider.getCurrentProject().name + formsDatabaseInteractor = ODKProvider.getFormsDatabaseInteractor() + networkInteractor = ODKProvider.getFormsNetworkInteractor() + progressBar.visibility = View.INVISIBLE + } + + override fun onProcessingError(exception: Exception) { + exception.printStackTrace() + progressBar.visibility = View.INVISIBLE + } + }) openFormsButton.setOnClickListener(this) downloadFormsButton.setOnClickListener(this) @@ -199,4 +203,4 @@ class ODKFeatureTesterActivity : AppCompatActivity(), View.OnClickListener { super.onDestroy() compositeDisposable.clear() } -} \ No newline at end of file +} diff --git a/sample/src/main/res/raw/sample_settings.txt b/sample/src/main/res/raw/sample_settings.txt new file mode 100644 index 00000000000..8047e44b5c2 --- /dev/null +++ b/sample/src/main/res/raw/sample_settings.txt @@ -0,0 +1,68 @@ +{ + "admin": { + "admin_password": false, + "admin_pw": "", + "edit_saved": true, + "send_finalized": true, + "view_sent": true, + "get_blank": true, + "delete_saved": false, + "save_mid": true, + "jump_to": false, + "access_settings": false, + "save_as": false, + "instance_form_sync": true, + "scoped_storage_used": true, + "default_to_finalized": true, + "delete_after_send": false, + "high_resolution": false, + "image_size": true, + "show_splash_screen": true, + "show_map_sdk": true, + "show_map_basemap": false, + "analytics": false, + "import_settings": false, + "change_form_metadata": false, + "change_language": false, + "change_server": false, + "change_autosend": false, + "change_navigation": false, + "change_constraint_behavior": false, + "change_font_size": false, + "change_app_language": true, + "change_protocol_settings": false, + "change_app_theme": false, + "mark_as_finalized": false + }, + "general": { + "protocol": "odk_default", + "server_url": "String", //Server URL to upload the submitted ODK forms + "navigation": "buttons", + "autosend": "wifi_and_cellular", + "appTheme": "light_theme", + "constraint_behavior": "on_swipe", + "default_to_finalized": true, + "high_resolution": false, + "image_size": "very_small", + "instance_sync": true + }, + "extension": { + //should we save the forms by-default + "save_by_default": false, + //should we exit when the form is saved + "exit_on_save": true, + //should we exit on back + "exit_on_back": false, + //Configure the UI colors + "form_activity_toolbar_background_color": "#00aa9900", + "form_activity_toolbar_foreground_color": "#000000", + "form_activity_primary_color": "#aa00ff", + "form_activity_footer_color": "#aa00ff", + "form_activity_navigation_button_background_color": "#0000aaff", + "form_activity_navigation_button_foreground_color": "#ffffff", + //Give a button to jump to beginning + "jump_to_beginning": true, + "app_provider": "your.app.package", + "app_version": "1" + } +} \ No newline at end of file