Full Code of opendatakit/collect for AI

master 77b1124ad9a2 cached
2434 files
11.5 MB
3.2M tokens
5828 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (13,013K chars total). Download the full file to get everything.
Repository: opendatakit/collect
Branch: master
Commit: 77b1124ad9a2
Files: 2434
Total size: 11.5 MB

Directory structure:
gitextract_2lkczetw/

├── .circleci/
│   ├── config.yml
│   ├── generate-app-test-list.sh
│   ├── gradle-large.properties
│   ├── gradle.properties
│   └── test_modules.txt
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── ISSUE_TEMPLATE/
│   │   └── config.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── TESTING_RESULT_TEMPLATES.md
├── .gitignore
├── .hgtags
├── LICENSE.md
├── README.md
├── SECURITY.md
├── analytics/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── analytics/
│                               ├── Analytics.kt
│                               ├── BlockableFirebaseAnalytics.kt
│                               └── NoopAnalytics.kt
├── androidshared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── androidshared/
│       │                       └── bitmap/
│       │                           ├── ImageCompressorTest.kt
│       │                           └── ImageFileUtilsTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── androidshared/
│       │   │                   ├── async/
│       │   │                   │   └── TrackableWorker.kt
│       │   │                   ├── bitmap/
│       │   │                   │   ├── ImageCompressor.kt
│       │   │                   │   └── ImageFileUtils.kt
│       │   │                   ├── data/
│       │   │                   │   ├── AppState.kt
│       │   │                   │   ├── Consumable.kt
│       │   │                   │   └── Data.kt
│       │   │                   ├── livedata/
│       │   │                   │   ├── LiveDataExt.kt
│       │   │                   │   ├── LiveDataUtils.java
│       │   │                   │   └── NonNullLiveData.kt
│       │   │                   ├── system/
│       │   │                   │   ├── BroadcastReceiverRegister.kt
│       │   │                   │   ├── CameraUtils.java
│       │   │                   │   ├── ContextExt.kt
│       │   │                   │   ├── ExternalFilesUtils.kt
│       │   │                   │   ├── IntentLauncher.kt
│       │   │                   │   ├── OpenGLVersionChecker.kt
│       │   │                   │   ├── PlayServicesChecker.java
│       │   │                   │   ├── ProcessRestoreDetector.kt
│       │   │                   │   └── UriExt.kt
│       │   │                   ├── ui/
│       │   │                   │   ├── AlertStore.kt
│       │   │                   │   ├── Animations.kt
│       │   │                   │   ├── ColorPickerDialog.kt
│       │   │                   │   ├── ComposeThemeProvider.kt
│       │   │                   │   ├── DialogFragmentUtils.kt
│       │   │                   │   ├── DialogUtils.kt
│       │   │                   │   ├── DisplayString.kt
│       │   │                   │   ├── EdgeToEdge.kt
│       │   │                   │   ├── FragmentFactoryBuilder.kt
│       │   │                   │   ├── GroupClickListener.kt
│       │   │                   │   ├── ListFragmentStateAdapter.kt
│       │   │                   │   ├── MenuExt.kt
│       │   │                   │   ├── ObviousProgressBar.kt
│       │   │                   │   ├── OneSignTextWatcher.kt
│       │   │                   │   ├── PrefUtils.kt
│       │   │                   │   ├── ReturnToAppActivity.kt
│       │   │                   │   ├── SnackbarUtils.kt
│       │   │                   │   ├── ToastUtils.kt
│       │   │                   │   ├── compose/
│       │   │                   │   │   └── Margins.kt
│       │   │                   │   └── multiclicksafe/
│       │   │                   │       ├── DoubleClickSafeMaterialButton.kt
│       │   │                   │       ├── MultiClickGuard.kt
│       │   │                   │       ├── MultiClickSafeMaterialButton.kt
│       │   │                   │       ├── MultiClickSafeTextInputEditText.kt
│       │   │                   │       └── MultiClickSaveOnClickListener.kt
│       │   │                   └── utils/
│       │   │                       ├── AppBarUtils.kt
│       │   │                       ├── ColorUtils.kt
│       │   │                       ├── CompressionUtils.kt
│       │   │                       ├── FileExt.kt
│       │   │                       ├── InMemUniqueIdGenerator.kt
│       │   │                       ├── PathUtils.kt
│       │   │                       ├── PreferenceFragmentCompatUtils.kt
│       │   │                       ├── ScreenUtils.java
│       │   │                       ├── SettingsUniqueIdGenerator.kt
│       │   │                       ├── UniqueIdGenerator.kt
│       │   │                       └── Validator.kt
│       │   └── res/
│       │       ├── color/
│       │       │   ├── color_error_button_icon.xml
│       │       │   ├── color_on_primary_low_emphasis.xml
│       │       │   ├── color_on_surface_high_emphasis.xml
│       │       │   ├── color_on_surface_low_emphasis.xml
│       │       │   ├── color_on_surface_medium_emphasis.xml
│       │       │   └── color_primary_low_emphasis.xml
│       │       ├── drawable/
│       │       │   ├── color_circle.xml
│       │       │   ├── ic_close_24.xml
│       │       │   ├── list_item_divider.xml
│       │       │   ├── radio_button_inset.xml
│       │       │   └── shadow_up.xml
│       │       ├── layout/
│       │       │   ├── app_bar_layout.xml
│       │       │   └── color_picker_dialog_layout.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── color_picker_dialog_colors.xml
│       │           ├── dimens.xml
│       │           └── styles.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── androidshared/
│           │                   ├── async/
│           │                   │   └── TrackableWorkerTest.kt
│           │                   ├── livedata/
│           │                   │   └── LiveDataUtilsTest.kt
│           │                   ├── system/
│           │                   │   └── UriExtTest.kt
│           │                   ├── ui/
│           │                   │   ├── ColorPickerDialogTest.kt
│           │                   │   ├── OneSignTextWatcherTest.kt
│           │                   │   └── ReturnToAppActivityTest.kt
│           │                   └── utils/
│           │                       ├── ColorUtilsTest.kt
│           │                       ├── CompressionUtilsTest.kt
│           │                       ├── DialogFragmentUtilsTest.java
│           │                       ├── InMemUniqueIdGeneratorTest.kt
│           │                       ├── IntentLauncherImplTest.kt
│           │                       ├── PathUtilsTest.kt
│           │                       ├── SettingsUniqueIdGeneratorTest.kt
│           │                       ├── UniqueIdGeneratorTest.kt
│           │                       └── ValidatorTest.kt
│           └── resources/
│               └── robolectric.properties
├── androidtest/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── androidtest/
│                               ├── ActivityScenarioExtensions.kt
│                               ├── ActivityScenarioLauncherRule.kt
│                               ├── DrawableMatcher.kt
│                               ├── FakeLifecycleOwner.kt
│                               ├── FragmentScenarioExtensions.kt
│                               ├── LiveDataTestUtils.kt
│                               ├── MainDispatcherRule.kt
│                               ├── NodeInteractionExtensions.kt
│                               └── RecordedIntentsRule.kt
├── async/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── async/
│       │                       ├── Cancellable.kt
│       │                       ├── OngoingWorkListener.kt
│       │                       ├── Scheduler.kt
│       │                       ├── SchedulerAsyncTaskMimic.kt
│       │                       ├── SchedulerBuilder.kt
│       │                       ├── ScopeCancellable.kt
│       │                       ├── TaskRunner.kt
│       │                       ├── TaskSpec.kt
│       │                       ├── TaskSpecRunner.kt
│       │                       ├── TaskSpecScheduler.kt
│       │                       ├── coroutines/
│       │                       │   └── CoroutineTaskRunner.kt
│       │                       ├── network/
│       │                       │   ├── ConnectivityProvider.kt
│       │                       │   └── NetworkStateProvider.kt
│       │                       ├── services/
│       │                       │   └── ForegroundServiceTaskSpecRunner.kt
│       │                       └── workmanager/
│       │                           ├── TaskSpecWorker.kt
│       │                           └── WorkManagerTaskSpecScheduler.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── async/
│                               ├── TaskSpecTest.kt
│                               └── workmanager/
│                                   └── TaskSpecWorkerTest.kt
├── audio-clips/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── audioclips/
│       │                       ├── AudioClipViewModel.kt
│       │                       ├── AudioPlayer.kt
│       │                       ├── AudioPlayerFactory.kt
│       │                       ├── Clip.kt
│       │                       ├── PlaybackFailedException.kt
│       │                       └── ThreadSafeMediaPlayerWrapper.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── audioclips/
│                               └── AudioClipViewModelTest.kt
├── audio-recorder/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── audiorecorder/
│       │                       ├── DaggerSetup.kt
│       │                       ├── mediarecorder/
│       │                       │   └── MediaRecorderRecordingResource.kt
│       │                       ├── recorder/
│       │                       │   ├── Recorder.kt
│       │                       │   ├── RecordingResource.kt
│       │                       │   └── RecordingResourceRecorder.kt
│       │                       ├── recording/
│       │                       │   ├── AudioRecorder.kt
│       │                       │   ├── AudioRecorderFactory.kt
│       │                       │   ├── AudioRecorderService.kt
│       │                       │   └── internal/
│       │                       │       ├── ForegroundServiceAudioRecorder.kt
│       │                       │       ├── RecordingForegroundServiceNotification.kt
│       │                       │       └── RecordingRepository.kt
│       │                       └── testsupport/
│       │                           └── StubAudioRecorder.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── audiorecorder/
│           │                   ├── mediarecorder/
│           │                   │   └── AMRRecordingResourceTest.kt
│           │                   ├── recorder/
│           │                   │   └── RecordingResourceRecorderTest.kt
│           │                   ├── recording/
│           │                   │   ├── AudioRecorderTest.kt
│           │                   │   └── internal/
│           │                   │       ├── AudioRecorderServiceTest.kt
│           │                   │       ├── ForegroundServiceAudioRecorderTest.kt
│           │                   │       └── RecordingForegroundServiceNotificationTest.kt
│           │                   ├── support/
│           │                   │   └── FakeRecorder.kt
│           │                   └── testsupport/
│           │                       ├── RobolectricApplication.kt
│           │                       └── StubAudioRecorderTest.kt
│           └── resources/
│               └── robolectric.properties
├── benchmark.sh
├── build.gradle
├── check-size.sh
├── codecov.yml
├── collect_app/
│   ├── build.gradle
│   ├── google-services.json
│   ├── libs/
│   │   └── bikram-sambat-1.8.0.jar
│   ├── proguard-rules.txt
│   └── src/
│       ├── androidTest/
│       │   ├── assets/
│       │   │   └── instances/
│       │   │       ├── One Question_2021-06-22_15-55-50.xml
│       │   │       └── one-question-google_2023-08-08_14-51-00.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── android/
│       │                       ├── benchmark/
│       │                       │   ├── EntitiesBenchmarkTest.kt
│       │                       │   ├── FormsUpdateBenchmarkTest.kt
│       │                       │   ├── SearchBenchmarkTest.kt
│       │                       │   └── support/
│       │                       │       └── Benchmarker.kt
│       │                       ├── feature/
│       │                       │   ├── entitymanagement/
│       │                       │   │   └── ViewEntitiesTest.kt
│       │                       │   ├── external/
│       │                       │   │   ├── AndroidShortcutsTest.kt
│       │                       │   │   ├── FormDownloadActionTest.kt
│       │                       │   │   ├── FormEditActionTest.kt
│       │                       │   │   ├── FormPickActionTest.kt
│       │                       │   │   ├── InstanceEditActionTest.kt
│       │                       │   │   ├── InstancePickActionTest.kt
│       │                       │   │   └── InstanceUploadActionTest.kt
│       │                       │   ├── formentry/
│       │                       │   │   ├── AddRepeatTest.kt
│       │                       │   │   ├── AudioAutoplayTest.kt
│       │                       │   │   ├── AudioRecordingTest.java
│       │                       │   │   ├── BackgroundAudioRecordingTest.java
│       │                       │   │   ├── CascadingSelectTest.kt
│       │                       │   │   ├── CatchFormDesignExceptionsTest.kt
│       │                       │   │   ├── ContextMenuTest.java
│       │                       │   │   ├── DeletingRepeatGroupsTest.java
│       │                       │   │   ├── EncryptedFormTest.kt
│       │                       │   │   ├── ExternalAudioRecordingTest.java
│       │                       │   │   ├── ExternalSecondaryInstanceTest.java
│       │                       │   │   ├── ExternalSelectsTest.kt
│       │                       │   │   ├── FieldListUpdateTest.kt
│       │                       │   │   ├── FillBlankFormWithRepeatGroupTest.kt
│       │                       │   │   ├── FormEndTest.kt
│       │                       │   │   ├── FormHierarchyTest.java
│       │                       │   │   ├── FormLanguageTest.java
│       │                       │   │   ├── FormMediaTest.kt
│       │                       │   │   ├── FormMetadataTest.kt
│       │                       │   │   ├── FormNavigationTest.kt
│       │                       │   │   ├── FormSaveTest.kt
│       │                       │   │   ├── FormStylingTest.kt
│       │                       │   │   ├── GuidanceTest.kt
│       │                       │   │   ├── ImageLoadingTest.kt
│       │                       │   │   ├── IntentGroupTest.kt
│       │                       │   │   ├── InvalidFormTest.kt
│       │                       │   │   ├── LikertTest.java
│       │                       │   │   ├── NestedIntentGroupTest.kt
│       │                       │   │   ├── QuickSaveTest.java
│       │                       │   │   ├── QuittingFormTest.java
│       │                       │   │   ├── RankingWidgetWithCSVTest.java
│       │                       │   │   ├── RequiredAndConstraintQuestionTest.kt
│       │                       │   │   ├── SaveIncompleteTest.kt
│       │                       │   │   ├── SavePointTest.kt
│       │                       │   │   ├── SearchAppearancesTest.kt
│       │                       │   │   ├── audit/
│       │                       │   │   │   ├── AuditTest.kt
│       │                       │   │   │   ├── IdentifyUserTest.kt
│       │                       │   │   │   └── TrackChangesReasonTest.kt
│       │                       │   │   ├── backgroundlocation/
│       │                       │   │   │   ├── LocationTrackingAuditTest.java
│       │                       │   │   │   └── SetGeopointActionTest.java
│       │                       │   │   ├── dynamicpreload/
│       │                       │   │   │   ├── DynamicPreLoadedDataPullTest.kt
│       │                       │   │   │   └── DynamicPreLoadedDataSelects.java
│       │                       │   │   └── entities/
│       │                       │   │       ├── EntityFormApprovalTest.kt
│       │                       │   │       ├── EntityFormCreateUpdateTest.kt
│       │                       │   │       ├── EntityFormEditTest.kt
│       │                       │   │       ├── EntityFormLockingTest.kt
│       │                       │   │       ├── EntityFormSpecVersionTest.kt
│       │                       │   │       └── EntityListSyncTest.kt
│       │                       │   ├── formmanagement/
│       │                       │   │   ├── BulkFinalizationTest.kt
│       │                       │   │   ├── DeleteBlankFormTest.java
│       │                       │   │   ├── FormUpdateTest.kt
│       │                       │   │   ├── FormsAdbTest.java
│       │                       │   │   ├── GetBlankFormsTest.java
│       │                       │   │   ├── HideOldVersionsTest.java
│       │                       │   │   ├── ManualUpdatesTest.java
│       │                       │   │   ├── MatchExactlyTest.kt
│       │                       │   │   └── PreviouslyDownloadedOnlyTest.kt
│       │                       │   ├── instancemanagement/
│       │                       │   │   ├── AutoSendTest.kt
│       │                       │   │   ├── DeleteSavedFormTest.kt
│       │                       │   │   ├── EditSavedFormTest.kt
│       │                       │   │   ├── InstancesAdbTest.kt
│       │                       │   │   ├── PartialSubmissionTest.kt
│       │                       │   │   └── SendFinalizedFormTest.kt
│       │                       │   ├── maps/
│       │                       │   │   └── FormMapTest.kt
│       │                       │   ├── projects/
│       │                       │   │   ├── AddNewProjectTest.kt
│       │                       │   │   ├── DeleteProjectTest.kt
│       │                       │   │   ├── GoogleDriveDeprecationTest.kt
│       │                       │   │   ├── LaunchScreenTest.kt
│       │                       │   │   ├── MobileDeviceManagementTest.kt
│       │                       │   │   ├── ProjectsAdbTest.kt
│       │                       │   │   ├── SwitchProjectTest.kt
│       │                       │   │   └── UpdateProjectTest.kt
│       │                       │   ├── settings/
│       │                       │   │   ├── ConfigureWithQRCodeTest.java
│       │                       │   │   ├── FormEntrySettingsTest.kt
│       │                       │   │   ├── FormManagementSettingsTest.kt
│       │                       │   │   ├── FormMetadataSettingsTest.kt
│       │                       │   │   ├── MovingBackwardsTest.kt
│       │                       │   │   ├── ResetProjectTest.kt
│       │                       │   │   ├── ServerSettingsTest.java
│       │                       │   │   └── SettingLanguageTest.kt
│       │                       │   └── smoke/
│       │                       │       ├── AllWidgetsFormTest.kt
│       │                       │       ├── BadServerTest.java
│       │                       │       └── GetAndSubmitFormTest.java
│       │                       ├── instrumented/
│       │                       │   ├── forms/
│       │                       │   │   └── FormUtilsTest.java
│       │                       │   ├── tasks/
│       │                       │   │   └── FormLoaderTaskTest.java
│       │                       │   └── utilities/
│       │                       │       ├── CustomSQLiteQueryExecutionTest.java
│       │                       │       └── DateTimeUtilsTest.java
│       │                       └── support/
│       │                           ├── ActivityHelpers.java
│       │                           ├── CollectHelpers.kt
│       │                           ├── ContentProviderUtils.kt
│       │                           ├── CountingTaskExecutorIdlingResource.java
│       │                           ├── DummyActivityLauncher.kt
│       │                           ├── FakeClickableMapFragment.kt
│       │                           ├── FakeLocationClient.java
│       │                           ├── FakeNetworkStateProvider.kt
│       │                           ├── StorageUtils.kt
│       │                           ├── StubOpenRosaServer.kt
│       │                           ├── SubmissionParser.kt
│       │                           ├── TestDependencies.kt
│       │                           ├── TranslatedStringBuilder.kt
│       │                           ├── actions/
│       │                           │   └── RotateAction.java
│       │                           ├── async/
│       │                           │   ├── AsyncWorkTracker.kt
│       │                           │   ├── AsyncWorkTrackerIdlingResource.kt
│       │                           │   ├── TrackingCoroutineAndWorkManagerScheduler.kt
│       │                           │   └── TrackingCoroutineDispatcher.kt
│       │                           ├── matchers/
│       │                           │   ├── CustomMatchers.kt
│       │                           │   └── ToastMatcher.java
│       │                           ├── pages/
│       │                           │   ├── AboutPage.java
│       │                           │   ├── AccessControlPage.kt
│       │                           │   ├── AddNewRepeatDialog.kt
│       │                           │   ├── AppClosedPage.kt
│       │                           │   ├── AsyncPage.kt
│       │                           │   ├── BlankFormSearchPage.java
│       │                           │   ├── BulkFinalizationConfirmationDialogPage.kt
│       │                           │   ├── CancelRecordingDialog.java
│       │                           │   ├── ChangesReasonPromptPage.java
│       │                           │   ├── DeleteSavedFormPage.java
│       │                           │   ├── DeleteSelectedDialog.java
│       │                           │   ├── EditSavedFormPage.java
│       │                           │   ├── EntitiesPage.kt
│       │                           │   ├── EntityListPage.kt
│       │                           │   ├── ErrorDialog.kt
│       │                           │   ├── ErrorPage.kt
│       │                           │   ├── ExperimentalPage.java
│       │                           │   ├── FillBlankFormPage.java
│       │                           │   ├── FirstLaunchPage.kt
│       │                           │   ├── FormEndPage.java
│       │                           │   ├── FormEntryPage.java
│       │                           │   ├── FormHierarchyPage.kt
│       │                           │   ├── FormManagementPage.java
│       │                           │   ├── FormMapPage.java
│       │                           │   ├── FormMetadataPage.java
│       │                           │   ├── FormsDownloadResultPage.kt
│       │                           │   ├── GetBlankFormPage.java
│       │                           │   ├── IdentifyUserPromptPage.java
│       │                           │   ├── ListPreferenceDialog.java
│       │                           │   ├── MainMenuPage.java
│       │                           │   ├── MainMenuSettingsPage.kt
│       │                           │   ├── ManualProjectCreatorDialogPage.kt
│       │                           │   ├── MapsSettingsPage.java
│       │                           │   ├── NotificationDrawer.kt
│       │                           │   ├── OkDialog.java
│       │                           │   ├── OpenSourceLicensesPage.java
│       │                           │   ├── Page.kt
│       │                           │   ├── PreferencePage.java
│       │                           │   ├── ProjectDisplayPage.kt
│       │                           │   ├── ProjectManagementPage.kt
│       │                           │   ├── ProjectSettingsDialogPage.kt
│       │                           │   ├── ProjectSettingsPage.java
│       │                           │   ├── QRCodePage.java
│       │                           │   ├── QrCodeProjectCreatorDialogPage.kt
│       │                           │   ├── ResetApplicationDialog.java
│       │                           │   ├── SaveOrDiscardFormDialog.kt
│       │                           │   ├── SaveOrIgnoreDrawingDialog.kt
│       │                           │   ├── SavepointRecoveryDialogPage.kt
│       │                           │   ├── SelectMinimalDialogPage.kt
│       │                           │   ├── SendFinalizedFormPage.kt
│       │                           │   ├── ServerAuthDialog.java
│       │                           │   ├── ServerSettingsPage.java
│       │                           │   ├── ShortcutsPage.java
│       │                           │   ├── UserAndDeviceIdentitySettingsPage.java
│       │                           │   ├── UserInterfacePage.java
│       │                           │   ├── ViewFormPage.kt
│       │                           │   └── ViewSentFormPage.java
│       │                           └── rules/
│       │                               ├── BlankFormTestRule.kt
│       │                               ├── CollectTestRule.kt
│       │                               ├── FormEntryActivityTestRule.kt
│       │                               ├── IdlingResourceRule.kt
│       │                               ├── NotificationDrawerRule.kt
│       │                               ├── PageComposeRule.kt
│       │                               ├── PrepDeviceForTestsRule.kt
│       │                               ├── RecentAppsRule.kt
│       │                               ├── ResetRotationRule.kt
│       │                               ├── ResetStateRule.kt
│       │                               ├── RetryOnDeviceErrorRule.kt
│       │                               ├── RunnableRule.kt
│       │                               └── TestRuleChain.kt
│       ├── debug/
│       │   ├── AndroidManifest.xml
│       │   └── google-services.json
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── svg_map_helper.js
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               ├── android/
│       │   │               │   ├── activities/
│       │   │               │   │   ├── AboutActivity.kt
│       │   │               │   │   ├── ActivityUtils.java
│       │   │               │   │   ├── AppListActivity.java
│       │   │               │   │   ├── BearingActivity.java
│       │   │               │   │   ├── CrashHandlerActivity.kt
│       │   │               │   │   ├── DeleteFormsActivity.kt
│       │   │               │   │   ├── FirstLaunchActivity.kt
│       │   │               │   │   ├── FormDownloadListActivity.java
│       │   │               │   │   ├── FormEntryViewModelFactory.kt
│       │   │               │   │   ├── FormFillingActivity.java
│       │   │               │   │   ├── FormListActivity.java
│       │   │               │   │   ├── FormMapActivity.kt
│       │   │               │   │   ├── InstanceChooserList.java
│       │   │               │   │   ├── ScannerWithFlashlightActivity.kt
│       │   │               │   │   └── viewmodels/
│       │   │               │   │       └── FormDownloadListViewModel.java
│       │   │               │   ├── adapters/
│       │   │               │   │   ├── AboutListAdapter.kt
│       │   │               │   │   ├── AbstractSelectListAdapter.java
│       │   │               │   │   ├── FormDownloadListAdapter.java
│       │   │               │   │   ├── InstanceListCursorAdapter.java
│       │   │               │   │   ├── InstanceUploaderAdapter.java
│       │   │               │   │   ├── RankingListAdapter.java
│       │   │               │   │   ├── SelectMultipleListAdapter.java
│       │   │               │   │   └── SelectOneListAdapter.java
│       │   │               │   ├── analytics/
│       │   │               │   │   ├── AnalyticsEvents.kt
│       │   │               │   │   └── AnalyticsUtils.kt
│       │   │               │   ├── application/
│       │   │               │   │   ├── Collect.java
│       │   │               │   │   ├── CollectSettingsChangeHandler.kt
│       │   │               │   │   ├── ComposeTheme.kt
│       │   │               │   │   ├── FeatureFlags.kt
│       │   │               │   │   ├── MapboxClassInstanceCreator.kt
│       │   │               │   │   └── initialization/
│       │   │               │   │       ├── AnalyticsInitializer.kt
│       │   │               │   │       ├── ApplicationInitializer.kt
│       │   │               │   │       ├── CachedFormsCleaner.kt
│       │   │               │   │       ├── CrashReportingTree.kt
│       │   │               │   │       ├── ExistingProjectMigrator.kt
│       │   │               │   │       ├── ExistingSettingsMigrator.kt
│       │   │               │   │       ├── GoogleDriveProjectsDeleter.kt
│       │   │               │   │       ├── JavaRosaInitializer.kt
│       │   │               │   │       ├── MapsInitializer.kt
│       │   │               │   │       ├── SavepointsImporter.kt
│       │   │               │   │       ├── ScheduledWorkUpgrade.kt
│       │   │               │   │       ├── UserPropertiesInitializer.kt
│       │   │               │   │       └── upgrade/
│       │   │               │   │           ├── BeforeProjectsInstallDetector.kt
│       │   │               │   │           └── UpgradeInitializer.kt
│       │   │               │   ├── audio/
│       │   │               │   │   ├── AMRAppender.java
│       │   │               │   │   ├── AudioButton.java
│       │   │               │   │   ├── AudioControllerView.java
│       │   │               │   │   ├── AudioFileAppender.java
│       │   │               │   │   ├── AudioRecordingControllerFragment.java
│       │   │               │   │   ├── AudioRecordingErrorDialogFragment.java
│       │   │               │   │   ├── BackgroundAudioHelpDialogFragment.java
│       │   │               │   │   ├── M4AAppender.java
│       │   │               │   │   ├── VolumeBar.java
│       │   │               │   │   └── Waveform.java
│       │   │               │   ├── backgroundwork/
│       │   │               │   │   ├── AutoUpdateTaskSpec.kt
│       │   │               │   │   ├── BackgroundWorkUtils.java
│       │   │               │   │   ├── FormUpdateAndInstanceSubmitScheduler.java
│       │   │               │   │   ├── FormUpdateScheduler.java
│       │   │               │   │   ├── InstanceSubmitScheduler.java
│       │   │               │   │   ├── SendFormsTaskSpec.kt
│       │   │               │   │   ├── SyncFormsTaskSpec.kt
│       │   │               │   │   └── TaskData.kt
│       │   │               │   ├── configure/
│       │   │               │   │   └── qr/
│       │   │               │   │       ├── AppConfigurationGenerator.kt
│       │   │               │   │       ├── CachingQRCodeGenerator.kt
│       │   │               │   │       ├── QRCodeActivityResultDelegate.kt
│       │   │               │   │       ├── QRCodeMenuProvider.kt
│       │   │               │   │       ├── QRCodeScannerFragment.kt
│       │   │               │   │       ├── QRCodeTabsActivity.kt
│       │   │               │   │       ├── QRCodeViewModel.kt
│       │   │               │   │       ├── SettingsBarcodeScannerViewFactory.kt
│       │   │               │   │       └── ShowQRCodeFragment.kt
│       │   │               │   ├── dao/
│       │   │               │   │   ├── CursorLoaderFactory.java
│       │   │               │   │   └── helpers/
│       │   │               │   │       └── InstancesDaoHelper.java
│       │   │               │   ├── database/
│       │   │               │   │   ├── DatabaseConstants.java
│       │   │               │   │   ├── DatabaseObjectMapper.kt
│       │   │               │   │   ├── entities/
│       │   │               │   │   │   └── DatabaseEntitiesRepository.kt
│       │   │               │   │   ├── forms/
│       │   │               │   │   │   ├── DatabaseFormColumns.kt
│       │   │               │   │   │   ├── DatabaseFormsRepository.java
│       │   │               │   │   │   └── FormDatabaseMigrator.java
│       │   │               │   │   ├── instances/
│       │   │               │   │   │   ├── DatabaseInstanceColumns.kt
│       │   │               │   │   │   ├── DatabaseInstancesRepository.java
│       │   │               │   │   │   └── InstanceDatabaseMigrator.java
│       │   │               │   │   ├── itemsets/
│       │   │               │   │   │   └── DatabaseFastExternalItemsetsRepository.kt
│       │   │               │   │   └── savepoints/
│       │   │               │   │       ├── DatabaseSavepointsColumns.kt
│       │   │               │   │       ├── DatabaseSavepointsRepository.kt
│       │   │               │   │       └── SavepointsDatabaseMigrator.kt
│       │   │               │   ├── dynamicpreload/
│       │   │               │   │   ├── DynamicPreloadXFormParserFactory.kt
│       │   │               │   │   ├── ExternalAnswerResolver.java
│       │   │               │   │   ├── ExternalAppsUtils.java
│       │   │               │   │   ├── ExternalDataHandler.java
│       │   │               │   │   ├── ExternalDataManager.java
│       │   │               │   │   ├── ExternalDataManagerImpl.java
│       │   │               │   │   ├── ExternalDataReader.java
│       │   │               │   │   ├── ExternalDataReaderImpl.java
│       │   │               │   │   ├── ExternalDataUseCases.kt
│       │   │               │   │   ├── ExternalDataUtil.java
│       │   │               │   │   ├── ExternalSQLiteOpenHelper.java
│       │   │               │   │   ├── ExternalSelectChoice.java
│       │   │               │   │   └── handler/
│       │   │               │   │       ├── ExternalDataHandlerBase.java
│       │   │               │   │       ├── ExternalDataHandlerPull.java
│       │   │               │   │       ├── ExternalDataHandlerSearch.java
│       │   │               │   │       └── ExternalDataSearchType.java
│       │   │               │   ├── entities/
│       │   │               │   │   └── EntitiesRepositoryProvider.kt
│       │   │               │   ├── exception/
│       │   │               │   │   ├── EncryptionException.java
│       │   │               │   │   ├── ExternalDataException.java
│       │   │               │   │   ├── ExternalParamsException.java
│       │   │               │   │   └── JavaRosaException.java
│       │   │               │   ├── external/
│       │   │               │   │   ├── AndroidShortcutsActivity.kt
│       │   │               │   │   ├── FormUriActivity.kt
│       │   │               │   │   ├── FormsContract.java
│       │   │               │   │   ├── FormsProvider.java
│       │   │               │   │   ├── InstanceProvider.java
│       │   │               │   │   └── InstancesContract.java
│       │   │               │   ├── fastexternalitemset/
│       │   │               │   │   ├── ItemsetDao.java
│       │   │               │   │   ├── ItemsetDbAdapter.java
│       │   │               │   │   └── XPathParseTool.java
│       │   │               │   ├── formentry/
│       │   │               │   │   ├── BackgroundAudioPermissionDialogFragment.java
│       │   │               │   │   ├── BackgroundAudioViewModel.java
│       │   │               │   │   ├── CurrentFormIndex.kt
│       │   │               │   │   ├── FormAnimation.kt
│       │   │               │   │   ├── FormDefCache.kt
│       │   │               │   │   ├── FormEnd.kt
│       │   │               │   │   ├── FormEndView.kt
│       │   │               │   │   ├── FormEndViewModel.kt
│       │   │               │   │   ├── FormEntryMenuProvider.kt
│       │   │               │   │   ├── FormEntryUseCases.kt
│       │   │               │   │   ├── FormEntryViewModel.java
│       │   │               │   │   ├── FormError.kt
│       │   │               │   │   ├── FormIndexAnimationHandler.kt
│       │   │               │   │   ├── FormLoadingDialogFragment.java
│       │   │               │   │   ├── FormOpeningMode.kt
│       │   │               │   │   ├── FormSessionRepository.kt
│       │   │               │   │   ├── ODKView.java
│       │   │               │   │   ├── PrinterWidgetViewModel.kt
│       │   │               │   │   ├── QuitFormDialog.kt
│       │   │               │   │   ├── RecordingHandler.java
│       │   │               │   │   ├── RecordingWarningDialogFragment.java
│       │   │               │   │   ├── RefreshFormListDialogFragment.java
│       │   │               │   │   ├── SwipeHandler.kt
│       │   │               │   │   ├── audit/
│       │   │               │   │   │   ├── AsyncTaskAuditEventWriter.java
│       │   │               │   │   │   ├── AuditConfig.java
│       │   │               │   │   │   ├── AuditEvent.java
│       │   │               │   │   │   ├── AuditEventCSVLine.java
│       │   │               │   │   │   ├── AuditEventLogger.java
│       │   │               │   │   │   ├── AuditEventSaveTask.java
│       │   │               │   │   │   ├── AuditUtils.kt
│       │   │               │   │   │   ├── ChangesReasonPromptDialogFragment.java
│       │   │               │   │   │   ├── IdentifyUserPromptDialogFragment.java
│       │   │               │   │   │   └── IdentityPromptViewModel.java
│       │   │               │   │   ├── backgroundlocation/
│       │   │               │   │   │   ├── BackgroundLocationHelper.java
│       │   │               │   │   │   ├── BackgroundLocationManager.java
│       │   │               │   │   │   └── BackgroundLocationViewModel.java
│       │   │               │   │   ├── media/
│       │   │               │   │   │   ├── FormMediaUtils.java
│       │   │               │   │   │   └── PromptAutoplayer.java
│       │   │               │   │   ├── questions/
│       │   │               │   │   │   ├── AnswersProvider.java
│       │   │               │   │   │   ├── AudioVideoImageTextLabel.java
│       │   │               │   │   │   ├── NoButtonsItem.java
│       │   │               │   │   │   ├── QuestionDetails.java
│       │   │               │   │   │   └── SelectChoiceUtils.kt
│       │   │               │   │   ├── repeats/
│       │   │               │   │   │   ├── AddRepeatDialog.kt
│       │   │               │   │   │   └── DeleteRepeatDialogFragment.java
│       │   │               │   │   └── saving/
│       │   │               │   │       ├── DiskFormSaver.java
│       │   │               │   │       ├── FormSaveViewModel.java
│       │   │               │   │       ├── FormSaver.java
│       │   │               │   │       ├── SaveAnswerFileErrorDialogFragment.java
│       │   │               │   │       ├── SaveAnswerFileProgressDialogFragment.java
│       │   │               │   │       └── SaveFormProgressDialogFragment.java
│       │   │               │   ├── formhierarchy/
│       │   │               │   │   ├── FormHierarchyFragment.java
│       │   │               │   │   ├── FormHierarchyFragmentHostActivity.kt
│       │   │               │   │   ├── FormHierarchyViewModel.kt
│       │   │               │   │   ├── HierarchyItem.kt
│       │   │               │   │   ├── HierarchyListAdapter.kt
│       │   │               │   │   ├── HierarchyListItemView.kt
│       │   │               │   │   └── QuestionAnswerProcessor.kt
│       │   │               │   ├── formlists/
│       │   │               │   │   ├── blankformlist/
│       │   │               │   │   │   ├── BlankFormListActivity.kt
│       │   │               │   │   │   ├── BlankFormListAdapter.kt
│       │   │               │   │   │   ├── BlankFormListItem.kt
│       │   │               │   │   │   ├── BlankFormListItemView.kt
│       │   │               │   │   │   ├── BlankFormListMenuProvider.kt
│       │   │               │   │   │   ├── BlankFormListViewModel.kt
│       │   │               │   │   │   └── DeleteBlankFormFragment.kt
│       │   │               │   │   ├── savedformlist/
│       │   │               │   │   │   ├── DeleteSavedFormFragment.kt
│       │   │               │   │   │   ├── SavedFormListItemView.kt
│       │   │               │   │   │   ├── SavedFormListListMenuProvider.kt
│       │   │               │   │   │   ├── SavedFormListViewModel.kt
│       │   │               │   │   │   └── SelectableSavedFormListItemViewHolder.kt
│       │   │               │   │   └── sorting/
│       │   │               │   │       ├── FormListSortingAdapter.kt
│       │   │               │   │       ├── FormListSortingBottomSheetDialog.kt
│       │   │               │   │       └── FormListSortingOption.kt
│       │   │               │   ├── formmanagement/
│       │   │               │   │   ├── CollectFormEntryControllerFactory.kt
│       │   │               │   │   ├── FormFillingIntentFactory.kt
│       │   │               │   │   ├── FormSourceExceptionMapper.kt
│       │   │               │   │   ├── FormsDataService.kt
│       │   │               │   │   ├── LocalFormUseCases.kt
│       │   │               │   │   ├── OpenRosaClientProvider.kt
│       │   │               │   │   ├── ServerFormDetails.kt
│       │   │               │   │   ├── ServerFormUseCases.kt
│       │   │               │   │   ├── download/
│       │   │               │   │   │   ├── FormDownloadException.kt
│       │   │               │   │   │   ├── FormDownloadExceptionMapper.kt
│       │   │               │   │   │   ├── FormDownloader.kt
│       │   │               │   │   │   └── ServerFormDownloader.java
│       │   │               │   │   ├── drafts/
│       │   │               │   │   │   ├── BulkFinalizationViewModel.kt
│       │   │               │   │   │   └── DraftsMenuProvider.kt
│       │   │               │   │   ├── finalization/
│       │   │               │   │   │   └── EditedFormFinalizationProcessor.kt
│       │   │               │   │   ├── formmap/
│       │   │               │   │   │   └── FormMapViewModel.kt
│       │   │               │   │   ├── matchexactly/
│       │   │               │   │   │   └── ServerFormsSynchronizer.java
│       │   │               │   │   └── metadata/
│       │   │               │   │       ├── FormMetadata.kt
│       │   │               │   │       └── FormMetadataParser.kt
│       │   │               │   ├── fragments/
│       │   │               │   │   ├── BarCodeScannerFragment.kt
│       │   │               │   │   ├── BarcodeWidgetScannerFragment.kt
│       │   │               │   │   ├── MediaLoadingFragment.java
│       │   │               │   │   ├── dialogs/
│       │   │               │   │   │   ├── FormsDownloadResultDialog.kt
│       │   │               │   │   │   ├── LocationProvidersDisabledDialog.java
│       │   │               │   │   │   ├── MovingBackwardsDialog.java
│       │   │               │   │   │   ├── RangePickerDialogFragment.kt
│       │   │               │   │   │   ├── RankingWidgetDialog.java
│       │   │               │   │   │   ├── ResetSettingsResultDialog.java
│       │   │               │   │   │   ├── SelectMinimalDialog.java
│       │   │               │   │   │   ├── SelectMultiMinimalDialog.java
│       │   │               │   │   │   ├── SelectOneMinimalDialog.java
│       │   │               │   │   │   └── SimpleDialog.java
│       │   │               │   │   └── viewmodels/
│       │   │               │   │       ├── RankingViewModel.java
│       │   │               │   │       └── SelectMinimalViewModel.java
│       │   │               │   ├── geo/
│       │   │               │   │   ├── MapConfiguratorProvider.java
│       │   │               │   │   └── MapFragmentFactoryImpl.kt
│       │   │               │   ├── injection/
│       │   │               │   │   ├── DaggerUtils.kt
│       │   │               │   │   └── config/
│       │   │               │   │       ├── AppDependencyComponent.kt
│       │   │               │   │       ├── AppDependencyModule.java
│       │   │               │   │       ├── CollectDrawDependencyModule.kt
│       │   │               │   │       ├── CollectEntitiesDependencyModule.kt
│       │   │               │   │       ├── CollectGeoDependencyModule.kt
│       │   │               │   │       ├── CollectGoogleMapsDependencyModule.kt
│       │   │               │   │       ├── CollectOsmDroidDependencyModule.kt
│       │   │               │   │       ├── CollectProjectsDependencyModule.kt
│       │   │               │   │       ├── CollectSelfieCameraDependencyModule.kt
│       │   │               │   │       └── ProjectDependencyModuleFactory.kt
│       │   │               │   ├── instancemanagement/
│       │   │               │   │   ├── FinalizeAllSnackbarPresenter.kt
│       │   │               │   │   ├── InstanceDeleter.kt
│       │   │               │   │   ├── InstanceDiskSynchronizer.java
│       │   │               │   │   ├── InstanceExt.kt
│       │   │               │   │   ├── InstanceListItemView.kt
│       │   │               │   │   ├── InstanceSubmitter.kt
│       │   │               │   │   ├── InstancesDataService.kt
│       │   │               │   │   ├── LocalInstancesUseCases.kt
│       │   │               │   │   ├── autosend/
│       │   │               │   │   │   ├── AutoSendSettingsProvider.kt
│       │   │               │   │   │   ├── FormExt.kt
│       │   │               │   │   │   └── InstanceAutoSendFetcher.kt
│       │   │               │   │   └── send/
│       │   │               │   │       ├── InstanceUploaderActivity.java
│       │   │               │   │       ├── InstanceUploaderListActivity.java
│       │   │               │   │       ├── ReadyToSendBanner.kt
│       │   │               │   │       └── ReadyToSendViewModel.kt
│       │   │               │   ├── itemsets/
│       │   │               │   │   └── FastExternalItemsetsRepository.kt
│       │   │               │   ├── javarosawrapper/
│       │   │               │   │   ├── FormController.kt
│       │   │               │   │   ├── FormControllerExt.kt
│       │   │               │   │   ├── FormDesignException.kt
│       │   │               │   │   ├── FormIndexUtils.java
│       │   │               │   │   ├── InstanceMetadata.java
│       │   │               │   │   ├── JavaRosaFormController.java
│       │   │               │   │   └── ValidationResult.kt
│       │   │               │   ├── listeners/
│       │   │               │   │   ├── AdvanceToNextListener.java
│       │   │               │   │   ├── DeleteInstancesListener.java
│       │   │               │   │   ├── DownloadFormsTaskListener.java
│       │   │               │   │   ├── FormListDownloaderListener.java
│       │   │               │   │   ├── FormLoaderListener.java
│       │   │               │   │   ├── InstanceUploaderListener.java
│       │   │               │   │   ├── Result.java
│       │   │               │   │   ├── SelectItemClickListener.java
│       │   │               │   │   ├── ThousandsSeparatorTextWatcher.java
│       │   │               │   │   └── WidgetValueChangedListener.java
│       │   │               │   ├── location/
│       │   │               │   │   └── client/
│       │   │               │   │       └── MaxAccuracyWithinTimeoutLocationClientWrapper.java
│       │   │               │   ├── logic/
│       │   │               │   │   ├── FileReference.java
│       │   │               │   │   ├── FileReferenceFactory.java
│       │   │               │   │   ├── ImmutableDisplayableQuestion.java
│       │   │               │   │   └── actions/
│       │   │               │   │       └── setgeopoint/
│       │   │               │   │           ├── CollectSetGeopointAction.java
│       │   │               │   │           └── CollectSetGeopointActionHandler.java
│       │   │               │   ├── mainmenu/
│       │   │               │   │   ├── CurrentProjectViewModel.kt
│       │   │               │   │   ├── MainMenuActivity.kt
│       │   │               │   │   ├── MainMenuButton.kt
│       │   │               │   │   ├── MainMenuFragment.kt
│       │   │               │   │   ├── MainMenuViewModel.kt
│       │   │               │   │   ├── MainMenuViewModelFactory.kt
│       │   │               │   │   ├── PermissionsDialogFragment.kt
│       │   │               │   │   ├── RequestPermissionsViewModel.kt
│       │   │               │   │   └── StartNewFormButton.kt
│       │   │               │   ├── notifications/
│       │   │               │   │   ├── NotificationManagerNotifier.kt
│       │   │               │   │   ├── NotificationUtils.kt
│       │   │               │   │   ├── Notifier.kt
│       │   │               │   │   └── builders/
│       │   │               │   │       ├── FormUpdatesAvailableNotificationBuilder.kt
│       │   │               │   │       ├── FormUpdatesDownloadedNotificationBuilder.kt
│       │   │               │   │       ├── FormsSubmissionNotificationBuilder.kt
│       │   │               │   │       ├── FormsSyncFailedNotificationBuilder.kt
│       │   │               │   │       └── FormsSyncStoppedNotificationBuilder.kt
│       │   │               │   ├── preferences/
│       │   │               │   │   ├── Defaults.kt
│       │   │               │   │   ├── PreferenceVisibilityHandler.kt
│       │   │               │   │   ├── ProjectPreferencesViewModel.kt
│       │   │               │   │   ├── ServerPreferencesAdder.java
│       │   │               │   │   ├── SettingsExt.kt
│       │   │               │   │   ├── dialogs/
│       │   │               │   │   │   ├── AdminPasswordDialogFragment.kt
│       │   │               │   │   │   ├── ChangeAdminPasswordDialog.kt
│       │   │               │   │   │   ├── DeleteProjectDialog.kt
│       │   │               │   │   │   ├── ResetDialogPreference.java
│       │   │               │   │   │   ├── ResetDialogPreferenceFragmentCompat.java
│       │   │               │   │   │   ├── ResetProgressDialog.kt
│       │   │               │   │   │   └── ServerAuthDialogFragment.java
│       │   │               │   │   ├── filters/
│       │   │               │   │   │   └── ControlCharacterFilter.java
│       │   │               │   │   ├── screens/
│       │   │               │   │   │   ├── AccessControlPreferencesFragment.kt
│       │   │               │   │   │   ├── BaseAdminPreferencesFragment.java
│       │   │               │   │   │   ├── BasePreferencesFragment.kt
│       │   │               │   │   │   ├── BaseProjectPreferencesFragment.java
│       │   │               │   │   │   ├── DevToolsPreferencesFragment.kt
│       │   │               │   │   │   ├── ExperimentalPreferencesFragment.java
│       │   │               │   │   │   ├── FormEntryAccessPreferencesFragment.kt
│       │   │               │   │   │   ├── FormManagementPreferencesFragment.java
│       │   │               │   │   │   ├── FormMetadataPreferencesFragment.java
│       │   │               │   │   │   ├── IdentityPreferencesFragment.kt
│       │   │               │   │   │   ├── MainMenuAccessPreferencesFragment.kt
│       │   │               │   │   │   ├── MapsPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectDisplayPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectManagementPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectPreferencesActivity.kt
│       │   │               │   │   │   ├── ProjectPreferencesFragment.kt
│       │   │               │   │   │   ├── ServerPreferencesFragment.java
│       │   │               │   │   │   ├── UserInterfacePreferencesFragment.java
│       │   │               │   │   │   └── UserSettingsAccessPreferencesFragment.java
│       │   │               │   │   ├── source/
│       │   │               │   │   │   ├── SettingsStore.kt
│       │   │               │   │   │   ├── SharedPreferencesSettings.kt
│       │   │               │   │   │   └── SharedPreferencesSettingsProvider.kt
│       │   │               │   │   └── utilities/
│       │   │               │   │       └── PreferencesUtils.java
│       │   │               │   ├── projects/
│       │   │               │   │   ├── DuplicateProjectConfirmationDialog.kt
│       │   │               │   │   ├── FileDebugLogger.kt
│       │   │               │   │   ├── ManualProjectCreatorDialog.kt
│       │   │               │   │   ├── ProjectCreatorImpl.kt
│       │   │               │   │   ├── ProjectDeleter.kt
│       │   │               │   │   ├── ProjectDependencyModule.kt
│       │   │               │   │   ├── ProjectIconView.kt
│       │   │               │   │   ├── ProjectListItemView.kt
│       │   │               │   │   ├── ProjectResetter.kt
│       │   │               │   │   ├── ProjectSettingsDialog.kt
│       │   │               │   │   ├── ProjectsDataService.kt
│       │   │               │   │   ├── QrCodeProjectCreatorDialog.kt
│       │   │               │   │   └── SettingsConnectionMatcherImpl.kt
│       │   │               │   ├── savepoints/
│       │   │               │   │   ├── SavepointTask.kt
│       │   │               │   │   └── SavepointUseCases.kt
│       │   │               │   ├── state/
│       │   │               │   │   └── DataKeys.kt
│       │   │               │   ├── storage/
│       │   │               │   │   ├── StoragePathProvider.kt
│       │   │               │   │   ├── StoragePaths.kt
│       │   │               │   │   └── StorageSubdirectory.java
│       │   │               │   ├── tasks/
│       │   │               │   │   ├── DownloadFormListTask.java
│       │   │               │   │   ├── DownloadFormsTask.java
│       │   │               │   │   ├── FormLoaderTask.java
│       │   │               │   │   ├── InstanceUploaderTask.java
│       │   │               │   │   ├── MediaLoadingTask.java
│       │   │               │   │   ├── ProgressNotifier.java
│       │   │               │   │   ├── SaveFormIndexTask.java
│       │   │               │   │   ├── SaveFormToDisk.java
│       │   │               │   │   └── SaveToDiskResult.java
│       │   │               │   ├── upload/
│       │   │               │   │   ├── FormUploadException.kt
│       │   │               │   │   ├── InstanceServerUploader.java
│       │   │               │   │   └── InstanceUploader.java
│       │   │               │   ├── utilities/
│       │   │               │   │   ├── ActionRegister.kt
│       │   │               │   │   ├── AdminPasswordProvider.java
│       │   │               │   │   ├── AndroidUserAgent.java
│       │   │               │   │   ├── AnimationUtils.java
│       │   │               │   │   ├── Appearances.kt
│       │   │               │   │   ├── ApplicationConstants.java
│       │   │               │   │   ├── ArrayUtils.java
│       │   │               │   │   ├── AuthDialogUtility.java
│       │   │               │   │   ├── CSVUtils.java
│       │   │               │   │   ├── ChangeLockProvider.kt
│       │   │               │   │   ├── CollectStrictMode.kt
│       │   │               │   │   ├── ContentUriHelper.kt
│       │   │               │   │   ├── ContentUriProvider.java
│       │   │               │   │   ├── ControllableLifecyleOwner.kt
│       │   │               │   │   ├── DialogUtils.java
│       │   │               │   │   ├── EncryptionUtils.java
│       │   │               │   │   ├── ExternalAppIntentProvider.java
│       │   │               │   │   ├── ExternalizableFormDefCache.java
│       │   │               │   │   ├── FileProvider.java
│       │   │               │   │   ├── FileUtils.java
│       │   │               │   │   ├── FormEntryPromptUtils.java
│       │   │               │   │   ├── FormNameUtils.java
│       │   │               │   │   ├── FormUtils.java
│       │   │               │   │   ├── FormsDownloadResultInterpreter.kt
│       │   │               │   │   ├── FormsRepositoryProvider.kt
│       │   │               │   │   ├── FormsUploadResultInterpreter.kt
│       │   │               │   │   ├── HtmlUtils.java
│       │   │               │   │   ├── ImageCompressionController.kt
│       │   │               │   │   ├── InstanceAutoDeleteChecker.kt
│       │   │               │   │   ├── InstanceUploaderUtils.java
│       │   │               │   │   ├── InstancesRepositoryProvider.kt
│       │   │               │   │   ├── LocaleHelper.kt
│       │   │               │   │   ├── MediaUtils.kt
│       │   │               │   │   ├── MyanmarDateUtils.java
│       │   │               │   │   ├── QuestionMediaManager.java
│       │   │               │   │   ├── RankingItemTouchHelperCallback.java
│       │   │               │   │   ├── ReplaceCallback.java
│       │   │               │   │   ├── ResponseMessageParser.java
│       │   │               │   │   ├── SavepointsRepositoryProvider.kt
│       │   │               │   │   ├── SelectOneWidgetUtils.java
│       │   │               │   │   ├── SoftKeyboardController.kt
│       │   │               │   │   ├── ThemeUtils.java
│       │   │               │   │   ├── UnderlyingValuesConcat.java
│       │   │               │   │   ├── ViewUtils.kt
│       │   │               │   │   ├── WebCredentialsUtils.java
│       │   │               │   │   └── ZipUtils.java
│       │   │               │   ├── version/
│       │   │               │   │   ├── VersionDescriptionProvider.java
│       │   │               │   │   └── VersionInformation.java
│       │   │               │   ├── views/
│       │   │               │   │   ├── ChoicesRecyclerView.java
│       │   │               │   │   ├── CustomNumberPicker.kt
│       │   │               │   │   ├── CustomWebView.java
│       │   │               │   │   ├── DayNightProgressDialog.java
│       │   │               │   │   ├── DecoratedBarcodeView.kt
│       │   │               │   │   ├── SlidingTabLayout.java
│       │   │               │   │   ├── SlidingTabStrip.java
│       │   │               │   │   ├── TrackingTouchSlider.kt
│       │   │               │   │   ├── TransparentProgressScreen.kt
│       │   │               │   │   ├── TwoItemMultipleChoiceView.java
│       │   │               │   │   └── WidgetAnswerText.kt
│       │   │               │   └── widgets/
│       │   │               │       ├── AnnotateWidget.java
│       │   │               │       ├── AudioWidget.java
│       │   │               │       ├── BaseImageWidget.java
│       │   │               │       ├── BearingWidget.java
│       │   │               │       ├── CounterWidget.kt
│       │   │               │       ├── DecimalWidget.java
│       │   │               │       ├── DrawWidget.java
│       │   │               │       ├── ExAudioWidget.java
│       │   │               │       ├── ExDecimalWidget.java
│       │   │               │       ├── ExImageWidget.java
│       │   │               │       ├── ExIntegerWidget.java
│       │   │               │       ├── ExStringWidget.java
│       │   │               │       ├── GeoPointMapWidget.java
│       │   │               │       ├── GeoPointWidget.java
│       │   │               │       ├── GeoShapeWidget.java
│       │   │               │       ├── GeoTraceWidget.java
│       │   │               │       ├── ImageWidget.java
│       │   │               │       ├── IntegerWidget.java
│       │   │               │       ├── MediaWidgetAnswerViewModel.kt
│       │   │               │       ├── OSMWidget.java
│       │   │               │       ├── PrinterWidget.kt
│       │   │               │       ├── QuestionWidget.java
│       │   │               │       ├── RatingWidget.java
│       │   │               │       ├── SignatureWidget.java
│       │   │               │       ├── StringNumberWidget.java
│       │   │               │       ├── StringWidget.java
│       │   │               │       ├── TextWidgetAnswer.kt
│       │   │               │       ├── TimedGridWidget.kt
│       │   │               │       ├── TriggerWidget.java
│       │   │               │       ├── UrlWidget.java
│       │   │               │       ├── WidgetAnswer.kt
│       │   │               │       ├── WidgetAnswerView.kt
│       │   │               │       ├── WidgetFactory.java
│       │   │               │       ├── WidgetIconButton.kt
│       │   │               │       ├── arbitraryfile/
│       │   │               │       │   ├── ArbitraryFileWidget.kt
│       │   │               │       │   ├── ArbitraryFileWidgetContent.kt
│       │   │               │       │   ├── ArbitraryFileWidgetDelegate.kt
│       │   │               │       │   ├── ExArbitraryFileWidget.kt
│       │   │               │       │   └── ExArbitraryFileWidgetContent.kt
│       │   │               │       ├── barcode/
│       │   │               │       │   ├── BarcodeWidget.kt
│       │   │               │       │   └── BarcodeWidgetContent.kt
│       │   │               │       ├── datetime/
│       │   │               │       │   ├── DatePickerDetails.java
│       │   │               │       │   ├── DateTimeUtils.java
│       │   │               │       │   ├── DateTimeWidget.java
│       │   │               │       │   ├── DateWidget.java
│       │   │               │       │   ├── TimeWidget.java
│       │   │               │       │   └── pickers/
│       │   │               │       │       ├── BikramSambatDatePickerDialog.java
│       │   │               │       │       ├── BuddhistDatePickerDialog.kt
│       │   │               │       │       ├── CopticDatePickerDialog.java
│       │   │               │       │       ├── CustomDatePickerDialog.java
│       │   │               │       │       ├── CustomTimePickerDialog.java
│       │   │               │       │       ├── EthiopianDatePickerDialog.java
│       │   │               │       │       ├── FixedDatePickerDialog.java
│       │   │               │       │       ├── IslamicDatePickerDialog.java
│       │   │               │       │       ├── MyanmarDatePickerDialog.java
│       │   │               │       │       └── PersianDatePickerDialog.java
│       │   │               │       ├── interfaces/
│       │   │               │       │   ├── FileWidget.java
│       │   │               │       │   ├── GeoDataRequester.kt
│       │   │               │       │   ├── MultiChoiceWidget.java
│       │   │               │       │   ├── Printer.kt
│       │   │               │       │   ├── SelectChoiceLoader.kt
│       │   │               │       │   ├── Widget.java
│       │   │               │       │   └── WidgetDataReceiver.kt
│       │   │               │       ├── items/
│       │   │               │       │   ├── BaseSelectListWidget.java
│       │   │               │       │   ├── ItemsWidgetUtils.kt
│       │   │               │       │   ├── LabelWidget.java
│       │   │               │       │   ├── LikertWidget.java
│       │   │               │       │   ├── ListMultiWidget.java
│       │   │               │       │   ├── ListWidget.java
│       │   │               │       │   ├── RankingWidget.java
│       │   │               │       │   ├── SelectImageMapWidget.java
│       │   │               │       │   ├── SelectMinimalWidget.java
│       │   │               │       │   ├── SelectMultiImageMapWidget.java
│       │   │               │       │   ├── SelectMultiMinimalWidget.java
│       │   │               │       │   ├── SelectMultiWidget.java
│       │   │               │       │   ├── SelectOneFromMapDialogFragment.kt
│       │   │               │       │   ├── SelectOneFromMapWidget.kt
│       │   │               │       │   ├── SelectOneImageMapWidget.java
│       │   │               │       │   ├── SelectOneMinimalWidget.java
│       │   │               │       │   └── SelectOneWidget.java
│       │   │               │       ├── range/
│       │   │               │       │   ├── RangeDecimalWidget.java
│       │   │               │       │   ├── RangeIntegerWidget.java
│       │   │               │       │   ├── RangePickerWidget.java
│       │   │               │       │   └── RangePickerWidgetUtils.kt
│       │   │               │       ├── utilities/
│       │   │               │       │   ├── ActivityGeoDataRequester.kt
│       │   │               │       │   ├── AdditionalAttributes.kt
│       │   │               │       │   ├── AudioFileRequester.java
│       │   │               │       │   ├── AudioRecorderRecordingStatusHandler.java
│       │   │               │       │   ├── BindAttributes.kt
│       │   │               │       │   ├── DateTimeWidgetUtils.java
│       │   │               │       │   ├── ExternalAppRecordingRequester.kt
│       │   │               │       │   ├── FileRequester.kt
│       │   │               │       │   ├── FormControllerWaitingForDataRegistry.java
│       │   │               │       │   ├── GeoPolyDialogFragment.kt
│       │   │               │       │   ├── GeoWidgetUtils.kt
│       │   │               │       │   ├── GetContentAudioFileRequester.kt
│       │   │               │       │   ├── ImageCaptureIntentCreator.kt
│       │   │               │       │   ├── InternalRecordingRequester.java
│       │   │               │       │   ├── QuestionFontSizeUtils.kt
│       │   │               │       │   ├── RangeWidgetUtils.java
│       │   │               │       │   ├── RecordingRequester.java
│       │   │               │       │   ├── RecordingRequesterProvider.java
│       │   │               │       │   ├── RecordingStatusHandler.java
│       │   │               │       │   ├── SearchQueryViewModel.java
│       │   │               │       │   ├── StringRequester.kt
│       │   │               │       │   ├── StringWidgetUtils.java
│       │   │               │       │   ├── ViewModelAudioPlayer.kt
│       │   │               │       │   ├── WaitingForDataRegistry.java
│       │   │               │       │   └── WidgetAnswerDialogFragment.kt
│       │   │               │       ├── video/
│       │   │               │       │   ├── ExVideoWidget.kt
│       │   │               │       │   ├── ExVideoWidgetContent.kt
│       │   │               │       │   ├── VideoWidget.kt
│       │   │               │       │   ├── VideoWidgetAnswer.kt
│       │   │               │       │   └── VideoWidgetContent.kt
│       │   │               │       ├── viewmodels/
│       │   │               │       │   ├── DateTimeViewModel.java
│       │   │               │       │   └── QuestionViewModel.kt
│       │   │               │       └── warnings/
│       │   │               │           └── SpacesInUnderlyingValuesWarning.java
│       │   │               └── utilities/
│       │   │                   ├── Result.java
│       │   │                   └── UserAgentProvider.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── fade_in.xml
│       │       │   ├── fade_out.xml
│       │       │   ├── push_left_in.xml
│       │       │   ├── push_left_out.xml
│       │       │   ├── push_right_in.xml
│       │       │   └── push_right_out.xml
│       │       ├── drawable/
│       │       │   ├── counter_minus_button_background.xml
│       │       │   ├── counter_plus_button_background.xml
│       │       │   ├── counter_value_background.xml
│       │       │   ├── ic_access_time.xml
│       │       │   ├── ic_add_circle_24.xml
│       │       │   ├── ic_arrow_back.xml
│       │       │   ├── ic_arrow_drop_down.xml
│       │       │   ├── ic_arrow_up.xml
│       │       │   ├── ic_baseline_delete_72.xml
│       │       │   ├── ic_baseline_delete_outline_24.xml
│       │       │   ├── ic_baseline_download_72.xml
│       │       │   ├── ic_baseline_edit_72.xml
│       │       │   ├── ic_baseline_error_24.xml
│       │       │   ├── ic_baseline_help_outline_24.xml
│       │       │   ├── ic_baseline_inbox_72.xml
│       │       │   ├── ic_baseline_note_72.xml
│       │       │   ├── ic_baseline_notifications_24.xml
│       │       │   ├── ic_baseline_qr_code_scanner_24.xml
│       │       │   ├── ic_baseline_refresh_24.xml
│       │       │   ├── ic_baseline_refresh_error_24.xml
│       │       │   ├── ic_baseline_search_24.xml
│       │       │   ├── ic_baseline_send_72.xml
│       │       │   ├── ic_baseline_sort_24.xml
│       │       │   ├── ic_cancel.xml
│       │       │   ├── ic_chat_bubble_24dp.xml
│       │       │   ├── ic_check_circle_24.xml
│       │       │   ├── ic_download_24.xml
│       │       │   ├── ic_edit_24.xml
│       │       │   ├── ic_folder_open.xml
│       │       │   ├── ic_form_state_blank.xml
│       │       │   ├── ic_form_state_finalized.xml
│       │       │   ├── ic_form_state_saved.xml
│       │       │   ├── ic_form_state_submission_failed.xml
│       │       │   ├── ic_form_state_submitted.xml
│       │       │   ├── ic_information_outline.xml
│       │       │   ├── ic_map.xml
│       │       │   ├── ic_menu_share.xml
│       │       │   ├── ic_navigate_back.xml
│       │       │   ├── ic_navigate_forward.xml
│       │       │   ├── ic_ondemand_video_black_24dp.xml
│       │       │   ├── ic_outline_assignment_accent_24.xml
│       │       │   ├── ic_outline_cloud_accent_24.xml
│       │       │   ├── ic_outline_color_lens_accent_24.xml
│       │       │   ├── ic_outline_delete_accent_24.xml
│       │       │   ├── ic_outline_edit_24.xml
│       │       │   ├── ic_outline_face_accent_24.xml
│       │       │   ├── ic_outline_forum_24.xml
│       │       │   ├── ic_outline_info_small.xml
│       │       │   ├── ic_outline_lock_24.xml
│       │       │   ├── ic_outline_lock_accent_24.xml
│       │       │   ├── ic_outline_lock_open_24.xml
│       │       │   ├── ic_outline_map_accent_24.xml
│       │       │   ├── ic_outline_menu_accent_24.xml
│       │       │   ├── ic_outline_phonelink_setup_accent_24.xml
│       │       │   ├── ic_outline_qr_code_scanner_accent_24.xml
│       │       │   ├── ic_outline_rate_review_24.xml
│       │       │   ├── ic_outline_refresh_accent_24.xml
│       │       │   ├── ic_outline_settings_accent_24.xml
│       │       │   ├── ic_outline_settings_applications_accent_24.xml
│       │       │   ├── ic_outline_share_24.xml
│       │       │   ├── ic_outline_stars_24.xml
│       │       │   ├── ic_outline_vpn_key_accent_24.xml
│       │       │   ├── ic_outline_warning_accent_24.xml
│       │       │   ├── ic_outline_website_24.xml
│       │       │   ├── ic_pause_24dp.xml
│       │       │   ├── ic_person_24dp.xml
│       │       │   ├── ic_play_arrow_24dp.xml
│       │       │   ├── ic_repeat.xml
│       │       │   ├── ic_room_form_state_complete_24dp.xml
│       │       │   ├── ic_room_form_state_complete_48dp.xml
│       │       │   ├── ic_room_form_state_incomplete_24dp.xml
│       │       │   ├── ic_room_form_state_incomplete_48dp.xml
│       │       │   ├── ic_room_form_state_submission_failed_24dp.xml
│       │       │   ├── ic_room_form_state_submission_failed_48dp.xml
│       │       │   ├── ic_room_form_state_submitted_24dp.xml
│       │       │   ├── ic_room_form_state_submitted_48dp.xml
│       │       │   ├── ic_save_menu_24.xml
│       │       │   ├── ic_send_24.xml
│       │       │   ├── ic_sort.xml
│       │       │   ├── ic_sort_by_alpha.xml
│       │       │   ├── ic_sort_by_last_saved.xml
│       │       │   ├── ic_splash_screen_icon.xml
│       │       │   ├── ic_stop_black_24dp.xml
│       │       │   ├── ic_visibility.xml
│       │       │   ├── ic_volume_up_black_24dp.xml
│       │       │   ├── inset_divider_64dp.xml
│       │       │   ├── main_menu_button_background.xml
│       │       │   ├── odk_logo.xml
│       │       │   ├── pill_filled.xml
│       │       │   ├── pill_unfilled.xml
│       │       │   ├── project_icon_background.xml
│       │       │   ├── question_with_error_border.xml
│       │       │   ├── select_item_border.xml
│       │       │   └── start_new_form_button_background.xml
│       │       ├── drawable-ldrtl/
│       │       │   ├── counter_minus_button_background.xml
│       │       │   └── counter_plus_button_background.xml
│       │       ├── layout/
│       │       │   ├── about_item_layout.xml
│       │       │   ├── about_layout.xml
│       │       │   ├── activity_blank_form_list.xml
│       │       │   ├── activity_custom_scanner.xml
│       │       │   ├── activity_preferences_layout.xml
│       │       │   ├── add_repeat_dialog_layout.xml
│       │       │   ├── admin_password_dialog_layout.xml
│       │       │   ├── annotate_widget.xml
│       │       │   ├── audio_controller_layout.xml
│       │       │   ├── audio_player_layout.xml
│       │       │   ├── audio_recording_controller_fragment.xml
│       │       │   ├── audio_video_image_text_label.xml
│       │       │   ├── audio_widget_answer.xml
│       │       │   ├── background_audio_help_fragment_layout.xml
│       │       │   ├── bearing_widget_answer.xml
│       │       │   ├── blank_form_list_item.xml
│       │       │   ├── bottom_sheet.xml
│       │       │   ├── captioned_item.xml
│       │       │   ├── captioned_list_dialog.xml
│       │       │   ├── changes_reason_dialog.xml
│       │       │   ├── checkbox.xml
│       │       │   ├── circular_progress_indicator.xml
│       │       │   ├── counter_widget.xml
│       │       │   ├── current_project_menu_icon.xml
│       │       │   ├── custom_date_picker_dialog.xml
│       │       │   ├── date_time_widget_answer.xml
│       │       │   ├── date_widget_answer.xml
│       │       │   ├── delete_form_layout.xml
│       │       │   ├── delete_project_dialog_layout.xml
│       │       │   ├── draw_widget.xml
│       │       │   ├── ex_audio_widget_answer.xml
│       │       │   ├── ex_image_widget_answer.xml
│       │       │   ├── ex_string_question_type.xml
│       │       │   ├── first_launch_layout.xml
│       │       │   ├── form_chooser_list.xml
│       │       │   ├── form_chooser_list_item.xml
│       │       │   ├── form_chooser_list_item_icon.xml
│       │       │   ├── form_chooser_list_item_map_button.xml
│       │       │   ├── form_chooser_list_item_multiple_choice.xml
│       │       │   ├── form_chooser_list_item_text.xml
│       │       │   ├── form_download_list.xml
│       │       │   ├── form_entry.xml
│       │       │   ├── form_entry_end.xml
│       │       │   ├── form_hierarchy_layout.xml
│       │       │   ├── form_map_activity.xml
│       │       │   ├── fragment_scan.xml
│       │       │   ├── geopoint_question.xml
│       │       │   ├── geoshape_question.xml
│       │       │   ├── geotrace_question.xml
│       │       │   ├── google_drive_deprecation_banner.xml
│       │       │   ├── help_layout.xml
│       │       │   ├── hierarchy_group_item.xml
│       │       │   ├── hierarchy_host_layout.xml
│       │       │   ├── hierarchy_question_item.xml
│       │       │   ├── hierarchy_repeatable_group_instance_item.xml
│       │       │   ├── hierarchy_repeatable_group_item.xml
│       │       │   ├── identify_user_dialog.xml
│       │       │   ├── image_widget.xml
│       │       │   ├── instance_uploader_list.xml
│       │       │   ├── label_widget.xml
│       │       │   ├── launch_intent_button_layout.xml
│       │       │   ├── main_menu.xml
│       │       │   ├── main_menu_activity.xml
│       │       │   ├── main_menu_button.xml
│       │       │   ├── manual_project_creator_dialog_layout.xml
│       │       │   ├── map_button.xml
│       │       │   ├── no_buttons_item_layout.xml
│       │       │   ├── number_picker_dialog.xml
│       │       │   ├── odk_view.xml
│       │       │   ├── osm_widget_answer.xml
│       │       │   ├── password_dialog_layout.xml
│       │       │   ├── permissions_dialog_layout.xml
│       │       │   ├── printer_widget.xml
│       │       │   ├── progress_bar_view.xml
│       │       │   ├── project_icon_view.xml
│       │       │   ├── project_list_item.xml
│       │       │   ├── project_settings_dialog_layout.xml
│       │       │   ├── qr_code_project_creator_dialog_layout.xml
│       │       │   ├── question_error_layout.xml
│       │       │   ├── question_widget.xml
│       │       │   ├── quit_form_dialog_layout.xml
│       │       │   ├── range_picker_widget_answer.xml
│       │       │   ├── range_widget_horizontal.xml
│       │       │   ├── range_widget_vertical.xml
│       │       │   ├── ranking_item.xml
│       │       │   ├── ranking_widget.xml
│       │       │   ├── rating_widget_answer.xml
│       │       │   ├── ready_to_send_banner.xml
│       │       │   ├── reset_dialog_layout.xml
│       │       │   ├── select_image_map_widget_answer.xml
│       │       │   ├── select_list_widget_answer.xml
│       │       │   ├── select_minimal_dialog_layout.xml
│       │       │   ├── select_minimal_widget_answer.xml
│       │       │   ├── select_multi_item.xml
│       │       │   ├── select_one_from_map_widget_answer.xml
│       │       │   ├── select_one_item.xml
│       │       │   ├── server_auth_dialog.xml
│       │       │   ├── show_qrcode_fragment.xml
│       │       │   ├── signature_widget.xml
│       │       │   ├── sort_item_layout.xml
│       │       │   ├── start_new_from_button.xml
│       │       │   ├── tabs_layout.xml
│       │       │   ├── time_widget_answer.xml
│       │       │   ├── transparent_progress_screen.xml
│       │       │   ├── trigger_widget_answer.xml
│       │       │   ├── url_widget_answer.xml
│       │       │   ├── waveform_layout.xml
│       │       │   ├── widget_answer_dialog_layout.xml
│       │       │   └── widget_answer_text.xml
│       │       ├── menu/
│       │       │   ├── blank_form_list_menu.xml
│       │       │   ├── changes_reason_dialog.xml
│       │       │   ├── drafts.xml
│       │       │   ├── form_hierarchy_menu.xml
│       │       │   ├── form_menu.xml
│       │       │   ├── instance_uploader_menu.xml
│       │       │   ├── main_menu.xml
│       │       │   ├── project_preferences_menu.xml
│       │       │   ├── qr_code_scan_menu.xml
│       │       │   ├── saved_form_list_menu.xml
│       │       │   └── select_minimal_dialog_menu.xml
│       │       ├── navigation/
│       │       │   └── form_entry.xml
│       │       ├── raw/
│       │       │   ├── isrgrootx1.pem
│       │       │   └── keep.xml
│       │       ├── values/
│       │       │   ├── arrays.xml
│       │       │   ├── attrs.xml
│       │       │   ├── buttons.xml
│       │       │   ├── colors.xml
│       │       │   ├── date_time_pickers.xml
│       │       │   ├── dimens.xml
│       │       │   ├── form_entry_activity_theme.xml
│       │       │   ├── form_state_colors.xml
│       │       │   ├── leak_canary_config.xml
│       │       │   ├── material_colors.xml
│       │       │   ├── screen_names.xml
│       │       │   ├── settings_theme.xml
│       │       │   ├── shape.xml
│       │       │   ├── styles.xml
│       │       │   ├── theme.xml
│       │       │   └── typography.xml
│       │       ├── values-night/
│       │       │   └── material_colors.xml
│       │       └── xml/
│       │           ├── access_control_preferences.xml
│       │           ├── dev_tools_preferences.xml
│       │           ├── experimental_preferences.xml
│       │           ├── form_entry_access_preferences.xml
│       │           ├── form_management_preferences.xml
│       │           ├── form_metadata_preferences.xml
│       │           ├── identity_preferences.xml
│       │           ├── main_menu_access_preferences.xml
│       │           ├── maps_preferences.xml
│       │           ├── network_security_config.xml
│       │           ├── odk_server_preferences.xml
│       │           ├── project_display_preferences.xml
│       │           ├── project_management_preferences.xml
│       │           ├── project_preferences.xml
│       │           ├── provider_paths.xml
│       │           ├── server_preferences.xml
│       │           ├── user_interface_preferences.xml
│       │           └── user_settings_access_preferences.xml
│       ├── release/
│       │   └── google-services.json
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               ├── android/
│           │               │   ├── TestSettingsProvider.kt
│           │               │   ├── activities/
│           │               │   │   ├── CrashHandlerActivityTest.kt
│           │               │   │   ├── FirstLaunchActivityTest.kt
│           │               │   │   ├── FormFillingActivityTest.kt
│           │               │   │   └── FormHierarchyFragmentHostActivityTest.kt
│           │               │   ├── application/
│           │               │   │   ├── CollectSettingsChangeHandlerTest.kt
│           │               │   │   ├── RobolectricApplication.java
│           │               │   │   └── initialization/
│           │               │   │       ├── AnalyticsInitializerTest.kt
│           │               │   │       ├── CachedFormsCleanerTest.kt
│           │               │   │       ├── ExistingSettingsMigratorTest.kt
│           │               │   │       ├── GoogleDriveProjectsDeleterTest.kt
│           │               │   │       ├── SavepointsImporterTest.kt
│           │               │   │       ├── ScheduledWorkUpgradeTest.kt
│           │               │   │       └── upgrade/
│           │               │   │           └── BeforeProjectsInstallDetectorTest.kt
│           │               │   ├── audio/
│           │               │   │   ├── AudioButtonTest.java
│           │               │   │   ├── AudioControllerViewTest.java
│           │               │   │   ├── AudioRecordingControllerFragmentTest.java
│           │               │   │   ├── AudioRecordingFormErrorDialogFragmentTest.java
│           │               │   │   └── BackgroundAudioHelpDialogFragmentTest.java
│           │               │   ├── backgroundwork/
│           │               │   │   ├── AutoUpdateTaskSpecTest.kt
│           │               │   │   ├── FormUpdateAndInstanceSubmitSchedulerTest.kt
│           │               │   │   ├── SendFormsTaskSpecTest.kt
│           │               │   │   └── SyncFormsTaskSpecTest.kt
│           │               │   ├── configure/
│           │               │   │   └── qr/
│           │               │   │       ├── QRCodeActivityResultDelegateTest.kt
│           │               │   │       ├── QRCodeMenuProviderTest.kt
│           │               │   │       ├── QRCodeScannerFragmentTest.kt
│           │               │   │       └── QRCodeViewModelTest.kt
│           │               │   ├── database/
│           │               │   │   ├── DatabaseFormsRepositoryTest.java
│           │               │   │   ├── DatabaseInstancesRepositoryTest.kt
│           │               │   │   ├── DatabaseSavepointsRepositoryTest.kt
│           │               │   │   ├── FormDatabaseMigratorTest.java
│           │               │   │   ├── InstanceDatabaseMigratorTest.kt
│           │               │   │   └── entities/
│           │               │   │       └── EntitiesDatabaseMigratorTest.kt
│           │               │   ├── dependencies/
│           │               │   │   ├── BikramSambatTest.java
│           │               │   │   └── PersianCalendarTest.java
│           │               │   ├── dynamicpreload/
│           │               │   │   ├── DynamicPreloadExtraTest.kt
│           │               │   │   ├── DynamicPreloadParseProcessorTest.kt
│           │               │   │   ├── ExternalDataReaderTest.java
│           │               │   │   ├── ExternalDataUseCasesTest.kt
│           │               │   │   └── ExternalDataUtilTest.java
│           │               │   ├── entities/
│           │               │   │   ├── DatabaseEntitiesRepositoryTest.kt
│           │               │   │   ├── EntitiesRepositoryTest.kt
│           │               │   │   ├── InMemEntitiesRepositoryTest.kt
│           │               │   │   └── support/
│           │               │   │       └── EntitySameAsMatcher.kt
│           │               │   ├── external/
│           │               │   │   ├── FormUriActivityTest.kt
│           │               │   │   ├── FormsProviderTest.java
│           │               │   │   └── InstanceProviderTest.java
│           │               │   ├── fakes/
│           │               │   │   └── FakePermissionsProvider.kt
│           │               │   ├── formentry/
│           │               │   │   ├── AppStateFormSessionRepositoryTest.kt
│           │               │   │   ├── AudioVideoImageTextLabelTest.java
│           │               │   │   ├── AudioVideoImageTextLabelVisibilityTest.kt
│           │               │   │   ├── BackgroundAudioPermissionDialogFragmentTest.java
│           │               │   │   ├── BackgroundAudioViewModelTest.java
│           │               │   │   ├── FormEndTest.kt
│           │               │   │   ├── FormEndViewModelTest.kt
│           │               │   │   ├── FormEntryMenuProviderTest.kt
│           │               │   │   ├── FormEntryUseCasesTest.kt
│           │               │   │   ├── FormEntryViewModelTest.java
│           │               │   │   ├── FormLoadingDialogFragmentTest.java
│           │               │   │   ├── FormSessionRepositoryTest.kt
│           │               │   │   ├── InMemoryFormSessionRepositoryTest.kt
│           │               │   │   ├── PrinterWidgetViewModelTest.kt
│           │               │   │   ├── QuitFormDialogTest.kt
│           │               │   │   ├── RecordingHandlerTest.java
│           │               │   │   ├── RefreshFormListDialogFragmentTest.java
│           │               │   │   ├── SaveFormProgressDialogFragmentTest.java
│           │               │   │   ├── audit/
│           │               │   │   │   ├── AsyncTaskAuditEventWriterTest.java
│           │               │   │   │   ├── AuditConfigTest.java
│           │               │   │   │   ├── AuditEventCSVLineTest.java
│           │               │   │   │   ├── AuditEventLoggerTest.java
│           │               │   │   │   ├── AuditEventTest.java
│           │               │   │   │   ├── FormSaveViewModelTest.java
│           │               │   │   │   └── IdentityPromptViewModelTest.java
│           │               │   │   ├── backgroundlocation/
│           │               │   │   │   └── BackgroundLocationManagerTest.java
│           │               │   │   ├── repeats/
│           │               │   │   │   └── DeleteRepeatDialogFragmentTest.java
│           │               │   │   └── support/
│           │               │   │       └── InMemFormSessionRepository.kt
│           │               │   ├── formhierarchy/
│           │               │   │   ├── HierarchyListItemViewTest.kt
│           │               │   │   └── QuestionAnswerProcessorTest.kt
│           │               │   ├── formlists/
│           │               │   │   ├── DeleteBlankFormFragmentTest.kt
│           │               │   │   ├── blankformlist/
│           │               │   │   │   ├── BlankFormListItemTest.kt
│           │               │   │   │   ├── BlankFormListItemViewTest.kt
│           │               │   │   │   ├── BlankFormListMenuProviderTest.kt
│           │               │   │   │   └── BlankFormListViewModelTest.kt
│           │               │   │   └── savedformlist/
│           │               │   │       ├── DeleteSavedFormFragmentTest.kt
│           │               │   │       ├── SavedFormListListMenuProviderTest.kt
│           │               │   │       └── SavedFormListViewModelTest.kt
│           │               │   ├── formmanagement/
│           │               │   │   ├── DownloadMediaFilesServerFormUseCasesTest.kt
│           │               │   │   ├── DownloadUpdatesServerFormUseCasesTest.kt
│           │               │   │   ├── FetchFormDetailsServerFormUseCasesTest.kt
│           │               │   │   ├── FilterFormsToAddTest.kt
│           │               │   │   ├── FormFillingIntentFactoryTest.kt
│           │               │   │   ├── FormSourceExceptionMapperTest.kt
│           │               │   │   ├── FormsDataServiceTest.kt
│           │               │   │   ├── LocalFormUseCasesTest.java
│           │               │   │   ├── ServerFormsSynchronizerTest.java
│           │               │   │   ├── ShouldAddFormFileTest.java
│           │               │   │   ├── download/
│           │               │   │   │   ├── FormDownloadExceptionMapperTest.kt
│           │               │   │   │   └── ServerFormDownloaderTest.java
│           │               │   │   ├── drafts/
│           │               │   │   │   └── DraftsMenuProviderTest.kt
│           │               │   │   ├── formmap/
│           │               │   │   │   └── FormMapViewModelTest.kt
│           │               │   │   └── metadata/
│           │               │   │       └── FormMetadataParserTest.kt
│           │               │   ├── fragments/
│           │               │   │   ├── dialogs/
│           │               │   │   │   ├── FormsDownloadResultDialogTest.kt
│           │               │   │   │   ├── RangePickerDialogFragmentTest.kt
│           │               │   │   │   ├── SelectMinimalDialogTest.java
│           │               │   │   │   ├── SelectMultiMinimalDialogTest.java
│           │               │   │   │   └── SelectOneMinimalDialogTest.java
│           │               │   │   └── support/
│           │               │   │       └── DialogFragmentHelpers.java
│           │               │   ├── geo/
│           │               │   │   └── MapFragmentFactoryImplTest.kt
│           │               │   ├── instancemanagement/
│           │               │   │   ├── InstanceDeleterTest.kt
│           │               │   │   ├── InstanceExtKtTest.kt
│           │               │   │   ├── InstanceListItemViewTest.kt
│           │               │   │   ├── InstancesDataServiceTest.kt
│           │               │   │   ├── LocalInstancesUseCasesTest.kt
│           │               │   │   ├── autosend/
│           │               │   │   │   ├── AutoSendSettingsProviderTest.kt
│           │               │   │   │   ├── FormExtTest.kt
│           │               │   │   │   └── InstanceAutoSendFetcherTest.kt
│           │               │   │   └── send/
│           │               │   │       ├── ReadyToSendBannerTest.kt
│           │               │   │       └── ReadyToSendViewModelTest.kt
│           │               │   ├── javarosawrapper/
│           │               │   │   ├── FakeFormController.java
│           │               │   │   └── FormControllerTest.java
│           │               │   ├── location/
│           │               │   │   └── client/
│           │               │   │       ├── FakeLocationClient.java
│           │               │   │       └── MaxAccuracyWithinTimeoutLocationClientWrapperTest.java
│           │               │   ├── mainmenu/
│           │               │   │   ├── CurrentProjectViewModelTest.kt
│           │               │   │   ├── MainMenuActivityTest.kt
│           │               │   │   ├── MainMenuButtonTest.kt
│           │               │   │   ├── MainMenuViewModelTest.kt
│           │               │   │   ├── PermissionsDialogFragmentTest.kt
│           │               │   │   └── RequestPermissionsViewModelTest.kt
│           │               │   ├── notifications/
│           │               │   │   └── NotificationManagerNotifierTest.kt
│           │               │   ├── preferences/
│           │               │   │   ├── AppConfigurationGeneratorTest.kt
│           │               │   │   ├── ProjectPreferencesViewModelTest.kt
│           │               │   │   ├── ServerPreferencesAdderTest.java
│           │               │   │   ├── dialogs/
│           │               │   │   │   ├── AdminPasswordDialogFragmentTest.kt
│           │               │   │   │   ├── ChangeAdminPasswordDialogTest.kt
│           │               │   │   │   ├── DeleteProjectDialogTest.kt
│           │               │   │   │   ├── ResetProgressDialogTest.kt
│           │               │   │   │   └── ServerAuthDialogFragmentTest.java
│           │               │   │   ├── screens/
│           │               │   │   │   ├── FormEntryAccessPreferencesFragmentTest.kt
│           │               │   │   │   ├── FormManagementPreferencesFragmentTest.kt
│           │               │   │   │   ├── FormMetadataPreferencesFragmentTest.kt
│           │               │   │   │   ├── IdentityPreferencesFragmentTest.kt
│           │               │   │   │   ├── MainMenuAccessPreferencesTest.kt
│           │               │   │   │   ├── MapsPreferencesFragmentTest.kt
│           │               │   │   │   ├── ProjectDisplayPreferencesFragmentTest.kt
│           │               │   │   │   ├── ProjectPreferencesFragmentTest.kt
│           │               │   │   │   └── UserInterfacePreferencesFragmentTest.kt
│           │               │   │   └── source/
│           │               │   │       ├── SettingsStoreTest.kt
│           │               │   │       ├── SharedPreferencesSettingsProviderTest.kt
│           │               │   │       └── SharedPreferencesSettingsTest.kt
│           │               │   ├── projects/
│           │               │   │   ├── ExistingProjectMigratorTest.kt
│           │               │   │   ├── ManualProjectCreatorDialogTest.kt
│           │               │   │   ├── ProjectCreatorImplTest.kt
│           │               │   │   ├── ProjectDeleterTest.kt
│           │               │   │   ├── ProjectIconViewTest.kt
│           │               │   │   ├── ProjectListItemViewTest.kt
│           │               │   │   ├── ProjectResetterTest.kt
│           │               │   │   ├── ProjectSettingsDialogTest.kt
│           │               │   │   ├── ProjectsDataServiceTest.kt
│           │               │   │   ├── QrCodeProjectCreatorDialogTest.kt
│           │               │   │   └── SettingsConnectionMatcherImplTest.kt
│           │               │   ├── savepoints/
│           │               │   │   └── SavepointUseCasesTest.kt
│           │               │   ├── storage/
│           │               │   │   └── StoragePathProviderTest.kt
│           │               │   ├── support/
│           │               │   │   ├── CollectHelpers.java
│           │               │   │   ├── Matchers.kt
│           │               │   │   ├── MockFormEntryPromptBuilder.java
│           │               │   │   ├── SwipableParentActivity.kt
│           │               │   │   └── WidgetTestActivity.kt
│           │               │   ├── tasks/
│           │               │   │   └── SaveFormIndexTaskTest.java
│           │               │   ├── utilities/
│           │               │   │   ├── AdminPasswordProviderTest.java
│           │               │   │   ├── AppearancesTest.kt
│           │               │   │   ├── ArrayUtilsTest.java
│           │               │   │   ├── CSVUtilsTest.java
│           │               │   │   ├── ChangeLockProviderTest.kt
│           │               │   │   ├── ExternalAppIntentProviderTest.kt
│           │               │   │   ├── ExternalAppUtilsTest.java
│           │               │   │   ├── FileUtilsTest.java
│           │               │   │   ├── FormNameUtilsTest.java
│           │               │   │   ├── FormsDownloadResultInterpreterTest.kt
│           │               │   │   ├── FormsRepositoryProviderTest.kt
│           │               │   │   ├── FormsUploadResultInterpreterTest.kt
│           │               │   │   ├── HtmlUtilsTest.kt
│           │               │   │   ├── ImageCompressionControllerTest.kt
│           │               │   │   ├── InstanceAutoDeleteCheckerTest.kt
│           │               │   │   ├── InstanceUploaderUtilsTest.java
│           │               │   │   ├── InstancesRepositoryProviderTest.kt
│           │               │   │   ├── MediaUtilsTest.kt
│           │               │   │   ├── MyanmarDateUtilsTest.java
│           │               │   │   ├── QuestionFontSizeUtilsTest.java
│           │               │   │   ├── StubFormController.kt
│           │               │   │   └── WebCredentialsUtilsTest.java
│           │               │   ├── version/
│           │               │   │   └── VersionInformationTest.java
│           │               │   ├── views/
│           │               │   │   ├── ChoicesRecyclerViewTest.java
│           │               │   │   ├── TrackingTouchSliderTest.java
│           │               │   │   └── helpers/
│           │               │   │       └── PromptAutoplayerTest.java
│           │               │   └── widgets/
│           │               │       ├── AnnotateWidgetTest.java
│           │               │       ├── ArbitraryFileWidgetTest.kt
│           │               │       ├── AudioWidgetTest.java
│           │               │       ├── BarcodeWidgetTest.kt
│           │               │       ├── BearingWidgetTest.java
│           │               │       ├── CounterWidgetTest.kt
│           │               │       ├── DecimalWidgetTest.java
│           │               │       ├── DrawWidgetTest.java
│           │               │       ├── ExArbitraryFileWidgetTest.kt
│           │               │       ├── ExAudioWidgetTest.java
│           │               │       ├── ExDecimalWidgetTest.java
│           │               │       ├── ExImageWidgetTest.java
│           │               │       ├── ExIntegerWidgetTest.java
│           │               │       ├── ExStringWidgetTest.kt
│           │               │       ├── ExVideoWidgetTest.kt
│           │               │       ├── GeoPointMapWidgetTest.java
│           │               │       ├── GeoPointWidgetTest.java
│           │               │       ├── GeoShapeWidgetTest.java
│           │               │       ├── GeoTraceWidgetTest.java
│           │               │       ├── ImageWidgetTest.java
│           │               │       ├── IntegerWidgetTest.java
│           │               │       ├── OSMWidgetTest.java
│           │               │       ├── PrinterWidgetTest.kt
│           │               │       ├── QuestionWidgetTest.java
│           │               │       ├── RatingWidgetTest.java
│           │               │       ├── SignatureWidgetTest.java
│           │               │       ├── StringNumberWidgetTest.java
│           │               │       ├── StringWidgetTest.kt
│           │               │       ├── TriggerWidgetTest.java
│           │               │       ├── UrlWidgetTest.java
│           │               │       ├── VideoWidgetTest.kt
│           │               │       ├── WidgetFactoryTest.kt
│           │               │       ├── base/
│           │               │       │   ├── BinaryWidgetTest.java
│           │               │       │   ├── FileWidgetTest.java
│           │               │       │   ├── GeneralExStringWidgetTest.java
│           │               │       │   ├── GeneralSelectMultiWidgetTest.java
│           │               │       │   ├── GeneralSelectOneWidgetTest.java
│           │               │       │   ├── GeneralStringWidgetTest.java
│           │               │       │   ├── QuestionWidgetTest.java
│           │               │       │   ├── SelectWidgetTest.java
│           │               │       │   └── WidgetTest.java
│           │               │       ├── datetime/
│           │               │       │   ├── DateTimeUtilsTest.java
│           │               │       │   ├── DateTimeWidgetTest.java
│           │               │       │   ├── DateTimeWidgetUtilsTest.java
│           │               │       │   ├── DateWidgetTest.java
│           │               │       │   ├── DaylightSavingTest.java
│           │               │       │   ├── TimeWidgetTest.java
│           │               │       │   └── pickers/
│           │               │       │       ├── BikramSambatDatePickerDialogTest.java
│           │               │       │       ├── BuddhistDatePickerDialogTest.kt
│           │               │       │       ├── CopticDatePickerDialogTest.java
│           │               │       │       ├── EthiopianDatePickerDialogTest.java
│           │               │       │       ├── IslamicDatePickerDialogTest.java
│           │               │       │       ├── MyanmarDatePickerDialogTest.java
│           │               │       │       └── PersianDatePickerDialogTest.java
│           │               │       ├── items/
│           │               │       │   ├── LikertWidgetTest.java
│           │               │       │   ├── ListMultiWidgetTest.java
│           │               │       │   ├── ListWidgetTest.java
│           │               │       │   ├── RankingWidgetTest.java
│           │               │       │   ├── SelectChoicesMapDataTest.kt
│           │               │       │   ├── SelectImageMapWidgetTest.java
│           │               │       │   ├── SelectMultiImageMapWidgetTest.java
│           │               │       │   ├── SelectMultiMinimalWidgetTest.java
│           │               │       │   ├── SelectMultiWidgetTest.java
│           │               │       │   ├── SelectOneFromMapDialogFragmentTest.kt
│           │               │       │   ├── SelectOneFromMapWidgetTest.kt
│           │               │       │   ├── SelectOneImageMapWidgetTest.java
│           │               │       │   ├── SelectOneMinimalWidgetTest.java
│           │               │       │   └── SelectOneWidgetTest.java
│           │               │       ├── range/
│           │               │       │   ├── RangeDecimalWidgetTest.java
│           │               │       │   ├── RangeIntegerWidgetTest.java
│           │               │       │   ├── RangePickerWidgetTest.kt
│           │               │       │   └── RangePickerWidgetUtilsTest.kt
│           │               │       ├── support/
│           │               │       │   ├── FakeQuestionMediaManager.java
│           │               │       │   ├── FakeWaitingForDataRegistry.java
│           │               │       │   ├── FormElementFixtures.kt
│           │               │       │   ├── FormEntryPromptSelectChoiceLoader.kt
│           │               │       │   ├── GeoWidgetHelpers.java
│           │               │       │   ├── NoOpMapFragment.kt
│           │               │       │   ├── QuestionWidgetHelpers.java
│           │               │       │   └── SynchronousImageLoader.kt
│           │               │       ├── utilities/
│           │               │       │   ├── ActivityGeoDataRequesterTest.java
│           │               │       │   ├── AudioRecorderRecordingStatusHandlerTest.java
│           │               │       │   ├── ExternalAppRecordingRequesterTest.kt
│           │               │       │   ├── FileRequesterImplTest.kt
│           │               │       │   ├── GeoPolyDialogFragmentTest.kt
│           │               │       │   ├── GeoWidgetUtilsTest.kt
│           │               │       │   ├── GetContentAudioFileRequesterTest.kt
│           │               │       │   ├── InternalRecordingRequesterTest.java
│           │               │       │   ├── RangeWidgetUtilsTest.java
│           │               │       │   ├── RecordingRequesterProviderTest.java
│           │               │       │   ├── StringRequesterImplTest.kt
│           │               │       │   └── StringWidgetUtilsTest.java
│           │               │       ├── viewmodels/
│           │               │       │   ├── DateTimeViewModelTest.java
│           │               │       │   └── QuestionViewModelTest.kt
│           │               │       └── warnings/
│           │               │           ├── SpacesInUnderlyingValuesTest.java
│           │               │           └── SpacesInUnderlyingValuesWarningTest.java
│           │               └── geo/
│           │                   └── javarosa/
│           │                       └── IntersectsFunctionHandlerTest.kt
│           └── resources/
│               ├── forms/
│               │   └── simple-search-external-csv.xml
│               ├── media/
│               │   └── simple-search-external-csv-fruits.csv
│               └── robolectric.properties
├── config/
│   ├── checkstyle.xml
│   ├── lint.xml
│   ├── pmd-ruleset.xml
│   └── quality.gradle
├── crash-handler/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── crashhandler/
│       │   │                   ├── CrashHandler.kt
│       │   │                   ├── CrashView.kt
│       │   │                   └── MockCrashView.kt
│       │   └── res/
│       │       └── layout/
│       │           └── crash_layout.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── crashhandler/
│                               └── CrashHandlerTest.kt
├── create-release.sh
├── db/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── db/
│       │                       └── sqlite/
│       │                           ├── AltDatabasePathContext.kt
│       │                           ├── CursorExt.kt
│       │                           ├── CustomSQLiteQueryBuilder.java
│       │                           ├── CustomSQLiteQueryExecutor.java
│       │                           ├── DatabaseConnection.kt
│       │                           ├── DatabaseMigrator.java
│       │                           ├── MigrationListDatabaseMigrator.kt
│       │                           ├── RowNumbers.kt
│       │                           ├── SQLiteColumns.kt
│       │                           ├── SQLiteDatabaseExt.kt
│       │                           ├── SQLiteUtils.java
│       │                           ├── SqlQuery.kt
│       │                           └── SynchronizedDatabaseConnection.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── db/
│                               └── sqlite/
│                                   ├── CustomSQLiteQueryBuilderTest.java
│                                   ├── DatabaseConnectionTest.kt
│                                   ├── RowNumbersTest.kt
│                                   ├── SQLiteUtilsTest.java
│                                   ├── SqlQueryTest.kt
│                                   ├── SqliteDatabaseExtTest.kt
│                                   └── support/
│                                       └── NoopMigrator.kt
├── debug.keystore
├── docs/
│   ├── ANALYTICS-QUESTIONS.md
│   ├── CODE-GUIDELINES.md
│   ├── CONTRIBUTING.md
│   ├── STATE.md
│   ├── TEST-GUIDELINES.md
│   ├── WIDGETS.md
│   └── WINDOWS-DEV-SETUP.md
├── download-robolectric-deps.sh
├── draw/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── draw/
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── DrawActivity.java
│       │   │                   ├── DrawView.kt
│       │   │                   ├── DrawViewModel.kt
│       │   │                   ├── PenColorPickerDialog.kt
│       │   │                   ├── PenColorPickerViewModel.kt
│       │   │                   ├── QuitDrawingDialog.kt
│       │   │                   └── RobolectricApplication.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── draw_layout.xml
│       │           └── quit_drawing_dialog_layout.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── draw/
│           │                   ├── DrawActivityTest.kt
│           │                   ├── PenColorPickerDialogTest.kt
│           │                   └── PenColorPickerViewModelTest.kt
│           └── resources/
│               └── robolectric.properties
├── entities/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── entities/
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── LocalEntityUseCases.kt
│       │   │                   ├── browser/
│       │   │                   │   ├── EntitiesFragment.kt
│       │   │                   │   ├── EntitiesViewModel.kt
│       │   │                   │   ├── EntityBrowserActivity.kt
│       │   │                   │   ├── EntityItem.kt
│       │   │                   │   └── EntityListsFragment.kt
│       │   │                   ├── javarosa/
│       │   │                   │   ├── filter/
│       │   │                   │   │   ├── LocalEntitiesFilterStrategy.kt
│       │   │                   │   │   └── PullDataFunctionHandler.kt
│       │   │                   │   ├── finalization/
│       │   │                   │   │   ├── EntitiesExtra.kt
│       │   │                   │   │   ├── EntityFormFinalizationProcessor.kt
│       │   │                   │   │   ├── FormEntity.kt
│       │   │                   │   │   └── InvalidEntity.kt
│       │   │                   │   ├── intance/
│       │   │                   │   │   ├── LocalEntitiesExternalInstanceParserFactory.kt
│       │   │                   │   │   ├── LocalEntitiesInstanceAdapter.kt
│       │   │                   │   │   └── LocalEntitiesInstanceProvider.kt
│       │   │                   │   ├── parse/
│       │   │                   │   │   ├── EntityFormExtra.kt
│       │   │                   │   │   ├── EntityFormParseProcessor.kt
│       │   │                   │   │   ├── EntitySchema.kt
│       │   │                   │   │   ├── EntityXFormParserFactory.kt
│       │   │                   │   │   ├── SaveTo.kt
│       │   │                   │   │   ├── StringExt.kt
│       │   │                   │   │   └── XPathExpressionExt.kt
│       │   │                   │   └── spec/
│       │   │                   │       ├── EntityAction.kt
│       │   │                   │       ├── EntityFormParser.kt
│       │   │                   │       ├── FormEntityElement.kt
│       │   │                   │       └── UnrecognizedEntityVersionException.kt
│       │   │                   ├── server/
│       │   │                   │   └── EntitySource.kt
│       │   │                   └── storage/
│       │   │                       ├── EntitiesRepository.kt
│       │   │                       ├── Entity.kt
│       │   │                       ├── EntityList.kt
│       │   │                       ├── InMemEntitiesRepository.kt
│       │   │                       └── QueryException.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── entities_layout.xml
│       │       │   ├── entity_list_item_layout.xml
│       │       │   └── list_layout.xml
│       │       └── navigation/
│       │           └── entities_nav.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── entities/
│                               ├── LocalEntityUseCasesTest.kt
│                               ├── browser/
│                               │   └── EntityItemTest.kt
│                               └── javarosa/
│                                   ├── EntitiesTest.kt
│                                   ├── EntityFormFinalizationProcessorTest.kt
│                                   ├── EntityFormParseProcessorTest.kt
│                                   ├── EntityFormParserTest.kt
│                                   ├── LocalEntitiesInstanceProviderTest.kt
│                                   ├── filter/
│                                   │   ├── LocalEntitiesFilterStrategyTest.kt
│                                   │   └── PullDataFunctionHandlerTest.kt
│                                   ├── parse/
│                                   │   ├── StringExtTest.kt
│                                   │   └── XPathExpressionExtTest.kt
│                                   └── support/
│                                       └── EntityXFormsElement.kt
├── errors/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── errors/
│       │   │                   ├── ErrorActivity.kt
│       │   │                   ├── ErrorAdapter.kt
│       │   │                   └── ErrorItem.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── activity_error.xml
│       │           └── error_item.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── errors/
│           │                   └── ErrorActivityTest.kt
│           └── resources/
│               └── robolectric.properties
├── external-app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── externalapp/
│       │                       └── ExternalAppUtils.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── externalapp/
│                               └── ExternalAppUtilsTest.kt
├── forms/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── forms/
│       │                       ├── Form.java
│       │                       ├── FormListItem.kt
│       │                       ├── FormSource.java
│       │                       ├── FormSourceException.kt
│       │                       ├── FormsRepository.java
│       │                       ├── ManifestFile.kt
│       │                       ├── MediaFile.kt
│       │                       ├── instances/
│       │                       │   ├── Instance.java
│       │                       │   └── InstancesRepository.java
│       │                       └── savepoints/
│       │                           ├── Savepoint.kt
│       │                           └── SavepointsRepository.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── forms/
│                               └── instances/
│                                   └── InstanceTest.kt
├── forms-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── formstest/
│       │                       ├── FormFixtures.kt
│       │                       ├── FormUtils.kt
│       │                       ├── FormsRepositoryTest.java
│       │                       ├── InMemFormsRepository.java
│       │                       ├── InMemInstancesRepository.java
│       │                       ├── InMemSavepointsRepository.kt
│       │                       ├── InstanceFixtures.kt
│       │                       ├── InstanceUtils.kt
│       │                       ├── InstancesRepositoryTest.kt
│       │                       └── SavepointsRepositoryTest.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── formstest/
│                               ├── InMemFormsRepositoryTest.java
│                               ├── InMemInstancesRepositoryTest.kt
│                               └── InMemSavepointsRepositoryTest.kt
├── fragments-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── fragmentstest/
│                               └── FragmentScenarioLauncherRule.kt
├── geo/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── geo/
│       │   │                   ├── Constants.kt
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── GeoActivityUtils.kt
│       │   │                   ├── GeoUtils.kt
│       │   │                   ├── analytics/
│       │   │                   │   └── AnalyticsEvents.kt
│       │   │                   ├── geopoint/
│       │   │                   │   ├── AccuracyProgressView.kt
│       │   │                   │   ├── AccuracyStatusView.kt
│       │   │                   │   ├── GeoPointActivity.kt
│       │   │                   │   ├── GeoPointDialogFragment.kt
│       │   │                   │   ├── GeoPointMapActivity.java
│       │   │                   │   ├── GeoPointViewModel.kt
│       │   │                   │   └── LocationAccuracy.kt
│       │   │                   ├── geopoly/
│       │   │                   │   ├── GeoPolyFragment.kt
│       │   │                   │   ├── GeoPolySettingsDialogFragment.java
│       │   │                   │   ├── GeoPolyUtils.kt
│       │   │                   │   ├── GeoPolyViewModel.kt
│       │   │                   │   └── InfoDialog.kt
│       │   │                   ├── javarosa/
│       │   │                   │   └── IntersectsFunctionHandler.kt
│       │   │                   └── selection/
│       │   │                       ├── MappableSelectItem.kt
│       │   │                       ├── SelectionMapFragment.kt
│       │   │                       └── SelectionSummarySheet.kt
│       │   └── res/
│       │       ├── color/
│       │       │   └── fab_surface_background_color_less_transparent_disabled.xml
│       │       ├── drawable/
│       │       │   ├── ic_add_location.xml
│       │       │   ├── ic_backspace.xml
│       │       │   ├── ic_crop_frame.xml
│       │       │   ├── ic_distance.xml
│       │       │   ├── ic_info.xml
│       │       │   ├── ic_layers.xml
│       │       │   ├── ic_my_location.xml
│       │       │   ├── ic_note_add.xml
│       │       │   ├── ic_pause_36.xml
│       │       │   └── property_divider.xml
│       │       ├── layout/
│       │       │   ├── accuracy_progress_layout.xml
│       │       │   ├── accuracy_status_layout.xml
│       │       │   ├── geopoint_dialog.xml
│       │       │   ├── geopoint_layout.xml
│       │       │   ├── geopoly_dialog.xml
│       │       │   ├── geopoly_layout.xml
│       │       │   ├── property.xml
│       │       │   ├── selection_map_layout.xml
│       │       │   ├── selection_summary_sheet_layout.xml
│       │       │   └── simple_spinner_dropdown_item.xml
│       │       ├── layout-land/
│       │       │   ├── geopoint_layout.xml
│       │       │   └── geopoly_layout.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── fab_surface.xml
│       │           └── force_light_surface_overlay.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── geo/
│           │                   ├── GeoUtilsTest.kt
│           │                   ├── geopoint/
│           │                   │   ├── AccuracyProgressViewTest.kt
│           │                   │   ├── AccuracyStatusViewTest.kt
│           │                   │   ├── GeoPointActivityTest.kt
│           │                   │   ├── GeoPointDialogFragmentTest.kt
│           │                   │   ├── GeoPointMapActivityTest.java
│           │                   │   └── LocationTrackerGeoPointViewModelTest.kt
│           │                   ├── geopoly/
│           │                   │   ├── GeoPolyFragmentTest.kt
│           │                   │   ├── GeoPolySettingsDialogFragmentTest.java
│           │                   │   ├── GeoPolyUtilsTest.kt
│           │                   │   ├── GeoPolyViewModelTest.kt
│           │                   │   └── InfoContentTest.kt
│           │                   ├── selection/
│           │                   │   ├── SelectionMapFragmentTest.kt
│           │                   │   └── SelectionSummarySheetTest.kt
│           │                   └── support/
│           │                       ├── AccuracyStatusViewMatcher.kt
│           │                       ├── FakeLocationTracker.kt
│           │                       ├── FakeMapFragment.kt
│           │                       ├── Fixtures.kt
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── google-maps/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── googlemaps/
│           │                   ├── BitmapDescriptorCache.kt
│           │                   ├── DaggerSetup.kt
│           │                   ├── GoogleMapConfigurator.java
│           │                   ├── GoogleMapFragment.java
│           │                   ├── GoogleMapsMapBoxOfflineTileProvider.java
│           │                   ├── MapPointExt.kt
│           │                   ├── circles/
│           │                   │   └── CircleFeature.kt
│           │                   └── scaleview/
│           │                       ├── Drawer.java
│           │                       ├── MapScaleModel.java
│           │                       ├── MapScaleView.java
│           │                       ├── Scale.java
│           │                       ├── Scales.java
│           │                       └── ViewConfig.java
│           └── res/
│               ├── layout/
│               │   └── map_layout.xml
│               └── values/
│                   └── attrs.xml
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── icons/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── res/
│               └── drawable/
│                   ├── ic_add_white_24.xml
│                   ├── ic_baseline_add_24.xml
│                   ├── ic_baseline_barcode_scanner_white_24.xml
│                   ├── ic_baseline_calendar_today_white_24.xml
│                   ├── ic_baseline_check_24.xml
│                   ├── ic_baseline_collapse_24.xml
│                   ├── ic_baseline_done_all_24.xml
│                   ├── ic_baseline_draw_white_24.xml
│                   ├── ic_baseline_expand_24.xml
│                   ├── ic_baseline_explore_white_24.xml
│                   ├── ic_baseline_format_list_bulleted_white_24.xml
│                   ├── ic_baseline_format_list_numbered_white_24.xml
│                   ├── ic_baseline_language_24.xml
│                   ├── ic_baseline_layers_24.xml
│                   ├── ic_baseline_library_music_white_24.xml
│                   ├── ic_baseline_list_24.xml
│                   ├── ic_baseline_location_off_24.xml
│                   ├── ic_baseline_location_on_24.xml
│                   ├── ic_baseline_location_on_white_24.xml
│                   ├── ic_baseline_markup_white_24.xml
│                   ├── ic_baseline_mic_24.xml
│                   ├── ic_baseline_mic_off_24.xml
│                   ├── ic_baseline_mic_white_24.xml
│                   ├── ic_baseline_my_location_white_24.xml
│                   ├── ic_baseline_open_in_new_white_24.xml
│                   ├── ic_baseline_photo_camera_white_24.xml
│                   ├── ic_baseline_photo_library_white_24.xml
│                   ├── ic_baseline_print_white_24.xml
│                   ├── ic_baseline_qr_code_2_add_24.xml
│                   ├── ic_baseline_remove_24.xml
│                   ├── ic_baseline_rule_24.xml
│                   ├── ic_baseline_settings_24.xml
│                   ├── ic_baseline_signature_white_24.xml
│                   ├── ic_baseline_time_filled_white_24.xml
│                   ├── ic_baseline_visibility_24.xml
│                   ├── ic_baseline_warning_24.xml
│                   ├── ic_baseline_wifi_off_24.xml
│                   ├── ic_clear_white.xml
│                   ├── ic_close.xml
│                   ├── ic_color_lens_white.xml
│                   ├── ic_delete.xml
│                   ├── ic_delete_24.xml
│                   ├── ic_edit.xml
│                   ├── ic_map_marker_big.xml
│                   ├── ic_map_marker_small.xml
│                   ├── ic_map_marker_with_hole_big.xml
│                   ├── ic_map_marker_with_hole_small.xml
│                   ├── ic_map_point.xml
│                   ├── ic_notification_small.xml
│                   ├── ic_outline_info_24.xml
│                   ├── ic_outline_polygon_white_24.xml
│                   ├── ic_outline_polyline_white_24.xml
│                   ├── ic_save.xml
│                   └── ic_save_white.xml
├── image-loader/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── imageloader/
│                               ├── GlideImageLoader.kt
│                               └── svg/
│                                   ├── SvgDecoder.kt
│                                   ├── SvgDrawableTranscoder.kt
│                                   ├── SvgModule.kt
│                                   └── SvgSoftwareLayerSetter.kt
├── lists/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── lists/
│       │   │                   ├── EmptyListView.kt
│       │   │                   ├── RecyclerViewUtils.kt
│       │   │                   └── selects/
│       │   │                       ├── MultiSelectAdapter.kt
│       │   │                       ├── MultiSelectControlsFragment.kt
│       │   │                       ├── MultiSelectListFragment.kt
│       │   │                       ├── MultiSelectViewModel.kt
│       │   │                       ├── SelectItem.kt
│       │   │                       └── SingleSelectViewModel.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── empty_list_view.xml
│       │       │   ├── multi_select_controls_layout.xml
│       │       │   └── multi_select_list.xml
│       │       └── values/
│       │           └── attrs.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── lists/
│           │                   ├── EmptyListViewTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   └── selects/
│           │                       ├── MultiSelectAdapterTest.kt
│           │                       ├── MultiSelectControlsFragmentTest.kt
│           │                       ├── MultiSelectListFragmentTest.kt
│           │                       ├── MultiSelectViewModelTest.kt
│           │                       ├── SingleSelectViewModelTest.kt
│           │                       └── support/
│           │                           └── TextAndCheckboxViewHolder.kt
│           └── resources/
│               └── robolectric.properties
├── location/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── location/
│       │                       ├── AndroidLocationClient.java
│       │                       ├── BaseLocationClient.kt
│       │                       ├── DaggerSetup.kt
│       │                       ├── GoogleFusedLocationClient.kt
│       │                       ├── Location.kt
│       │                       ├── LocationClient.java
│       │                       ├── LocationClientProvider.kt
│       │                       ├── LocationUtils.kt
│       │                       ├── satellites/
│       │                       │   ├── GpsStatusSatelliteInfoClient.kt
│       │                       │   └── SatelliteInfoClient.kt
│       │                       └── tracker/
│       │                           ├── ForegroundServiceLocationTracker.kt
│       │                           └── LocationTracker.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── location/
│           │                   ├── AndroidLocationClientTest.java
│           │                   ├── GoogleFusedLocationClientTest.kt
│           │                   ├── LocationClientProviderTest.kt
│           │                   ├── LocationUtilsTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   ├── TestClientListener.java
│           │                   ├── TestLocationListener.java
│           │                   └── tracker/
│           │                       ├── ForegroundServiceLocationTrackerTest.kt
│           │                       ├── LocationTrackerServiceTest.kt
│           │                       └── LocationTrackerTest.kt
│           └── resources/
│               └── robolectric.properties
├── mapbox/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── mapbox/
│           │                   ├── DynamicPolyLineFeature.kt
│           │                   ├── DynamicPolygonFeature.kt
│           │                   ├── LineFeature.kt
│           │                   ├── MapBoxInitializationFragment.kt
│           │                   ├── MapFeature.kt
│           │                   ├── MapUtils.kt
│           │                   ├── MapboxMapConfigurator.java
│           │                   ├── MapboxMapFragment.kt
│           │                   ├── MarkerFeature.kt
│           │                   ├── StaticPolyLineFeature.kt
│           │                   ├── StaticPolygonFeature.kt
│           │                   └── TileHttpServer.java
│           └── res/
│               └── layout/
│                   └── mapbox_fragment_layout.xml
├── maps/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── maps/
│       │   │                   ├── AnalyticsEvents.kt
│       │   │                   ├── MapConfigurator.kt
│       │   │                   ├── MapConsts.kt
│       │   │                   ├── MapFragment.kt
│       │   │                   ├── MapFragmentFactory.kt
│       │   │                   ├── MapPoint.kt
│       │   │                   ├── MapViewModel.kt
│       │   │                   ├── MapViewModelMapFragment.kt
│       │   │                   ├── ZoomObserver.kt
│       │   │                   ├── circles/
│       │   │                   │   ├── CircleDescription.kt
│       │   │                   │   └── CurrentLocationDelegate.kt
│       │   │                   ├── layers/
│       │   │                   │   ├── DirectoryReferenceLayerRepository.kt
│       │   │                   │   ├── MapFragmentReferenceLayerUtils.kt
│       │   │                   │   ├── MbtilesFile.java
│       │   │                   │   ├── OfflineMapLayersImporterAdapter.kt
│       │   │                   │   ├── OfflineMapLayersImporterDialogFragment.kt
│       │   │                   │   ├── OfflineMapLayersPickerAdapter.kt
│       │   │                   │   ├── OfflineMapLayersPickerBottomSheetDialogFragment.kt
│       │   │                   │   ├── OfflineMapLayersViewModel.kt
│       │   │                   │   ├── ReferenceLayerRepository.kt
│       │   │                   │   └── TileSource.java
│       │   │                   ├── markers/
│       │   │                   │   ├── MarkerDescription.kt
│       │   │                   │   ├── MarkerIconCreator.kt
│       │   │                   │   └── MarkerIconDescription.kt
│       │   │                   └── traces/
│       │   │                       ├── LineDescription.kt
│       │   │                       ├── PolygonDescription.kt
│       │   │                       └── TraceDescription.kt
│       │   └── res/
│       │       ├── drawable/
│       │       │   └── ic_crosshairs.xml
│       │       └── layout/
│       │           ├── offline_map_layers_importer.xml
│       │           ├── offline_map_layers_importer_item.xml
│       │           ├── offline_map_layers_picker.xml
│       │           └── offline_map_layers_picker_item.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── maps/
│           │                   ├── LineDescriptionTest.kt
│           │                   ├── MarkerIconDescriptionTest.kt
│           │                   ├── PolygonDescriptionTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   ├── TraceDescriptionTest.kt
│           │                   └── layers/
│           │                       ├── DirectoryReferenceLayerRepositoryTest.kt
│           │                       ├── InMemReferenceLayerRepository.kt
│           │                       ├── MapFragmentReferenceLayerUtilsTest.kt
│           │                       ├── OfflineMapLayersImporterDialogFragmentTest.kt
│           │                       └── OfflineMapLayersPickerBottomSheetDialogFragmentTest.kt
│           └── resources/
│               └── robolectric.properties
├── material/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── material/
│       │   │                   ├── BottomSheetBehavior.kt
│       │   │                   ├── ErrorsPill.kt
│       │   │                   ├── MaterialFullScreenDialogFragment.kt
│       │   │                   ├── MaterialPill.kt
│       │   │                   ├── MaterialProgressDialogFragment.java
│       │   │                   └── Pill.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── pill.xml
│       │       │   └── progress_dialog.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── material_3_button_icon_end_style.xml
│       │           └── material_full_screen_dialog_theme.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── material/
│                               ├── ErrorsPillTest.kt
│                               └── MaterialProgressDialogFragmentTest.java
├── metadata/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── metadata/
│       │                       ├── InstallIDProvider.kt
│       │                       └── PropertyManager.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── metadata/
│                               ├── PropertyManagerTest.kt
│                               └── SettingsInstallIDProviderTest.kt
├── mobile-device-management/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── mobiledevicemanagement/
│       │   │                   ├── MDMConfigHandler.kt
│       │   │                   └── MDMConfigObserver.kt
│       │   └── res/
│       │       └── xml/
│       │           └── managed_configuration.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── mobiledevicemanagement/
│                               ├── MDMConfigHandlerTest.kt
│                               └── MDMConfigObserverTest.kt
├── nbistubs/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── AndroidManifest.xml
├── open-rosa/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── openrosa/
│       │                       ├── forms/
│       │                       │   ├── DocumentFetchResult.java
│       │                       │   ├── EntityIntegrity.kt
│       │                       │   ├── OpenRosaClient.kt
│       │                       │   └── OpenRosaXmlFetcher.java
│       │                       ├── http/
│       │                       │   ├── CaseInsensitiveEmptyHeaders.java
│       │                       │   ├── CaseInsensitiveHeaders.java
│       │                       │   ├── CollectThenSystemContentTypeMapper.java
│       │                       │   ├── HttpCredentials.java
│       │                       │   ├── HttpCredentialsInterface.java
│       │                       │   ├── HttpGetResult.java
│       │                       │   ├── HttpHeadResult.java
│       │                       │   ├── HttpPostResult.java
│       │                       │   ├── OpenRosaConstants.kt
│       │                       │   ├── OpenRosaHttpInterface.java
│       │                       │   └── okhttp/
│       │                       │       ├── OkHttpCaseInsensitiveHeaders.java
│       │                       │       ├── OkHttpConnection.java
│       │                       │       ├── OkHttpOpenRosaServerClientProvider.java
│       │                       │       ├── OpenRosaServerClient.java
│       │                       │       └── OpenRosaServerClientProvider.java
│       │                       └── parse/
│       │                           ├── Kxml2OpenRosaResponseParser.kt
│       │                           └── OpenRosaResponseParser.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── openrosa/
│                               ├── forms/
│                               │   ├── OpenRosaClientTest.kt
│                               │   └── OpenRosaXmlFetcherTest.java
│                               ├── http/
│                               │   ├── CaseInsensitiveEmptyHeadersTest.java
│                               │   ├── CollectThenSystemContentTypeMapperTest.java
│                               │   ├── OpenRosaGetRequestTest.java
│                               │   ├── OpenRosaHeadRequestTest.java
│                               │   ├── OpenRosaPostRequestTest.java
│                               │   └── okhttp/
│                               │       ├── OkHttpCaseInsensitiveHeadersTest.java
│                               │       ├── OkHttpConnectionGetRequestTest.java
│                               │       ├── OkHttpConnectionHeadRequestTest.java
│                               │       ├── OkHttpConnectionPostRequestTest.java
│                               │       ├── OkHttpOpenRosaServerClientProviderTest.java
│                               │       └── OpenRosaServerClientProviderTest.java
│                               ├── parse/
│                               │   └── Kxml2OpenRosaResponseParserTest.kt
│                               └── support/
│                                   ├── MockWebServerHelper.java
│                                   ├── MockWebServerRule.kt
│                                   └── StubWebCredentialsProvider.java
├── osmdroid/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── osmdroid/
│           │                   ├── DaggerSetup.kt
│           │                   ├── OsmDroidInitializer.kt
│           │                   ├── OsmDroidMapConfigurator.java
│           │                   ├── OsmDroidMapFragment.java
│           │                   ├── OsmMBTileModuleProvider.java
│           │                   ├── OsmMBTileProvider.java
│           │                   ├── OsmMBTileSource.java
│           │                   └── WebMapService.java
│           └── res/
│               └── layout/
│                   └── osm_map_layout.xml
├── permissions/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── permissions/
│       │   │                   ├── LocationAccessibilityChecker.kt
│       │   │                   ├── PermissionListener.kt
│       │   │                   ├── PermissionsChecker.kt
│       │   │                   ├── PermissionsDialogCreator.kt
│       │   │                   ├── PermissionsProvider.kt
│       │   │                   └── RequestPermissionsAPI.kt
│       │   └── res/
│       │       └── drawable/
│       │           ├── ic_photo_camera.xml
│       │           ├── ic_room_24dp.xml
│       │           └── ic_storage.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── permissions/
│           │                   ├── PermissionsDialogCreatorTest.kt
│           │                   └── PermissionsProviderTest.kt
│           └── resources/
│               └── robolectric.properties
├── printer/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── printer/
│                               └── HtmlPrinter.kt
├── projects/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── projects/
│       │                       ├── DaggerSetup.kt
│       │                       ├── InMemProjectsRepository.kt
│       │                       ├── Project.kt
│       │                       ├── ProjectConfigurationResult.kt
│       │                       ├── ProjectCreator.kt
│       │                       ├── ProjectDependencyFactory.kt
│       │                       ├── ProjectsRepository.kt
│       │                       ├── SettingsConnectionMatcher.kt
│       │                       └── SharedPreferencesProjectsRepository.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── projects/
│           │                   ├── InMemProjectsRepositoryTest.kt
│           │                   ├── ProjectsRepositoryTest.kt
│           │                   ├── SharedPreferencesProjectsRepositoryTest.kt
│           │                   └── support/
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── qr-code/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── qrcode/
│       │   │                   ├── BarcodeFilter.kt
│       │   │                   ├── BarcodeScannerViewContainer.kt
│       │   │                   ├── DetectedState.kt
│       │   │                   ├── FlashlightToggle.kt
│       │   │                   ├── ScannerControls.kt
│       │   │                   ├── ScannerOverlay.kt
│       │   │                   ├── mlkit/
│       │   │                   │   ├── MlKitBarcodeScannerViewFactory.kt
│       │   │                   │   └── PlayServicesFallbackBarcodeScannerViewFactory.kt
│       │   │                   └── zxing/
│       │   │                       ├── QRCodeCreator.kt
│       │   │                       ├── QRCodeDecoder.kt
│       │   │                       └── ZxingBarcodeScannerViewFactory.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── mlkit_barcode_scanner_layout.xml
│       │           └── zxing_barcode_scanner_layout.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── qrcode/
│           │                   ├── BarcodeFilterTest.kt
│           │                   └── QRCodeEncodeDecodeTest.kt
│           └── resources/
│               └── robolectric.properties
├── secrets.gradle
├── selfie-camera/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── selfiecamera/
│       │   │                   ├── Camera.kt
│       │   │                   ├── CameraXCamera.kt
│       │   │                   ├── CaptureSelfieActivity.kt
│       │   │                   └── DaggerSetup.kt
│       │   └── res/
│       │       └── layout/
│       │           └── activity_capture_selfie.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── selfiecamera/
│           │                   ├── CaptureSelfieActivityTest.kt
│           │                   └── support/
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── service-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── servicetest/
│                               ├── NotificationDetails.kt
│                               └── ServiceScenario.kt
├── settings/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── settings/
│       │   │                   ├── InMemSettingsProvider.kt
│       │   │                   ├── ODKAppSettingsImporter.kt
│       │   │                   ├── ODKAppSettingsMigrator.java
│       │   │                   ├── SettingsProvider.kt
│       │   │                   ├── enums/
│       │   │                   │   ├── AutoSend.kt
│       │   │                   │   ├── FormUpdateMode.java
│       │   │                   │   ├── GuidanceHintMode.kt
│       │   │                   │   ├── StringIdEnum.kt
│       │   │                   │   └── StringIdEnumUtils.kt
│       │   │                   ├── importing/
│       │   │                   │   ├── ProjectDetailsCreatorImpl.kt
│       │   │                   │   └── SettingsImporter.kt
│       │   │                   ├── keys/
│       │   │                   │   ├── AppConfigurationKeys.kt
│       │   │                   │   ├── MetaKeys.kt
│       │   │                   │   ├── ProjectKeys.kt
│       │   │                   │   └── ProtectedProjectKeys.kt
│       │   │                   ├── migration/
│       │   │                   │   ├── KeyCombiner.java
│       │   │                   │   ├── KeyExtractor.java
│       │   │                   │   ├── KeyMover.java
│       │   │                   │   ├── KeyRenamer.java
│       │   │                   │   ├── KeyTranslator.java
│       │   │                   │   ├── KeyUpdater.java
│       │   │                   │   ├── KeyValuePair.java
│       │   │                   │   ├── Migration.java
│       │   │                   │   ├── MigrationUtils.java
│       │   │                   │   └── ValueTranslator.java
│       │   │                   └── validation/
│       │   │                       └── JsonSchemaSettingsValidator.kt
│       │   ├── res/
│       │   │   └── values/
│       │   │       └── strings.xml
│       │   └── resources/
│       │       └── client-settings.schema.json
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── settings/
│                               ├── ODKAppSettingsImporterTest.kt
│                               ├── ODKAppSettingsMigratorTest.java
│                               ├── importing/
│                               │   ├── ProjectDetailsCreatorImplTest.kt
│                               │   └── SettingsImporterTest.kt
│                               ├── migration/
│                               │   ├── KeyCombinerTest.java
│                               │   ├── KeyExtractorTest.java
│                               │   ├── KeyMoverTest.java
│                               │   ├── KeyRemoverTest.java
│                               │   ├── KeyRenamerTest.java
│                               │   ├── KeyTranslatorTest.java
│                               │   └── ValueTranslatorTest.java
│                               ├── support/
│                               │   └── SettingsUtils.kt
│                               └── validation/
│                                   ├── JsonSchemaSettingsValidatorTest.kt
│                                   └── OriginalJsonSchemaSettingsValidatorTest.kt
├── settings.gradle
├── shadows/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── shadows/
│       │                       └── ShadowAndroidXAlertDialog.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── shadows/
│                               └── ShadowAndroidXAlertDialogTest.kt
├── shared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── shared/
│       │                       ├── DebugLogger.kt
│       │                       ├── PathUtils.kt
│       │                       ├── Query.kt
│       │                       ├── TempFiles.kt
│       │                       ├── TimeInMs.kt
│       │                       ├── collections/
│       │                       │   └── CollectionExtensions.kt
│       │                       ├── files/
│       │                       │   └── FileExt.kt
│       │                       ├── geometry/
│       │                       │   └── Geometry.kt
│       │                       ├── injection/
│       │                       │   └── ObjectProvider.kt
│       │                       ├── locks/
│       │                       │   ├── BooleanChangeLock.kt
│       │                       │   ├── ChangeLock.kt
│       │                       │   └── ThreadSafeBooleanChangeLock.kt
│       │                       ├── result/
│       │                       │   └── Result.kt
│       │                       ├── settings/
│       │                       │   ├── InMemSettings.kt
│       │                       │   └── Settings.kt
│       │                       └── strings/
│       │                           ├── Md5.kt
│       │                           ├── RandomString.java
│       │                           ├── StringUtils.kt
│       │                           └── UUIDGenerator.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── shared/
│                               ├── Md5Test.kt
│                               ├── PathUtilsTest.kt
│                               ├── QuickCheck.kt
│                               ├── collections/
│                               │   └── CollectionExtensionsTest.kt
│                               ├── files/
│                               │   └── FileExtTest.kt
│                               ├── geometry/
│                               │   ├── GeometryTest.kt
│                               │   └── support/
│                               │       ├── GeometryTestUtils.kt
│                               │       └── GeometryTestUtilsTest.kt
│                               ├── locks/
│                               │   ├── BooleanChangeLockTest.kt
│                               │   ├── ChangeLockTest.kt
│                               │   └── ThreadSafeBooleanChangeLockTest.kt
│                               └── strings/
│                                   └── StringUtilsTest.kt
├── strings/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── strings/
│       │   │                   ├── format/
│       │   │                   │   └── LengthFormatter.kt
│       │   │                   └── localization/
│       │   │                       ├── LocalizedActivity.kt
│       │   │                       └── LocalizedApplication.kt
│       │   └── res/
│       │       ├── values/
│       │       │   ├── strings.xml
│       │       │   └── untranslated.xml
│       │       ├── values-af/
│       │       │   └── strings.xml
│       │       ├── values-am/
│       │       │   └── strings.xml
│       │       ├── values-ar/
│       │       │   └── strings.xml
│       │       ├── values-bg/
│       │       │   └── strings.xml
│       │       ├── values-bn/
│       │       │   └── strings.xml
│       │       ├── values-ca/
│       │       │   └── strings.xml
│       │       ├── values-cs/
│       │       │   └── strings.xml
│       │       ├── values-da/
│       │       │   └── strings.xml
│       │       ├── values-de/
│       │       │   └── strings.xml
│       │       ├── values-es/
│       │       │   └── strings.xml
│       │       ├── values-es-rSV/
│       │       │   └── strings.xml
│       │       ├── values-et/
│       │       │   └── strings.xml
│       │       ├── values-fa/
│       │       │   └── strings.xml
│       │       ├── values-fa-rAF/
│       │       │   └── strings.xml
│       │       ├── values-fi/
│       │       │   └── strings.xml
│       │       ├── values-fr/
│       │       │   └── strings.xml
│       │       ├── values-hi/
│       │       │   └── strings.xml
│       │       ├── values-ht/
│       │       │   └── strings.xml
│       │       ├── values-in/
│       │       │   └── strings.xml
│       │       ├── values-it/
│       │       │   └── strings.xml
│       │       ├── values-ja/
│       │       │   └── strings.xml
│       │       ├── values-ka/
│       │       │   └── strings.xml
│       │       ├── values-km/
│       │       │   └── strings.xml
│       │       ├── values-ln/
│       │       │   └── strings.xml
│       │       ├── values-lo-rLA/
│       │       │   └── strings.xml
│       │       ├── values-lt/
│       │       │   └── strings.xml
│       │       ├── values-mg/
│       │       │   └── strings.xml
│       │       ├── values-ml/
│       │       │   └── strings.xml
│       │       ├── values-mr/
│       │       │   └── strings.xml
│       │       ├── values-ms/
│       │       │   └── strings.xml
│       │       ├── values-my/
│       │       │   └── strings.xml
│       │       ├── values-ne-rNP/
│       │       │   └── strings.xml
│       │       ├── values-nl/
│       │       │   └── strings.xml
│       │       ├── values-no/
│       │       │   └── strings.xml
│       │       ├── values-pl/
│       │       │   └── strings.xml
│       │       ├── values-ps/
│       │       │   └── strings.xml
│       │       ├── values-pt/
│       │       │   └── strings.xml
│       │       ├── values-ro/
│       │       │   └── strings.xml
│       │       ├── values-ru/
│       │       │   └── strings.xml
│       │       ├── values-rw/
│       │       │   └── strings.xml
│       │       ├── values-si/
│       │       │   └── strings.xml
│       │       ├── values-sl/
│       │       │   └── strings.xml
│       │       ├── values-so/
│       │       │   └── strings.xml
│       │       ├── values-sq/
│       │       │   └── strings.xml
│       │       ├── values-sr/
│       │       │   └── strings.xml
│       │       ├── values-sv-rSE/
│       │       │   └── strings.xml
│       │       ├── values-sw/
│       │       │   └── strings.xml
│       │       ├── values-sw-rKE/
│       │       │   └── strings.xml
│       │       ├── values-te/
│       │       │   └── strings.xml
│       │       ├── values-th-rTH/
│       │       │   └── strings.xml
│       │       ├── values-ti/
│       │       │   └── strings.xml
│       │       ├── values-tl/
│       │       │   └── strings.xml
│       │       ├── values-tl-rPH/
│       │       │   └── strings.xml
│       │       ├── values-tr/
│       │       │   └── strings.xml
│       │       ├── values-uk/
│       │       │   └── strings.xml
│       │       ├── values-ur/
│       │       │   └── strings.xml
│       │       ├── values-ur-rPK/
│       │       │   └── strings.xml
│       │       ├── values-vi/
│       │       │   └── strings.xml
│       │       ├── values-zh/
│       │       │   └── strings.xml
│       │       ├── values-zh-rTW/
│       │       │   └── strings.xml
│       │       └── values-zu/
│       │           └── strings.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── strings/
│           │                   └── format/
│           │                       ├── DateFormatsTest.kt
│           │                       └── LengthFormatterTest.kt
│           └── resources/
│               └── robolectric.properties
├── test-forms/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── resources/
│               ├── forms/
│               │   ├── Empty First Repeat.xml
│               │   ├── RepeatGroupAndGroup.xml
│               │   ├── RepeatTitles_1648.xml
│               │   ├── TestRepeat.xml
│               │   ├── all-widgets.xml
│               │   ├── audio-question.xml
│               │   ├── basic.xml
│               │   ├── different-search-appearances.xml
│               │   ├── dynamic_and_static_choices.xml
│               │   ├── dynamic_required_question.xml
│               │   ├── emptyGroupFieldList.xml
│               │   ├── encrypted-no-instanceID.xml
│               │   ├── encrypted.xml
│               │   ├── entity-update-pulldata.xml
│               │   ├── external-audio-question.xml
│               │   ├── external-csv-search-broken.xml
│               │   ├── external-csv-search.xml
│               │   ├── external_csv_form.xml
│               │   ├── external_data_questions.xml
│               │   ├── external_select.xml
│               │   ├── external_select_10.xml
│               │   ├── external_select_csv.xml
│               │   ├── field-list-repeat.xml
│               │   ├── fieldlist-updates.xml
│               │   ├── fixed-count-repeat.xml
│               │   ├── form1.xml
│               │   ├── form2.xml
│               │   ├── form3.xml
│               │   ├── form4.xml
│               │   ├── form5.xml
│               │   ├── form6.xml
│               │   ├── form7.xml
│               │   ├── form8.xml
│               │   ├── form9.xml
│               │   ├── formHierarchy1.xml
│               │   ├── formHierarchy2.xml
│               │   ├── formHierarchy3.xml
│               │   ├── form_design_error.xml
│               │   ├── form_styling.xml
│               │   ├── form_with_images.xml
│               │   ├── g6Error.xml
│               │   ├── hints_textq.xml
│               │   ├── identify-user-audit-false.xml
│               │   ├── identify-user-audit.xml
│               │   ├── intent-group.xml
│               │   ├── internal-audio-question.xml
│               │   ├── invalid-form.xml
│               │   ├── likert_test.xml
│               │   ├── location-audit.xml
│               │   ├── manyQ.xml
│               │   ├── metadata.xml
│               │   ├── nested-intent-group.xml
│               │   ├── numberInCSV.xml
│               │   ├── one-question-audit.xml
│               │   ├── one-question-autoplay.xml
│               │   ├── one-question-autosend-disabled.xml
│               │   ├── one-question-autosend.xml
│               │   ├── one-question-background-audio-audit.xml
│               │   ├── one-question-background-audio-multiple.xml
│               │   ├── one-question-background-audio.xml
│               │   ├── one-question-editable.xml
│               │   ├── one-question-encrypted-unicode.xml
│               │   ├── one-question-entity-create-and-update.xml
│               │   ├── one-question-entity-follow-up.xml
│               │   ├── one-question-entity-registration-broken.xml
│               │   ├── one-question-entity-registration-editable.xml
│               │   ├── one-question-entity-registration-id.xml
│               │   ├── one-question-entity-registration-v2020.1.xml
│               │   ├── one-question-entity-registration-v2023.1.xml
│               │   ├── one-question-entity-registration.xml
│               │   ├── one-question-entity-update-and-create.xml
│               │   ├── one-question-entity-update-editable.xml
│               │   ├── one-question-entity-update.xml
│               │   ├── one-question-last-saved-updated.xml
│               │   ├── one-question-last-saved.xml
│               │   ├── one-question-partial.xml
│               │   ├── one-question-repeat.xml
│               │   ├── one-question-translation.xml
│               │   ├── one-question-updated.xml
│               │   ├── one-question-uuid-instance-name.xml
│               │   ├── one-question-with-constraint.xml
│               │   ├── one-question.xml
│               │   ├── pull_data.xml
│               │   ├── random.xml
│               │   ├── randomTest_broken.xml
│               │   ├── ranking_widget.xml
│               │   ├── repeat_group_form.xml
│               │   ├── repeat_group_new.xml
│               │   ├── repeat_group_wrapped_with_a_regular_group.xml
│               │   ├── repeat_groups.xml
│               │   ├── repeat_in_field_list.xml
│               │   ├── repeat_without_label.xml
│               │   ├── requiredQuestionInFieldList.xml
│               │   ├── required_question_with_audio.xml
│               │   ├── required_question_with_custom_error_message.xml
│               │   ├── search_and_select.xml
│               │   ├── selectOneExternal.xml
│               │   ├── select_one_external.xml
│               │   ├── setgeopoint-action.xml
│               │   ├── simple-search-external-csv.xml
│               │   ├── single-geopoint.xml
│               │   ├── start-geopoint.xml
│               │   ├── string_widgets_in_field_list.xml
│               │   ├── track-changes-reason-on-edit.xml
│               │   ├── two-question-audit-track-changes.xml
│               │   ├── two-question-audit.xml
│               │   ├── two-question-external.xml
│               │   ├── two-question-required.xml
│               │   ├── two-question-save-incomplete-required.xml
│               │   ├── two-question-save-incomplete.xml
│               │   ├── two-question-updated.xml
│               │   ├── two-question.xml
│               │   ├── two-questions-in-group.xml
│               │   └── validate.xml
│               └── media/
│                   ├── external-csv-search-produce.csv
│                   ├── external_csv_cities.csv
│                   ├── external_csv_countries.csv
│                   ├── external_csv_neighbourhoods.csv
│                   ├── external_data.csv
│                   ├── external_data.xml
│                   ├── external_data_10.xml
│                   ├── external_data_broken.csv
│                   ├── fruits.csv
│                   ├── itemSets.csv
│                   ├── people.csv
│                   ├── selectOneExternal-media/
│                   │   └── itemsets.csv
│                   ├── simple-search-external-csv-fruits.csv
│                   ├── test.m4a
│                   └── updated-people.csv
├── test-shared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── testshared/
│                               ├── ActivityControllerRule.kt
│                               ├── ActivityExt.kt
│                               ├── AssertIntentsHelper.kt
│                               ├── AssertionFramework.kt
│                               ├── ComposeAssertions.kt
│                               ├── ComposeInteractions.kt
│                               ├── DummyActivity.kt
│                               ├── ErrorIntentLauncher.kt
│                               ├── EspressoAssertions.kt
│                               ├── EspressoInteractions.kt
│                               ├── FakeAudioPlayer.kt
│                               ├── FakeBarcodeScannerView.kt
│                               ├── FakeBroadcastReceiverRegister.kt
│                               ├── FakeScheduler.kt
│                               ├── FragmentResultRecorder.kt
│                               ├── LocationTestUtils.kt
│                               ├── MockFragmentFactory.kt
│                               ├── MockWebPageService.kt
│                               ├── RecyclerViewMatcher.kt
│                               ├── RobolectricHelpers.kt
│                               ├── SliderExt.kt
│                               ├── TimeZoneSetter.kt
│                               ├── ViewActions.kt
│                               ├── ViewMatchers.kt
│                               └── WaitFor.kt
├── timedgrid/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── timedgrid/
│           │                   ├── AssessmentType.kt
│           │                   ├── CommonTimedGridRenderer.kt
│           │                   ├── FinishType.kt
│           │                   ├── NavigationAwareWidget.kt
│           │                   ├── PausableCountDownTimer.kt
│           │                   ├── TimedGridRenderer.kt
│           │                   ├── TimedGridState.kt
│           │                   ├── TimedGridSummary.kt
│           │                   ├── TimedGridSummaryAnswerCreator.kt
│           │                   ├── TimedGridViewModel.kt
│           │                   ├── TimedGridWidgetConfiguration.kt
│           │                   ├── TimedGridWidgetDelegate.kt
│           │                   └── TimedGridWidgetLayout.kt
│           └── res/
│               ├── color/
│               │   └── timed_grid_button_tint_selector.xml
│               ├── drawable/
│               │   └── row_number_background.xml
│               ├── layout/
│               │   ├── timed_grid.xml
│               │   ├── timed_grid_item_button.xml
│               │   └── timed_grid_item_row.xml
│               └── values/
│                   ├── colors.xml
│                   ├── dimens.xml
│                   ├── strings.xml
│                   └── styles.xml
├── upgrade/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── upgrade/
│       │                       ├── AppUpgrader.kt
│       │                       ├── LaunchState.kt
│       │                       └── Upgrade.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── upgrade/
│                               ├── AppUpgraderTest.kt
│                               └── VersionCodeLaunchStateTest.kt
└── web-page/
    ├── .gitignore
    ├── build.gradle.kts
    └── src/
        ├── main/
        │   ├── AndroidManifest.xml
        │   └── java/
        │       └── org/
        │           └── odk/
        │               └── collect/
        │                   └── webpage/
        │                       ├── CustomTabsWebPageService.kt
        │                       └── WebPageService.kt
        └── test/
            └── java/
                └── org/
                    └── odk/
                        └── collect/
                            └── webpage/
                                └── CustomTabsWebPageServiceTest.java

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
# This config and the the Gradle flags/opts are based on: https://circleci.com/docs/2.0/language-android/
# and https://support.circleci.com/hc/en-us/articles/360021812453

version: 2

references:
  android_config_small: &android_config_small
    working_directory: ~/work
    docker:
      - image: cimg/android:2026.02
    resource_class: small

  android_config: &android_config
    working_directory: ~/work
    docker:
      - image: cimg/android:2026.02
    resource_class: large

  android_config_large: &android_config_large
    working_directory: ~/work
    docker:
      - image: cimg/android:2026.02
    resource_class: xlarge

  gcloud_config: &gcloud_config
    working_directory: ~/work
    docker:
      - image: cimg/gcp:2025.01
    resource_class: small

jobs:
  compile:
    <<: *android_config
    steps:
      - checkout
      - restore_cache:
          keys:
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-
      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle.properties ~/.gradle/gradle.properties
      - run:
          name: Download Robolectric deps
          command: ./download-robolectric-deps.sh

      - run:
          name: Compile code
          command: ./gradlew assembleDebug

      - save_cache:
          paths:
            - ~/.gradle/caches
            - ~/.gradle/wrapper
          key: compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
      - save_cache:
          paths:
            - ~/work
          key: workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}

      - persist_to_workspace:
          root: ~/work
          paths:
            - collect_app/build/outputs/apk

  create_dependency_backup:
    <<: *android_config_small
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Create Maven repo from dependencies
          command: ./gradlew cacheToMavenLocal
      - run:
          name: Compress Maven repo
          command: tar -cvzf maven.tar .local-m2
      - store_artifacts:
          path: maven.tar

  check_quality:
    <<: *android_config
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle.properties ~/.gradle/gradle.properties

      - run:
          name: Run code quality checks
          command: ./gradlew pmd ktlintCheck checkstyle

      - run:
          name: Run Android lint
          command: ./gradlew lintDebug

  test_modules:
    <<: *android_config
    parallelism: 4
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - test_modules-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - test_modules
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle.properties ~/.gradle/gradle.properties

      - run:
          name: Generate list of modules for this fork
          command: |
            cat .circleci/test_modules.txt | circleci tests split > .circleci/fork_test_modules.txt && \
            echo "Modules for this fork:" && \
            cat .circleci/fork_test_modules.txt

      - run:
          name: Run module unit tests
          command: |
            ./gradlew $(cat .circleci/fork_test_modules.txt | awk '{for (i=1; i<=NF; i++) printf "%s:testDebug ",$i}')

      - store_test_results:
          path: collect_app/build/test-results

      - save_cache:
          paths:
            - ~/.gradle/caches
            - ~/.gradle/wrapper
          key: test_modules-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}

  test_app:
    <<: *android_config
    parallelism: 4
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - test_app-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - test_app-
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle.properties ~/.gradle/gradle.properties

      - run:
          name: Generate list of test classes
          command: .circleci/generate-app-test-list.sh

      - run:
          name: Generate list of tests for this fork
          command: |
            cat .circleci/collect_app_test_classes.txt | circleci tests split > .circleci/fork_test_classes.txt && \
            echo "Tests for this fork:" && \
            cat .circleci/fork_test_classes.txt && \
            echo "" && \
            echo "Will run command:" && \
            echo "./gradlew collect_app:testDebug $(cat .circleci/fork_test_classes.txt | awk '{for (i=1; i<=NF; i++) printf "--tests %s ",$i}')"

      - run:
          name: Run app unit tests
          command: |
            ./gradlew collect_app:testDebug $(cat .circleci/fork_test_classes.txt | awk '{for (i=1; i<=NF; i++) printf "--tests %s ",$i}')

      - store_artifacts:
          path: collect_app/build/reports
          destination: reports
      - store_test_results:
          path: collect_app/build/test-results

      - save_cache:
          paths:
            - ~/.gradle/caches
            - ~/.gradle/wrapper
          key: test_app-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}

  build_instrumented:
    <<: *android_config_large
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - build_instrumented-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - build_instrumented-
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle-large.properties ~/.gradle/gradle.properties

      - run:
          name: Assemble connected test build
          command: ./gradlew assembleDebugAndroidTest

      - save_cache:
          paths:
            - ~/.gradle/caches
            - ~/.gradle/wrapper
          key: build_instrumented-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}

      - persist_to_workspace:
          root: ~/work
          paths:
            - collect_app/build/outputs/apk

  build_release:
    <<: *android_config
    steps:
      - checkout
      - restore_cache:
          keys:
            - workflow-{{ .Environment.CIRCLE_WORKFLOW_ID }}
      - restore_cache:
          keys:
            - compile-{{ checksum "gradle/libs.versions.toml" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}
            - compile-

      - run:
          name: Copy gradle config
          command: mkdir -p ~/.gradle && cp .circleci/gradle.properties ~/.gradle/gradle.properties

      - run:
          name: Set up secrets.properties for Maps frameworks
          command: |
            if [[ -n "$GOOGLE_MAPS_API_KEY" ]]; then \
              echo "GOOGLE_MAPS_API_KEY=$GOOGLE_MAPS_API_KEY" >> secrets.properties
              echo "MAPBOX_ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN" >> secrets.properties
              echo "MAPBOX_DOWNLOADS_TOKEN=$MAPBOX_DOWNLOADS_TOKEN" >> secrets.properties
            fi

      - run:
          name: Assemble self signed release build
          command: ./gradlew assembleSelfSignedRelease

      - run:
          name: Check APK size hasn't increased
          command: |
            if [[ -n "$GOOGLE_MAPS_API_KEY" ]]; then \
              ./check-size.sh 20447232
            else
              ./check-size.sh 11010048
            fi

      - run:
          name: Copy APK to predictable path for artifact storage
          command: cp collect_app/build/outputs/apk/selfSignedRelease/*.apk selfSignedRelease.apk
      - store_artifacts:
          path: selfSignedRelease.apk

  test_smoke_instrumented:
    <<: *gcloud_config
    steps:
      - attach_workspace:
          at: /tmp/workspace

      - run:
          name: Authorize gcloud
          command: |
            if [[ "$CIRCLE_PROJECT_USERNAME" == "getodk" ]]; then \
              gcloud config set project api-project-322300403941
              echo $GCLOUD_SERVICE_KEY | base64 --decode > client-secret.json
              gcloud auth activate-service-account --key-file client-secret.json
            fi
      - run:
          name: Run integration tests
          command: |
            if [[ "$CIRCLE_PROJECT_USERNAME" == "getodk" ]]; then \
              echo "y" | gcloud beta firebase test android run \
              --type instrumentation \
              --app /tmp/workspace/collect_app/build/outputs/apk/debug/ODK-Collect-debug.apk \
              --test /tmp/workspace/collect_app/build/outputs/apk/androidTest/debug/ODK-Collect-debug-androidTest.apk \
              --device model=MediumPhone.arm,version=34,locale=en,orientation=portrait \
              --results-bucket opendatakit-collect-test-results \
              --directories-to-pull /sdcard --timeout 20m \
              --test-targets "package org.odk.collect.android.feature.smoke"
            fi
          no_output_timeout: 25m

  test_instrumented:
    <<: *gcloud_config
    steps:
      - attach_workspace:
          at: /tmp/workspace

      - run:
          name: Authorize gcloud
          command: |
            if [[ -n "$GCLOUD_SERVICE_KEY" ]]; then \
              gcloud config set project api-project-322300403941
              echo $GCLOUD_SERVICE_KEY | base64 --decode > client-secret.json
              gcloud auth activate-service-account --key-file client-secret.json
            fi
      - run:
          name: Run integration tests
          command: |
            echo "y" | gcloud beta firebase test android run \
              --type instrumentation \
              --num-uniform-shards=25 \
              --app /tmp/workspace/collect_app/build/outputs/apk/debug/ODK-Collect-debug.apk \
              --test /tmp/workspace/collect_app/build/outputs/apk/androidTest/debug/ODK-Collect-debug-androidTest.apk \
              --device model=MediumPhone.arm,version=34,locale=en,orientation=portrait \
              --results-bucket opendatakit-collect-test-results \
              --directories-to-pull /sdcard --timeout 20m \
              --test-targets "notPackage org.odk.collect.android.regression" \
              --test-targets "notPackage org.odk.collect.android.benchmark"
          no_output_timeout: 25m

workflows:
  version: 2
  pr:
    jobs:
      - hold_pr:
          type: approval
          filters:
            branches:
              ignore:
                - master
                - ^v((20)[0-9]{2})\.\d+\.x$
      - compile:
          requires:
            - hold_pr
      - check_quality:
          requires:
            - compile
      - test_modules:
          requires:
            - compile
      - test_app:
          requires:
            - compile
      - build_release:
          requires:
            - compile
      - build_instrumented:
          requires:
            - compile

  master:
    jobs:
      - compile:
          filters:
            branches:
              only:
                - master
                - ^v((20)[0-9]{2})\.\d+\.x$
      - check_quality:
          requires:
            - compile
      - test_modules:
          requires:
            - compile
      - test_app:
          requires:
            - compile
      - build_release:
          requires:
            - compile
      - build_instrumented:
          requires:
            - compile
      - test_smoke_instrumented:
          requires:
            - build_instrumented

  nightly:
    triggers:
      - schedule:
          cron: "0 0 * * 1-5"
          filters:
            branches:
              only:
                - master
    jobs:
      - compile
      - build_instrumented:
          requires:
            - compile
      - test_instrumented:
          requires:
            - build_instrumented

  release:
    jobs:
      - compile:
          filters:
            tags:
              only: /^v((20)[0-9]{2})\.\d+\.\d+$/ # matches semvers like v1.2.3
            branches:
              ignore: /.*/
      - create_dependency_backup:
          requires:
            - compile
          filters:
            tags:
              only: /^v((20)[0-9]{2})\.\d+\.\d+$/ # matches semvers like v1.2.3
            branches:
              ignore: /.*/



================================================
FILE: .circleci/generate-app-test-list.sh
================================================
ls -R collect_app/src/test/java/ | grep Test.java > .circleci/collect_app_test_files.txt
ls -R collect_app/src/test/java/ | grep Test.kt >> .circleci/collect_app_test_files.txt
cat .circleci/collect_app_test_files.txt | sed "s/\.java//" | sed "s/\.kt//" > .circleci/collect_app_test_classes.txt


================================================
FILE: .circleci/gradle-large.properties
================================================
# Gradle config for "X-Large" Circle CI resource (https://circleci.com/pricing/price-list/)

org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dkotlin.daemon.jvm.options=-Xmx2g
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.workers.max=8
test.heap.max=1g


================================================
FILE: .circleci/gradle.properties
================================================
# Gradle config for "Large" Circle CI resource (https://circleci.com/pricing/price-list/)

org.gradle.jvmargs=-Xmx2560m -XX:MaxMetaspaceSize=1g
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.workers.max=4
test.heap.max=1g


================================================
FILE: .circleci/test_modules.txt
================================================
shared
forms-test
androidshared
async
strings
audio-clips
audio-recorder
projects
location
geo
upgrade
permissions
settings
maps
errors
crash-handler
entities
qr-code
shadows
metadata
selfie-camera
draw
printer
lists
web-page
open-rosa
mobile-device-management
material


================================================
FILE: .editorconfig
================================================
root = true

[*.{kt,kts}]
ktlint_standard_no-blank-lines-in-chained-method-calls = disabled
ktlint_standard_trailing-comma-on-call-site = disabled
ktlint_standard_trailing-comma-on-declaration-site = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_no-empty-first-line-in-class-body = disabled
ktlint_standard_argument-list-wrapping = disabled
ktlint_standard_parameter-list-wrapping = disabled
ktlint_standard_multiline-expression-wrapping = disabled
ktlint_standard_max-line-length = disabled
ktlint_standard_string-template-indent = disabled
ktlint_standard_annotation = disabled
ktlint_standard_value-parameter-comment = disabled
ktlint_standard_property-naming = disabled
ktlint_standard_value-argument-comment = disabled
ktlint_standard_blank-line-before-declaration = disabled
ktlint_standard_no-consecutive-comments = disabled
ktlint_standard_enum-wrapping = disabled
ktlint_standard_statement-wrapping = disabled
ktlint_standard_try-catch-finally-spacing = disabled
ktlint_standard_wrapping = disabled
ktlint_standard_chain-method-continuation = disabled
ktlint_standard_function-expression-body = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_binary-expression-wrapping = disabled
ktlint_standard_condition-wrapping = disabled
ktlint_standard_function-literal = disabled
ktlint_standard_backing-property-naming = disabled
ktlint_function_naming_ignore_when_annotated_with = Composable
ktlint_standard_no-unused-imports=enabled


================================================
FILE: .gitattributes
================================================
* text=lf


================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
Please refer to the project-wide [ODK Code of Conduct](https://github.com/getodk/governance/blob/master/CODE-OF-CONDUCT.md).

================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links: 
  - name: "Report an issue"
    about: "For when Collect is behaving in an unexpected way"
    url: "https://forum.getodk.org/c/support/6"
  - name: "Request a feature"
    about: "For when Collect is missing functionality"
    url: "https://forum.getodk.org/c/features/9"
  - name: "Everything else"
    about: "For everything else"
    url: "https://forum.getodk.org/c/support/6"

================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!-- 

Thank you for taking the time to report an ODK Collect issue!

This space is for bugs that have clear reproduction steps and expected behavior. For unexpected behavior that is unclear how to address, general usage questions, form design questions, and to ask about the source code, please visit the ODK forum: https://forum.getodk.org

Before filling the template below, visit https://github.com/getodk/collect/issues?q=is%3Aissue and search to see whether your issue was already reported or fixed. If you find a match, comment on it or add a +1 rather than posting a new issue. If you find a problem you know how to fix, submit a pull request. 🎉

Feature suggestions should be described [in the forum Features category](https://forum.getodk.org/c/features) and discussed by the broader user community. Once there is a clear way forward, issues should be filed on the relevant repositories.

-->

#### ODK Collect version

#### Android version

#### Device used

#### Problem description

#### Steps to reproduce the problem

#### Expected behavior

#### Other information 

Things you tried, stack traces, related issues, suggestions on how to fix it...


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Closes #

<!-- 
Thank you for contributing to ODK Collect!

Before sending this PR, please read
https://github.com/getodk/collect/blob/master/docs/CONTRIBUTING.md
-->

#### Why is this the best possible solution? Were any other approaches considered?

#### How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

#### Do we need any specific form for testing your changes? If so, please attach one.

#### Does this change require updates to documentation? If so, please file an issue [here]( https://github.com/getodk/docs/issues/new) and include the link below.

#### Before submitting this PR, please make sure you have:
- [ ] added or modified tests for any new or changed behavior
- [ ] run `./gradlew connectedAndroidTest` (or `./gradlew testLab`) and confirmed all checks still pass
- [ ] added a comment above any new strings describing it for translators
- [ ] added any new strings with date formatting to `DateFormatsTest`
- [ ] verified that any code or assets from external sources are properly credited in comments and/or in the [about file](https://github.com/getodk/collect/blob/master/collect_app/src/main/assets/open_source_licenses.html).
- [ ] verified that any new UI elements use theme colors. [UI Components Style guidelines](https://github.com/getodk/collect/blob/master/docs/CODE-GUIDELINES.md#ui-components-style-guidelines)


================================================
FILE: .github/TESTING_RESULT_TEMPLATES.md
================================================
# Testing result templates

## Tested with success!
#### Verified on: [List of devices/os versions]
#### Verified cases: [optional]

***

## Bug[s] has[have] been found! / Regression[s] has[have] been found!

#### Verified on: [List of devices/os versions]

#### Problem visible on: [only if it's related to some specific devices otherwise it’s the same as above]

#### Steps to reproduce:

#### Current behavior:

#### Expected behavior:

#### Other information: [optional]


================================================
FILE: .gitignore
================================================
build
.gradle
.idea
.kotlin
local.properties
*.iml
.DS_Store
*.sublime-project

# emacs backup files
*.*~

# gradle env props
secrets.properties

# built application files
*.apk
*.ap_

# files for the Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Android Studio files
.externalNativeBuild/
.navigation/
captures/

# Visual Studio Code files
.project
.settings/
collect_app/.classpath
collect_app/.project
collect_app/.settings/

# Config for the official ODK Collect build
collect_app/src/odkCollectRelease/

# Files generated during CI runs
.circleci/collect_app_test_files.txt
.circleci/collect_app_test_classes.txt
.circleci/fork_test_classes.txt

# Robolectric dependencies
robolectric-deps/
**/robolectric-deps.properties

.local-m2
apks


================================================
FILE: .hgtags
================================================
5836a17a0e6f28b4e5b7a7abc9152446f4806ee2 v1.0.0
30d9314729db181177bb7209d1c16cd65a5095eb v1.1.0
827cf67bd902b80c37dce8d4ee8d2d29437408a5 v1.1.1
82798e410f5ab043721b3998e23861fd365a9801 v1.1.2
78fc6b2df0575ec79b94c0196babacbafcb7f958 v1.1.3
c6308d8be8cd99d060a06f3b10c87f5722776098 v1.1.4
f85cab690aa86dc86c2d53f12def22f16d9c0c5b v1.1.7-beta1
165ee1feda811cccefda77ae83896b7cb3209b6c v1.1.7-rc1
0c06023f4bae172a79a5aad27ca8d66798f2109e v1.1.7-rc2
caeb88584771e1e569c87eed7cca90738c867189 v1.1.7
96568099c2ec1408508178568fc5ca2503ec670b v1.2 RC1
96568099c2ec1408508178568fc5ca2503ec670b v1.2 RC1
15185704d55c220b02abcf5de6170a106f387f5b v1.2 RC1
88476e4dc9845a0a276bb57f93911d8aacc68912 v1.2.0
88476e4dc9845a0a276bb57f93911d8aacc68912 v1.2.0
ccb4a2556950af32ac153c26ca1f71faebbf8a9b v1.2.0
ccb4a2556950af32ac153c26ca1f71faebbf8a9b v1.2.0
2a9b44755f0a5af2558b7e22ac9948377b6e9597 v1.2.0
2a9b44755f0a5af2558b7e22ac9948377b6e9597 v1.2.0
a5faa6055d4bdbc5db786673c28d9872142120c7 v1.2.0
a5faa6055d4bdbc5db786673c28d9872142120c7 v1.2.0
0000000000000000000000000000000000000000 v1.2.0
b0ac9ab2b5bccea1b160e774b28a1f0c8af9a9e8 v1.2.0 rev 1012
3e7860308f3d7520ff91b8fb27bc5123450cfaa4 v1.2.0 rev 1013
3e7860308f3d7520ff91b8fb27bc5123450cfaa4 v1.2.0 rev 1013
b7d1fccb1a29ae62185bef1a123e80dbcdbc171c v1.2.0 rev 1013
29d29a54a208785e93d8ed2024e2222115ede489 v1.2.0 rev 1014
29d29a54a208785e93d8ed2024e2222115ede489 v1.2.0 rev 1014
0000000000000000000000000000000000000000 v1.2.0 rev 1014
abbf6ad98f25f0f33216ed11125a3a9cee8f90bc v1.2.1 rev 1014
6b017ddf90f21ab24a9b0f219657d48b1bdfc204 v1.2.1 rev 1015
fbc9d90492a631209d8587d299d08b0d005c681a v1.2.1 rev 1016
fd9ea977734c1bdbb37f40217becb4ec50d356d2 v1.2.1 rev 1017
b25021b3a495e039ef4a2a932a95df705648dc3c v1.2.0 rev 1010 prerelease
797ac8701d2c93b13c5cc585d39ff0a1a74d70d2 v1.2.0 rev 1011 prerelease
6e3dcf4780ac5e8a62b8d92f4111638cbc9a53e9 v1.2.0 rev 1009 prerelease
dd3c2816eb879b2b922d2e4c52bc95c8996a8f25 v1.2.0 rev 1008 RC2
06063863a95919cd18dc36841febbf21ca0fa60e v1.2.0 rev 1008 RC1
7f9a9e162ff5de00b4384de5a6bd7b0132ad1e9c v1.2.0 rev 1007 beta
a5a35a6eaf724a9c080a8ab85a2190f8fa6470fa v1.2.0 rev 1006 beta
eca30a5719a2d603c364d470bedfbd7c90c89e35 v1.2.0 rev 1005 beta
820c7e389d341953d0158290f880c9226d144870 v1.2.0 rev 1004 alpha
5630fb8134d1e8169517b5586b05cc4183370e56 v1.2.0 rev 1003 alpha
f628ef1bc45293e3d5fea77ac881a7b7652af554 v1.2.0 rev 1001 alpha
8c5544b1b0f4d469f35832c730d02a3bfbdb21ea v1.2.0 rev 1000 alpha
7f9a9e162ff5de00b4384de5a6bd7b0132ad1e9c v1.2.0 rev 1007 RC1
7f9a9e162ff5de00b4384de5a6bd7b0132ad1e9c v1.2.0 rev 1007 beta
0000000000000000000000000000000000000000 v1.2.0 rev 1007 beta
a5a35a6eaf724a9c080a8ab85a2190f8fa6470fa v1.2.0 rev 1006 RC1
a5a35a6eaf724a9c080a8ab85a2190f8fa6470fa v1.2.0 rev 1006 beta
0000000000000000000000000000000000000000 v1.2.0 rev 1006 beta
eca30a5719a2d603c364d470bedfbd7c90c89e35 v1.2.0 rev 1005 RC1
eca30a5719a2d603c364d470bedfbd7c90c89e35 v1.2.0 rev 1005 beta
0000000000000000000000000000000000000000 v1.2.0 rev 1005 beta
820c7e389d341953d0158290f880c9226d144870 v1.2.0 rev 1004 RC1
820c7e389d341953d0158290f880c9226d144870 v1.2.0 rev 1004 alpha
0000000000000000000000000000000000000000 v1.2.0 rev 1004 alpha
5630fb8134d1e8169517b5586b05cc4183370e56 v1.2.0 rev 1003 RC1
5630fb8134d1e8169517b5586b05cc4183370e56 v1.2.0 rev 1003 alpha
0000000000000000000000000000000000000000 v1.2.0 rev 1003 alpha
f628ef1bc45293e3d5fea77ac881a7b7652af554 v1.2.0 rev 1001 RC1
f628ef1bc45293e3d5fea77ac881a7b7652af554 v1.2.0 rev 1001 alpha
0000000000000000000000000000000000000000 v1.2.0 rev 1001 alpha
8c5544b1b0f4d469f35832c730d02a3bfbdb21ea v1.2.0 rev 1000 RC1
8c5544b1b0f4d469f35832c730d02a3bfbdb21ea v1.2.0 rev 1000 alpha
0000000000000000000000000000000000000000 v1.2.0 rev 1000 alpha
7be1f7e0a0dc36b67f8a584c7f420c240eefd5c6 v1.2.1 rev 1018 (plus swahili)
c11fe1aebaca2e213f71e61ad2337791d02723e0 v1.2.1 rev 1019
64e490522c2ef5ebc9af8a1a2c0dbf78bb213c06 v1.2.1 rev 1020
ea230f4ee12c303640c30090c30a9ac386324d5a v1.2.2 rev 1021
ea230f4ee12c303640c30090c30a9ac386324d5a v1.2.2 rev 1021
3b8a3847d1bea472176a27548d602b119d0e695d v1.2.2 rev 1021
3b8a3847d1bea472176a27548d602b119d0e695d v1.2.2 rev 1021
f714913194222fb579c5ef6e59092c788eeea300 v1.2.2 rev 1021
1759bdc402730ed7a16d26e7aba44aa43f822355 v1.2.2 rev 1023
cef8219f74248bd4d295e5c105b9f0ced3ac7f8d v1.3 rev 1025
a3d74ab96cdee3e972f7e507776a3834f497fbe0 v1.3 rev 1027
5c2ce96c94c6daf5277befaabf54ab74f088437b v1.3 rev 1029
1c8b890c69fbccc47de596c8592d21c7439646ba v1.3 rev 1030
e1e6c70eef9913497c65de897e229a6e0d871ad8 v1.4 rev 1033
68616e24e60d963334c762daba5784c7af763d76 v1.4 rev 1034
aa63d3a1f3295cf5a4a6bc74d8f1a4d4939fdd8b v1.4 rev 1035
db03f3497da8c76883e475a14a2b034e61e29c37 v1.4 rev 1036
db03f3497da8c76883e475a14a2b034e61e29c37 v1.4 rev 1036
8f77433258b376de5a6a7267df03ecc7cdecc1a4 v1.4 rev 1036
86afc4615411eaeee61271790b2bae5de7b94176 v1.4 rev 1037
3254b74a70d9c4f4088ba710fd6d7f542ffe166f v1.4 rev 1038
bc69898dc4ccb061079ee82f9b52da34de8400b7 v1.4.3 rev 1040
cd78ad21a3c8b1f106cdbb35a55ddfd1c2cf021f v1.4.3 rev 1041
7bf86c85d2dac5d6353bf2007a5c817654bbfdfc v1.4.3 rev 1042
753b33ca1fa800b517fcb6156d55370b986cedeb v1.4.4 rev 1044
753b33ca1fa800b517fcb6156d55370b986cedeb v1.4.4 rev 1044
c0d79cc86e2da93dfb03165a520de2c42b5cf061 v1.4.4 rev 1044
72d2e66877f36e0d3b607a6dbc4207c96dcc4c0c v1.4.4 rev 1045
712f8174b16bd95ece6bac433f871a19d59ea46c v1.4.4 rev 1046
5a92ad65ed775aa744b0abfe1aaa3ef756bd82f3 v1.4.5 rev 1048
5a92ad65ed775aa744b0abfe1aaa3ef756bd82f3 v1.4.5 rev 1048
1a6028ae2ce23b2eb50bd7ee3b2674effd2620af v1.4.5 rev 1048
aacc424db2a79c201abd6dcb481af830d017477f v1.4.6 rev 1049 for testing
aacc424db2a79c201abd6dcb481af830d017477f v1.4.6 rev 1049 for testing
1fced08f31e9e4f10fcdf067debdbad3557899de v1.4.6 rev 1049 for testing


================================================
FILE: LICENSE.md
================================================
Apache License
==============

_Version 2.0, January 2004_  
_&lt;<http://www.apache.org/licenses/>&gt;_

### Terms and Conditions for use, reproduction, and distribution

#### 1. Definitions

“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.

“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.

“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.

“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.

“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.

“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.

“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).

“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.

“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”

“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.

#### 2. Grant of Copyright License

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.

#### 3. Grant of Patent License

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.

#### 4. Redistribution

You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:

* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.

You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.

#### 5. Submission of Contributions

Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.

#### 6. Trademarks

This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

#### 7. Disclaimer of Warranty

Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.

#### 8. Limitation of Liability

In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.

#### 9. Accepting Warranty or Additional Liability

While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

_END OF TERMS AND CONDITIONS_

### APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.

    Copyright [yyyy] [name of copyright owner]
    
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    
      http://www.apache.org/licenses/LICENSE-2.0
    
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.


================================================
FILE: README.md
================================================
# ODK Collect

![Platform](https://img.shields.io/badge/platform-Android-blue.svg)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Build status](https://circleci.com/gh/getodk/collect.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/getodk/collect)
[![Slack](https://img.shields.io/badge/chat-on%20slack-brightgreen)](https://slack.getodk.org)

ODK Collect is an Android app for filling out forms. It is designed to be used in resource-constrained environments with challenges such as unreliable connectivity or power infrastructure. ODK Collect is part the ODK project, a free and open-source set of tools which help organizations author, field, and manage mobile data collection solutions. Learn more about ODK and its history [here](https://getodk.org/) and read about example ODK deployments [here](https://forum.getodk.org/c/showcase).

ODK Collect renders forms that are compliant with the [ODK XForms standard](https://getodk.github.io/xforms-spec/), a subset of the [XForms 1.1 standard](https://www.w3.org/TR/xforms/) with some extensions. The form parsing is done by the [JavaRosa library](https://github.com/getodk/javarosa) which Collect includes as a dependency.

Please note that the `master` branch reflects ongoing development and is not production-ready.

## Table of Contents
* [Learn more about ODK Collect](#learn-more-about-odk-collect)
* [Release cycle](#release-cycle)
* [Downloading builds](#downloading-builds)
* [Suggesting new features](#suggesting-new-features)
* Contributing
  * [Contributing code](#contributing-code)
  * [Contributing translations](#contributing-translations)
* Developing
  * [Setting up your development environment](#setting-up-your-development-environment)
  * [Testing a form without a server](#testing-a-form-without-a-server)
  * [Using APIs for local development](#using-apis-for-local-development)
  * [Debugging JavaRosa](#debugging-javarosa)
  * [Troubleshooting](#troubleshooting)
  * [Test devices](#test-devices)
* [Creating signed releases for Google Play Store](#creating-signed-releases-for-google-play-store)

## Learn more about ODK Collect
* ODK website: [https://getodk.org](https://getodk.org)
* ODK Collect usage documentation: [https://docs.getodk.org/collect-intro/](https://docs.getodk.org/collect-intro/)
* ODK forum: [https://forum.getodk.org](https://forum.getodk.org)
* ODK developer Slack chat: [https://slack.getodk.org](https://slack.getodk.org)

## Release cycle

The work to be done is continuously revised and prioritized in [the backlog](https://github.com/orgs/getodk/projects/9/views/8) by the Collect team. The majority of this is influenced by the priorities in [the ODK roadmap](https://getodk.org/roadmap). Releases are planned to happen every 2-3 months (resulting in ~4 releases a year). This goal is to balance the pace of delivery with keeping things stable for users while also minimizing the risk in each release.

Sometimes issues will be assigned to core team members before they are actually started (moved to "in progress") to make it clear who's going to be working on what.

Once the majority of high risk or visible work is done for a release, a new beta will then be released to the Play Store by [@lognaturel](https://github.com/lognaturel) and that will be used for regression testing by [@getodk/testers](https://github.com/orgs/getodk/teams/testers). If any problems are found, the release is blocked until we can merge fixes. Regression testing should continue on the original beta build (rather than a new one with fixes) unless problems block the rest of testing. Once the process is complete, [@lognaturel](https://github.com/lognaturel) pushes the releases to the Play Store following [these instructions](#creating-signed-releases-for-google-play-store).

Fixes to a previous release should be merged to a "release" branch (`v2023.2.x` for example) so as to leave `master` available for the current release's work. If hotfix changes are needed in the current release as well then these can be merged in as a PR after hotfix releases (generally easiest as a single PR for the whole hotfix release). This approach can also be used if work for the next release starts before the current one is out - the next release continues on `master` while the release is on a release branch.

At the beginning of each release cycle, [@grzesiek2010](https://github.com/grzesiek2010) updates all dependencies that have compatible upgrades available and ensures that the build targets the latest SDK.

## Downloading builds
Per-commit debug builds can be found on [CircleCI](https://circleci.com/gh/getodk/collect). Login with your GitHub account, click the build you'd like, then find the APK in the Artifacts tab.

If you are looking to use ODK Collect, we strongly recommend using the [Play Store build](https://play.google.com/store/apps/details?id=org.odk.collect.android). Current and previous production builds can be found in [Releases](https://github.com/getodk/collect/releases).

## Suggesting new features
We try to make sure that all issues in the issue tracker are as close to fully specified as possible so that they can be closed by a pull request. Feature suggestions should be described [in the forum Features category](https://forum.getodk.org/c/features) and discussed by the broader user community. Once there is a clear way forward, issues should be filed on the relevant repositories. More controversial features will be discussed as part of the Technical Steering Committee's [roadmapping process](https://github.com/getodk/governance/blob/master/TSC-1/STANDARD-OPERATING-PROCEDURES.md#roadmap).

## Contributing code
Any and all contributions to the project are welcome. ODK Collect is used across the world primarily by organizations with a social purpose so you can have real impact!

Issues tagged as [good first issue](https://github.com/getodk/collect/labels/good%20first%20issue) should be a good place to start. There are also currently many issues tagged as [needs reproduction](https://github.com/getodk/collect/labels/needs%20reproduction) which need someone to try to reproduce them with the current version of ODK Collect and comment on the issue with their findings.

If you're ready to contribute code, see [the contribution guide](docs/CONTRIBUTING.md).

## Contributing translations
If you know a language other than English, consider contributing translations through [Transifex](https://explore.transifex.com/getodk/collect/).

Translations are updated right before the first beta for a release and before the release itself. To update translations, download the zip from https://explore.transifex.com/getodk/collect/. The contents of each folder then need to be moved to the Android project folders. A quick script like [the one in this gist](https://gist.github.com/lognaturel/9974fab4e7579fac034511cd4944176b) can help. We currently copy everything from Transifex to minimize manual intervention. Sometimes translation files will only get comment changes. When new languages are updated in Transifex, they need to be added to the script above. Additionally, `ApplicationConstants.TRANSLATIONS_AVAILABLE` needs to be updated. This array provides the choices for the language preference in settings. Ideally the list could be dynamically generated.

## Setting up your development environment

1. Download and install [Git](https://git-scm.com/downloads) and add it to your PATH

1. Download and install [Android Studio](https://developer.android.com/studio/index.html) 

1. Fork the collect project ([why and how to fork](https://help.github.com/articles/fork-a-repo/))

1. Clone your fork of the project locally. At the command line:

        git clone https://github.com/YOUR-GITHUB-USERNAME/collect

    If you prefer not to use the command line, you can use Android Studio to create a new project from version control using `https://github.com/YOUR-GITHUB-USERNAME/collect`.

1. Use Android Studio to import the project from its Gradle settings. To run the project, click on the green arrow at the top of the screen.

1. Windows developers: continue configuring Android Studio with the steps in this document: [Developing ODK Collect on Windows](docs/WINDOWS-DEV-SETUP.md).

1. Make sure you can run unit tests by running everything under `collect_app/src/test/java` in Android Studio or on the command line:

    ```
    ./gradlew testDebug
    ```

1. Make sure you can run instrumented tests by running everything under `collect_app/src/androidTest/java` in Android Studio or on the command line:

    ```
    ./gradlew connectedAndroidTest
    ```
    **Note:** You can see the emulator setup used on CI in  `.circleci/config.yml`.

## Customizing the development environment

### Changing JVM heap size

You can customize the heap size that is used for compiling and running tests. Increasing these will most likely speed up compilation and tests on your local machine. The default values are specified in the project's `gradle.properties` and this can be overriden by your user level `gradle.properties` (found in your `GRADLE_USER_HOME` directory). An example `gradle.properties` that would give you a heap size of 4GB (rather than the default 1GB) would look like:

```
org.gradle.jvmargs=-Xmx4096m
```

## Testing a form without a server
When you first run Collect, it is set to download forms from [https://demo.getodk.org/](https://demo.getodk.org/), the demo server. You can sometimes verify your changes with those forms but it can also be helpful to put a specific test form on your device. Here are some options for that:

1. The `All question types` form from the default server is [here](https://docs.google.com/spreadsheets/d/1af_Sl8A_L8_EULbhRLHVl8OclCfco09Hq2tqb9CslwQ/edit#gid=0). You can also try [example forms](https://github.com/XLSForm/example-forms) and [test forms](https://github.com/XLSForm/test-forms) or [make your own](https://xlsform.org).

1. Convert the XLSForm (xlsx) to XForm (xml). Use the [ODK website](http://getodk.org/xlsform/) or [XLSForm Offline](https://gumroad.com/l/xlsform-offline) or [pyxform](https://github.com/XLSForm/pyxform).

1. Once you have the XForm, use [adb](https://developer.android.com/studio/command-line/adb.html) to push the form to your device (after [enabling USB debugging](https://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htm)) or emulator.
	```
	adb push my_form.xml /sdcard/Android/data/org.odk.collect.android/files/projects/{project-id}/forms
	```

If you are using the demo project, kindly replace `{project_id}` with `DEMO`

4. Launch ODK Collect and tap `+ Start new form`. The new form will be there.

More information about using Android Debug Bridge with Collect can be found [here](https://docs.getodk.org/collect-adb/).

## Using APIs for local development

Certain functions in ODK Collect depend on cloud services that require API keys or authorization steps to work.  Here are the steps you need to take in order to use these functions in your development builds.

**Google Maps API**: When the "Google Maps SDK" option is selected in the "User interface" settings, ODK Collect uses the Google Maps API for displaying maps in the geospatial question types (GeoPoint, GeoTrace, and GeoShape).  To enable this API:
  1. [Get a Google Maps API key](https://developers.google.com/maps/documentation/android-api/signup).  Note that this requires a credit card number, though the card will not be charged immediately; some free API usage is permitted.  You should carefully read the terms before providing a credit card number.
  1. Edit or create `secrets.properties` and set the `GOOGLE_MAPS_API_KEY` property to your API key.  You should end up with a line that looks like this:
    ```
    GOOGLE_MAPS_API_KEY=AIbzvW8e0ub...
    ```

**Mapbox Maps SDK for Android**: When the "Mapbox SDK" option is selected in the "User interface" settings, ODK Collect uses the Mapbox SDK for displaying maps in the geospatial question types (GeoPoint, GeoTrace, and GeoShape).  To enable this API:
  1. [Create a Mapbox account](https://www.mapbox.com/signup/).  Note that signing up with the "Pay-As-You-Go" plan does not require a credit card.  Mapbox provides free API usage up to the monthly thresholds documented at [https://www.mapbox.com/pricing](https://www.mapbox.com/pricing).  If your usage exceeds these thresholds, you will receive e-mail with instructions on how to add a credit card for payment; services will remain live until the end of the 30-day billing term, after which the account will be deactivated and will require a credit card to reactivate.
  2. Find your access token on your [account page](https://account.mapbox.com/) - it should be in "Tokens" as "Default public token".
  3. Edit or create `secrets.properties` and set the `MAPBOX_ACCESS_TOKEN` property to your access token.  You should end up with a line that looks like this:
    ```
    MAPBOX_ACCESS_TOKEN=pk.eyJk3bumVp4i...
    ```
  4. Create a new secret token with the "DOWNLOADS:READ" secret scope and then add it to `secrets.properties` as `MAPBOX_DOWNLOADS_TOKEN`.

*Note: Mapbox will not be available as an option in compiled versions of Collect unless you follow the steps above. Mapbox will also not be available on x86 devices as the native libraries are excluded to reduce the APK size. If you need to use an x86 device, you can force the build to include x86 libs by include the `x86Libs` Gradle parameter. For example, to build a debug APK with x86 libs: `./gradlew assembleDebug -Px86Libs`.*

## Debugging JavaRosa

JavaRosa is the form engine that powers Collect. If you want to debug or change that code while running Collect you can deploy it locally with Maven (you'll need `mvn` and `sed` installed):

1. Build and install your changes of JavaRosa (into your local Maven repo):

```bash
./gradlew publishToMavenLocal
```

1. Change `const val javarosa = javarosa_online` in `Dependencies.kt` to `const val javarosa = javarosa_local`

## Troubleshooting

#### Error when running Robolectric tests from Android Studio on macOS: `build/intermediates/bundles/debug/AndroidManifest.xml (No such file or directory)`
> Configure the default JUnit test runner configuration in order to work around a bug where IntelliJ / Android Studio does not set the working directory to the module being tested. This can be accomplished by editing the run configurations, Defaults -> JUnit and changing the working directory value to $MODULE_DIR$.

> Source: [Robolectric Wiki](https://github.com/robolectric/robolectric/wiki/Running-tests-in-Android-Studio#notes-for-mac).

#### Android Studio Error: `SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.`
When cloning the project from Android Studio, click "No" when prompted to open the `build.gradle` file and then open project.

#### Execution failed for task ':collect_app:transformClassesWithInstantRunForDebug'.

We have seen this problem happen in both IntelliJ IDEA and Android Studio, and believe it to be due to a bug in the IDE, which we can't fix.  As a workaround, turning off [Instant Run](https://developer.android.com/studio/run/#set-up-ir) will usually avoid this problem. The problem is fixed in Android Studio 3.5 with the new [Apply Changes](https://medium.com/androiddevelopers/android-studio-project-marble-apply-changes-e3048662e8cd) feature.

#### Moving to the main view if user minimizes the app
If you build the app on your own using Android Studio `(Build -> Build APK)` and then install it (from an `.apk` file), you might notice this strange behaviour thoroughly described: [#1280](https://github.com/getodk/collect/issues/1280) and [#1142](https://github.com/getodk/collect/issues/1142).

This problem occurs building other apps as well.

#### gradlew Failure: `FAILURE: Build failed with an exception.`

If you encounter an error similar to this when running `gradlew`:

```
FAILURE: Build failed with an exception

What went wrong:
A problem occurred configuring project ':collect_app'.
> Failed to notify project evaluation listener.
   > Could not initialize class com.android.sdklib.repository.AndroidSdkHandler
```

You may have a mismatch between the embedded Android SDK Java and the JDK installed on your machine. You may wish to set your **JAVA_HOME** environment variable to that SDK. For example, on macOS:

`export JAVA_HOME="/Applications/Android\ Studio.app/Contents/jre/Contents/Home/"
`

Note that this change might cause problems with other Java-based applications (e.g., if you uninstall Android Studio).

#### gradlew Failure: `java.lang.NullPointerException (no error message).`
If you encounter the `java.lang.NullPointerException (no error message).` when running `gradlew`, please make sure your Java version for this project is Java 17.

This can be configured under **File > Project Structure** in Android Studio, or by editing `$USER_HOME/.gradle/gradle.properties` to set `org.gradle.java.home=(path to JDK home)` for command-line use.

#### `Unable to resolve artifact: Missing` while running tests

This is encountered when Robolectric has problems downloading the jars it needs for different Android SDK levels. If you keep running into this you can download the JARs locally and point Robolectric to them by doing:

```
./download-robolectric-deps.sh
```

## Test devices

Devices that @getodk/testers have available for testing are as follows:

* Xiaomi Redmi 9T 4GB - Android 10
* Pixel 7a 8GB - Android 14
* LG Nexus 5X 2GB - Android 8.1
* Samsung Galaxy M12 4GB - Android 11
* Samsung Galaxy M23 4GB - Android 14
* Xiaomi Redmi 7 3GB - Android 10
* Pixel 6a 6GB - Android 13
* Pixel 3a 4GB - Android 12
* Huawei Y560-L01 1GB - Android 5.1

## Creating signed releases for Google Play Store
Maintainers keep a folder with a clean checkout of the code and use [jenv.be](https://www.jenv.be) in that folder to ensure compilation with Java 17.

### Release prerequisites:

- a`local.properties` file in the root folder with the following:
  ```
  sdk.dir=/path/to/android/sdk
  ```

- the keystore file and passwords

- a `secrets.properties` file in the root project folder folder with the following:
  ```
  // secrets.properties
  RELEASE_STORE_FILE=/path/to/collect.keystore
  RELEASE_STORE_PASSWORD=secure-store-password
  RELEASE_KEY_ALIAS=key-alias
  RELEASE_KEY_PASSWORD=secure-alias-password
  ```

- a `google-services.json` file in the `collect_app/src/odkCollectRelease` folder. The contents of the file are similar to the contents of `collect_app/src/google-services.json`.

### Release checklist:

- update translations
- make sure CI is green for the chosen commit
- run `./gradlew releaseCheck`. If successful, a signed release will be at `collect_app/build/outputs/apk` (with an old version name)
- verify a basic "happy path": scan a QR code to configure a new project, get a blank form, fill it, open the form map (confirms that the Google Maps key is correct), send form
- run `./benchmark.sh` with a real device connected to verify performance
  - To run benchmarks a project will need to be set up in Central with the benchmark forms and app users. The forms and entities needed for that are available [here](https://drive.google.com/drive/folders/1dPLvDY0LhVX-5qTUEs6EDoraDnLpUS0g?usp=drive_link).
- verify new APK can be installed as update to previous version and that above "happy path" works in that case also
- create and publish scheduled forum post with release description
- write Play Store release notes, include link to forum post
- when creating a major release:
  - Tag the commit for the release (`vX.X.0`)
  - Run `./create-release.sh <last release version code> <release tag>`
- when creating a patch release:
  - Tag the commit for the patch release (`vX.X.X`)
  - (If beta has started for next release) Tag the commit for the beta release (`vX.X.X-beta.X`)
  - Run `./create-release.sh <last release version code> <patch release tag> <beta release tag>`
- when creating a beta release:
  - Tag the commit for the beta release (`vX.X.X-beta.X`)
  - Run `./create-release.sh <last release version code> <beta release tag>`
- add a release to Github [here](https://github.com/getodk/collect/releases), generate release notes and attach the APK
- upload APK(s) to Play Store
  - When creating a hotfix, the beta APK should be uploaded second as it will have a higher version code
- backup dependencies for the release by downloading the `vX.X.X.tar` artifact from the `create_dependency_backup` job on Circle CI (for the release commit) and then uploading it to [this folder](https://drive.google.com/drive/folders/1_tMKBFLdhzFZF9GKNeob4FbARjdfbtJu?usp=share_link)
- backup a self signed release APK by downloading the `selfSignedRelease.apk` from the `build_release` job on Circle CI (for the release commit) and then upload to [this folder](https://drive.google.com/drive/folders/1pbbeNaMTziFhtZmedOs0If3BeYu3Ex5x?usp=share_link)

## Compiling a previous release using backed-up dependencies

1. Download the `.tar` for relevant release tag
2. Extract `.local-m2` into the project directory:
    ```bash
    tar -xf maven.tar -C <collect project directory>
    ```
   
The project will now be able to fetch dependencies that are no longer available (but were used to compile the release) from the `.local-m2` Maven repo.



================================================
FILE: SECURITY.md
================================================
# Security Policy

## Reporting a Vulnerability

See our [Vulnerability Disclosure Policy](https://getodk.org/vdp).


================================================
FILE: analytics/.gitignore
================================================
/build


================================================
FILE: analytics/build.gradle.kts
================================================
plugins {
    alias(libs.plugins.androidLibrary)
}

apply(from = "../config/quality.gradle")

android {
    compileSdk = libs.versions.compileSdk.get().toInt()

    defaultConfig {
        minSdk = libs.versions.minSdk.get().toInt()

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    namespace = "org.odk.collect.analytics"
}

dependencies {
    implementation(libs.kotlinStdlib)
    implementation(libs.androidxCoreKtx)
    implementation(libs.firebaseCrashlytics)
    implementation(libs.firebaseAnalytics)
}


================================================
FILE: analytics/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile


================================================
FILE: analytics/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>


================================================
FILE: analytics/src/main/java/org/odk/collect/analytics/Analytics.kt
================================================
package org.odk.collect.analytics

interface Analytics {
    fun logEvent(event: String)
    fun logEventWithParam(event: String, key: String, value: String)
    fun logNonFatal(throwable: Throwable)
    fun logMessage(message: String)
    fun setAnalyticsCollectionEnabled(isAnalyticsEnabled: Boolean)
    fun setUserProperty(name: String, value: String)

    companion object {
        private var instance: Analytics = NoopAnalytics()
        private val params = mutableMapOf<String, String>()

        fun setInstance(analytics: Analytics) {
            this.instance = analytics
        }

        @JvmStatic
        fun log(event: String) {
            instance.logEvent(event)
        }

        @JvmStatic
        fun log(event: String, key: String) {
            val paramValue = params[key]

            if (paramValue != null) {
                log(event, key, paramValue)
            } else {
                log(event)
            }
        }

        @JvmStatic
        fun log(event: String, key: String, value: String) {
            instance.logEventWithParam(event, key, value)
        }

        @JvmStatic
        fun setParam(key: String, value: String) {
            params[key] = value
        }

        @JvmStatic
        fun getParamValue(key: String): String? {
            return params[key]
        }

        fun setUserProperty(name: String, value: String) {
            instance.setUserProperty(name, value)
        }

        fun logNonFatal(throwable: Throwable) {
            instance.logNonFatal(throwable)
        }
    }
}


================================================
FILE: analytics/src/main/java/org/odk/collect/analytics/BlockableFirebaseAnalytics.kt
================================================
package org.odk.collect.analytics

import android.app.Application
import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics

class BlockableFirebaseAnalytics(application: Application) : Analytics {
    private val firebaseAnalytics = FirebaseAnalytics.getInstance(application)
    private val crashlytics = FirebaseCrashlytics.getInstance()

    override fun logEvent(event: String) {
        firebaseAnalytics.logEvent(event, null)
    }

    override fun logEventWithParam(event: String, key: String, value: String) {
        val bundle = Bundle()
        bundle.putString(key, value)
        firebaseAnalytics.logEvent(event, bundle)
    }

    override fun logNonFatal(throwable: Throwable) {
        crashlytics.recordException(throwable)
    }

    override fun logMessage(message: String) {
        crashlytics.log(message)
    }

    override fun setAnalyticsCollectionEnabled(isAnalyticsEnabled: Boolean) {
        firebaseAnalytics.setAnalyticsCollectionEnabled(isAnalyticsEnabled)
        crashlytics.setCrashlyticsCollectionEnabled(isAnalyticsEnabled)
    }

    override fun setUserProperty(name: String, value: String) {
        firebaseAnalytics.setUserProperty(name, value)
    }
}


================================================
FILE: analytics/src/main/java/org/odk/collect/analytics/NoopAnalytics.kt
================================================
package org.odk.collect.analytics

class NoopAnalytics : Analytics {
    override fun logEvent(event: String) {}
    override fun logEventWithParam(event: String, key: String, value: String) {}
    override fun logNonFatal(throwable: Throwable) {}
    override fun logMessage(message: String) {}
    override fun setAnalyticsCollectionEnabled(isAnalyticsEnabled: Boolean) {}
    override fun setUserProperty(name: String, value: String) {}
}


================================================
FILE: androidshared/.gitignore
================================================
/build


================================================
FILE: androidshared/build.gradle.kts
================================================
plugins {
    alias(libs.plugins.androidLibrary)
    alias(libs.plugins.kotlinKsp)
    alias(libs.plugins.composeCompiler)
}

apply(from = "../config/quality.gradle")

android {
    compileSdk = libs.versions.compileSdk.get().toInt()

    buildFeatures {
        viewBinding = true
        compose = true
    }

    defaultConfig {
        minSdk = libs.versions.minSdk.get().toInt()

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
        }
    }

    compileOptions {
        isCoreLibraryDesugaringEnabled = true
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    testOptions {
        unitTests.isIncludeAndroidResources = true
    }
    namespace = "org.odk.collect.androidshared"
}

dependencies {
    coreLibraryDesugaring(libs.desugar)

    implementation(project(":icons"))
    implementation(project(":strings"))
    implementation(project(":shared"))
    implementation(project(":async"))
    implementation(libs.kotlinStdlib)
    implementation(libs.androidxCoreKtx)
    implementation(libs.androidxLifecycleLivedataKtx)
    implementation(libs.androidMaterial)
    implementation(libs.androidxFragmentKtx)
    implementation(libs.androidxPreferenceKtx)
    implementation(libs.timber)
    implementation(libs.androidxExinterface)
    implementation(libs.playServicesLocation)

    val composeBom = platform(libs.androidxComposeBom)
    implementation(composeBom)
    implementation(libs.androidXComposeMaterial)

    testImplementation(project(":test-shared"))
    testImplementation(project(":androidtest"))
    testImplementation(libs.junit)
    testImplementation(libs.androidxTestExtJunit)
    testImplementation(libs.androidxTestEspressoCore)
    testImplementation(libs.robolectric)
    testImplementation(libs.mockitoKotlin)
    testImplementation(libs.androidxArchCoreTesting)

    androidTestImplementation(libs.androidxTestExtJunit)
    androidTestImplementation(libs.junit)

    debugImplementation(project(":fragments-test"))
}


================================================
FILE: androidshared/src/androidTest/java/org/odk/collect/androidshared/bitmap/ImageCompressorTest.kt
================================================
/*
 * Copyright 2017 Nafundi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.odk.collect.androidshared.bitmap

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.exifinterface.media.ExifInterface
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File

@RunWith(AndroidJUnit4::class)
class ImageCompressorTest {
    private lateinit var testImagePath: String
    private val imageCompressor = ImageCompressor

    @Test
    fun imageShouldNotBeChangedIfMaxPixelsIsZero() {
        saveTestBitmap(3000, 2000)
        imageCompressor.execute(testImagePath, 0)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(3000, equalTo(image.width))
        assertThat(2000, equalTo(image.height))
    }

    @Test
    fun imageShouldNotBeChangedIfMaxPixelsIsSmallerThanZero() {
        saveTestBitmap(3000, 2000)
        imageCompressor.execute(testImagePath, -10)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(3000, equalTo(image.width))
        assertThat(2000, equalTo(image.height))
    }

    @Test
    fun imageShouldNotBeChangedIfMaxPixelsIsNotSmallerThanTheEdgeWhenWidthIsBiggerThanHeight() {
        saveTestBitmap(3000, 2000)
        imageCompressor.execute(testImagePath, 3000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(3000, equalTo(image.width))
        assertThat(2000, equalTo(image.height))
    }

    @Test
    fun imageShouldNotBeChangedIfMaxPixelsIsNotSmallerThanTheLongEdgeWhenWidthIsSmallerThanHeight() {
        saveTestBitmap(2000, 3000)
        imageCompressor.execute(testImagePath, 4000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(2000, equalTo(image.width))
        assertThat(3000, equalTo(image.height))
    }

    @Test
    fun imageShouldNotBeChangedIfMaxPixelsIsNotSmallerThanTheLongEdgeWhenWidthEqualsHeight() {
        saveTestBitmap(3000, 3000)
        imageCompressor.execute(testImagePath, 3000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(3000, equalTo(image.width))
        assertThat(3000, equalTo(image.height))
    }

    @Test
    fun imageShouldBeCompressedIfMaxPixelsIsSmallerThanTheLongEdgeWhenWidthIsBiggerThanHeight() {
        saveTestBitmap(4000, 3000)
        imageCompressor.execute(testImagePath, 2000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(2000, equalTo(image.width))
        assertThat(1500, equalTo(image.height))
    }

    @Test
    fun imageShouldBeCompressedIfMaxPixelsIsSmallerThanTheLongEdgeWhenWidthIsSmallerThanHeight() {
        saveTestBitmap(3000, 4000)
        imageCompressor.execute(testImagePath, 2000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(1500, equalTo(image.width))
        assertThat(2000, equalTo(image.height))
    }

    @Test
    fun imageShouldBeCompressedIfMaxPixelsIsSmallerThanTheLongEdgeWhenWidthEqualsHeight() {
        saveTestBitmap(3000, 3000)
        imageCompressor.execute(testImagePath, 2000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(2000, equalTo(image.width))
        assertThat(2000, equalTo(image.height))
    }

    @Test
    fun keepExifAfterScaling() {
        val attributes = mutableMapOf(
            // supported exif tags
            ExifInterface.TAG_DATETIME to "2014:01:23 14:57:18",
            ExifInterface.TAG_DATETIME_ORIGINAL to "2014:01:23 14:57:18",
            ExifInterface.TAG_DATETIME_DIGITIZED to "2014:01:23 14:57:18",
            ExifInterface.TAG_OFFSET_TIME to "+1:00",
            ExifInterface.TAG_OFFSET_TIME_ORIGINAL to "+1:00",
            ExifInterface.TAG_OFFSET_TIME_DIGITIZED to "+1:00",
            ExifInterface.TAG_SUBSEC_TIME to "First photo",
            ExifInterface.TAG_SUBSEC_TIME_ORIGINAL to "0",
            ExifInterface.TAG_SUBSEC_TIME_DIGITIZED to "0",
            ExifInterface.TAG_IMAGE_DESCRIPTION to "Photo from Poland",
            ExifInterface.TAG_MAKE to "OLYMPUS IMAGING CORP",
            ExifInterface.TAG_MODEL to "STYLUS1",
            ExifInterface.TAG_SOFTWARE to "Version 1.0",
            ExifInterface.TAG_ARTIST to "Grzegorz",
            ExifInterface.TAG_COPYRIGHT to "G",
            ExifInterface.TAG_MAKER_NOTE to "OLYMPUS",
            ExifInterface.TAG_USER_COMMENT to "First photo",
            ExifInterface.TAG_IMAGE_UNIQUE_ID to "123456789",
            ExifInterface.TAG_CAMERA_OWNER_NAME to "John",
            ExifInterface.TAG_BODY_SERIAL_NUMBER to "987654321",
            ExifInterface.TAG_GPS_ALTITUDE to "41/1",
            ExifInterface.TAG_GPS_ALTITUDE_REF to "0",
            ExifInterface.TAG_GPS_DATESTAMP to "2014:01:23",
            ExifInterface.TAG_GPS_TIMESTAMP to "14:57:18",
            ExifInterface.TAG_GPS_LATITUDE to "50/1,49/1,8592/1000",
            ExifInterface.TAG_GPS_LATITUDE_REF to "N",
            ExifInterface.TAG_GPS_LONGITUDE to "0/1,8/1,12450/1000",
            ExifInterface.TAG_GPS_LONGITUDE_REF to "W",
            ExifInterface.TAG_GPS_SATELLITES to "8",
            ExifInterface.TAG_GPS_STATUS to "A",
            ExifInterface.TAG_ORIENTATION to "1",
            // unsupported exif tags
            ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH to "5",
            ExifInterface.TAG_DNG_VERSION to "100"
        )

        saveTestBitmap(3000, 4000, attributes)
        imageCompressor.execute(testImagePath, 2000)

        val exifData = ExifInterface(testImagePath)
        for (attributeName in attributes.keys) {
            if (attributeName == ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH ||
                attributeName == ExifInterface.TAG_DNG_VERSION
            ) {
                assertThat(exifData.getAttribute(attributeName), equalTo(null))
            } else {
                assertThat(exifData.getAttribute(attributeName), equalTo(attributes[attributeName]))
            }
        }
    }

    @Test
    fun verifyNoRotationAppliedForExifRotation() {
        val attributes = mapOf(ExifInterface.TAG_ORIENTATION to ExifInterface.ORIENTATION_ROTATE_90.toString())
        saveTestBitmap(3000, 4000, attributes)
        imageCompressor.execute(testImagePath, 4000)

        val image = ImageFileUtils.getBitmap(testImagePath, BitmapFactory.Options())!!

        assertThat(3000, equalTo(image.width))
        assertThat(4000, equalTo(image.height))
    }

    private fun saveTestBitmap(width: Int, height: Int, attributes: Map<String, String> = emptyMap()) {
        testImagePath = File.createTempFile("test", ".jpg").absolutePath

        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        ImageFileUtils.saveBitmapToFile(bitmap, testImagePath)
        val exifInterface = ExifInterface(testImagePath)
        for ((key, value) in attributes) {
            exifInterface.setAttribute(key, value)
        }
        exifInterface.saveAttributes()
    }
}


================================================
FILE: androidshared/src/androidTest/java/org/odk/collect/androidshared/bitmap/ImageFileUtilsTest.kt
================================================
/*
 * Copyright 2017 Nafundi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.odk.collect.androidshared.bitmap

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import androidx.exifinterface.media.ExifInterface
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import timber.log.Timber
import java.io.File
import java.io.IOException

@RunWith(AndroidJUnit4::class)
class ImageFileUtilsTest {

    private lateinit var sourceFile: File
    private lateinit var destinationFile: File
    private lateinit var attributes: MutableMap<String, String>

    @Before
    fun setup() {
        sourceFile = createTempImageFile("source")
        destinationFile = createTempImageFile("destination")
        attributes = HashMap()
    }

    @Test
    fun copyAndRotateImageNinety() {
        attributes[ExifInterface.TAG_ORIENTATION] = ExifInterface.ORIENTATION_ROTATE_90.toString()
        saveTestBitmapToFile(sourceFile.absolutePath, attributes)
        ImageFileUtils.copyImageAndApplyExifRotation(sourceFile, destinationFile)
        val image = ImageFileUtils.getBitmap(
            destinationFile.absolutePath,
            BitmapFactory.Options()
        )!!

        assertEquals(2, image.width)
        assertEquals(1, image.height)
        assertEquals(Color.GREEN, image.getPixel(0, 0))
        assertEquals(Color.RED, image.getPixel(1, 0))
        verifyNoExifOrientationInDestinationFile(destinationFile.absolutePath)
    }

    @Test
    fun copyAndRotateImageTwoSeventy() {
        attributes[ExifInterface.TAG_ORIENTATION] = ExifInterface.ORIENTATION_ROTATE_270.toString()
        saveTestBitmapToFile(sourceFile.absolutePath, attributes)
        ImageFileUtils.copyImageAndApplyExifRotation(sourceFile, destinationFile)
        val image = ImageFileUtils.getBitmap(
            destinationFile.absolutePath,
            BitmapFactory.Options()
        )!!

        assertEquals(2, image.width)
        assertEquals(1, image.height)
        assertEquals(Color.RED, image.getPixel(0, 0))
        assertEquals(Color.GREEN, image.getPixel(1, 0))
        verifyNoExifOrientationInDestinationFile(destinationFile.absolutePath)
    }

    @Test
    fun copyAndRotateImageOneEighty() {
        attributes[ExifInterface.TAG_ORIENTATION] = ExifInterface.ORIENTATION_ROTATE_180.toString()
        saveTestBitmapToFile(sourceFile.absolutePath, attributes)
        ImageFileUtils.copyImageAndApplyExifRotation(sourceFile, destinationFile)
        val image = ImageFileUtils.getBitmap(
            destinationFile.absolutePath,
            BitmapFactory.Options()
        )!!

        assertEquals(1, image.width)
        assertEquals(2, image.height)
        assertEquals(Color.GREEN, image.getPixel(0, 0))
        assertEquals(Color.RED, image.getPixel(0, 1))
        verifyNoExifOrientationInDestinationFile(destinationFile.absolutePath)
    }

    @Test
    fun copyAndRotateImageUndefined() {
        attributes[ExifInterface.TAG_ORIENTATION] = ExifInterface.ORIENTATION_UNDEFINED.toString()
        saveTestBitmapToFile(sourceFile.absolutePath, attributes)
        ImageFileUtils.copyImageAndApplyExifRotation(sourceFile, destinationFile)
        val image = ImageFileUtils.getBitmap(
            destinationFile.absolutePath,
            BitmapFactory.Options()
        )!!

        assertEquals(1, image.width)
        assertEquals(2, image.height)
        assertEquals(Color.RED, image.getPixel(0, 0))
        assertEquals(Color.GREEN, image.getPixel(0, 1))
        verifyNoExifOrientationInDestinationFile(destinationFile.absolutePath)
    }

    @Test
    fun copyAndRotateImageNoExif() {
        saveTestBitmapToFile(sourceFile.absolutePath, null)
        ImageFileUtils.copyImageAndApplyExifRotation(sourceFile, destinationFile)
        val image = ImageFileUtils.getBitmap(
            destinationFile.absolutePath,
            BitmapFactory.Options()
        )!!

        assertEquals(1, image.width)
        assertEquals(2, image.height)
        assertEquals(Color.RED, image.getPixel(0, 0))
        assertEquals(Color.GREEN, image.getPixel(0, 1))
        verifyNoExifOrientationInDestinationFile(destinationFile.absolutePath)
    }

    /**
     * These cases all have a window smaller than the image so the image should be scaled down.
     * Note that the scaling isn't exact -- the factor is the closest power of 2 to the exact one.
     */
    @Test
    fun scaleDownBitmapWhenNeeded() {
        runScaleTest(1000, 1000, 500, 500, 500, 500, false)
        runScaleTest(600, 800, 600, 200, 150, 200, false)
        runScaleTest(500, 400, 250, 200, 250, 200, false)
    }

    @Test
    fun doNotScaleDownBitmapWhenNotNeeded() {
        runScaleTest(1000, 1000, 2000, 2000, 1000, 1000, false)
        runScaleTest(600, 800, 600, 800, 600, 800, false)
        runScaleTest(500, 400, 600, 600, 500, 400, false)
        runScaleTest(2000, 800, 4000, 2000, 2000, 800, false)
    }

    @Test
    fun accuratelyScaleBitmapToDisplay() {
        runScaleTest(1000, 1000, 500, 500, 500, 500, true)
        runScaleTest(600, 800, 600, 200, 150, 200, true)
        runScaleTest(500, 400, 250, 200, 250, 200, true)
        runScaleTest(2000, 800, 300, 400, 300, 120, true)
        runScaleTest(1000, 1000, 2000, 2000, 2000, 2000, true)
        runScaleTest(600, 800, 600, 800, 600, 800, true)
        runScaleTest(500, 400, 600, 600, 600, 480, true)
        runScaleTest(2000, 800, 4000, 2000, 4000, 1600, true)
    }

    private fun runScaleTest(
        imageHeight: Int,
        imageWidth: Int,
        windowHeight: Int,
        windowWidth: Int,
        expectedHeight: Int,
        expectedWidth: Int,
        shouldScaleAccurately: Boolean
    ) {
        ScaleImageTest()
            .createBitmap(imageHeight, imageWidth)
            .scaleBitmapToDisplay(windowHeight, windowWidth, shouldScaleAccurately)
            .assertScaledBitmapDimensions(expectedHeight, expectedWidth)
    }

    private fun verifyNoExifOrientationInDestinationFile(destinationFilePath: String) {
        val exifData = getTestImageExif(destinationFilePath)
        if (exifData != null) {
            assertEquals(
                ExifInterface.ORIENTATION_UNDEFINED,
                exifData.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED
                )
            )
        }
    }

    private fun saveTestBitmapToFile(
        filePath: String,
        attributes: Map<String, String>?
    ) {
        val bitmap = Bitmap.createBitmap(1, 2, Bitmap.Config.ARGB_8888)
        bitmap.setPixel(0, 0, Color.RED)
        bitmap.setPixel(0, 1, Color.GREEN)

        ImageFileUtils.saveBitmapToFile(bitmap, filePath)
        if (attributes != null) {
            try {
                val exifInterface = ExifInterface(filePath)
                for (attributeName in attributes.keys) {
                    exifInterface.setAttribute(attributeName, attributes[attributeName])
                }
                exifInterface.saveAttributes()
            } catch (e: IOException) {
                Timber.w(e)
            }
        }
    }

    private fun getTestImageExif(imagePath: String): ExifInterface? {
        try {
            return ExifInterface(imagePath)
        } catch (e: Exception) {
            Timber.w(e)
        }
        return null
    }

    private fun createTempImageFile(imageName: String): File {
        val temp = File.createTempFile(imageName, ".png")
        temp.deleteOnExit()
        return temp
    }

    private class ScaleImageTest {
        private val cache = ApplicationProvider.getApplicationContext<Context>().externalCacheDir
        private val imageFile = File(cache, "testImage.jpeg")
        private var scaledBitmap: Bitmap? = null

        fun createBitmap(imageHeight: Int, imageWidth: Int): ScaleImageTest {
            val bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888)
            ImageFileUtils.saveBitmapToFile(bitmap, imageFile.absolutePath)
            return this
        }

        fun scaleBitmapToDisplay(
            windowHeight: Int,
            windowWidth: Int,
            shouldScaleAccurately: Boolean
        ): ScaleImageTest {
            scaledBitmap = ImageFileUtils.getBitmapScaledToDisplay(
                imageFile,
                windowHeight,
                windowWidth,
                shouldScaleAccurately
            )
            return this
        }

        fun assertScaledBitmapDimensions(expectedHeight: Int, expectedWidth: Int) {
            assertEquals(expectedHeight.toLong(), scaledBitmap!!.height.toLong())
            assertEquals(expectedWidth.toLong(), scaledBitmap!!.width.toLong())
        }
    }
}


================================================
FILE: androidshared/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application>
        <activity android:name="org.odk.collect.androidshared.ui.ReturnToAppActivity" />
    </application>
</manifest>


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/async/TrackableWorker.kt
================================================
package org.odk.collect.androidshared.async

import org.odk.collect.androidshared.livedata.MutableNonNullLiveData
import org.odk.collect.androidshared.livedata.NonNullLiveData
import org.odk.collect.async.Scheduler
import java.util.concurrent.atomic.AtomicInteger
import java.util.function.Consumer
import java.util.function.Supplier

class TrackableWorker(private val scheduler: Scheduler) {

    private val _isWorking = MutableNonNullLiveData(false)
    val isWorking: NonNullLiveData<Boolean> = _isWorking

    private var activeBackgroundJobsCounter = AtomicInteger(0)

    fun <T> immediate(background: Supplier<T>, foreground: Consumer<T>) {
        activeBackgroundJobsCounter.incrementAndGet()
        _isWorking.value = true
        scheduler.immediate(background) { result ->
            if (activeBackgroundJobsCounter.decrementAndGet() == 0) {
                _isWorking.value = false
            }
            foreground.accept(result)
        }
    }

    fun immediate(background: Runnable) {
        immediate(
            background = {
                background.run()
            },
            foreground = {}
        )
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/bitmap/ImageCompressor.kt
================================================
/*
 * Copyright 2017 Nafundi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.odk.collect.androidshared.bitmap

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.exifinterface.media.ExifInterface
import timber.log.Timber

object ImageCompressor {
    /**
     * Before proceed with scaling or rotating, make sure existing exif information is stored/restored.
     * @author Khuong Ninh (khuong.ninh@it-development.com)
     */
    fun execute(imagePath: String, maxPixels: Int) {
        backupExifData(imagePath)
        scaleDownImage(imagePath, maxPixels)
        restoreExifData(imagePath)
    }

    /**
     * This method is used to reduce an original picture size.
     * maxPixels refers to the max pixels of the long edge, the short edge is scaled proportionately.
     */
    private fun scaleDownImage(imagePath: String, maxPixels: Int) {
        if (maxPixels <= 0) {
            return
        }

        var image = ImageFileUtils.getBitmap(imagePath, BitmapFactory.Options())
        if (image != null) {
            val originalWidth = image.width.toDouble()
            val originalHeight = image.height.toDouble()
            if (originalWidth > originalHeight && originalWidth > maxPixels) {
                val newHeight = (originalHeight / (originalWidth / maxPixels)).toInt()
                image = Bitmap.createScaledBitmap(image, maxPixels, newHeight, false)
                ImageFileUtils.saveBitmapToFile(image, imagePath)
            } else if (originalHeight > maxPixels) {
                val newWidth = (originalWidth / (originalHeight / maxPixels)).toInt()
                image = Bitmap.createScaledBitmap(image, newWidth, maxPixels, false)
                ImageFileUtils.saveBitmapToFile(image, imagePath)
            }
        }
    }

    private fun backupExifData(imagePath: String) {
        try {
            val exif = ExifInterface(imagePath)
            for ((key, _) in exifDataBackup) {
                exifDataBackup[key] = exif.getAttribute(key)
            }
        } catch (e: Throwable) {
            Timber.w(e)
        }
    }

    private fun restoreExifData(imagePath: String) {
        try {
            val exif = ExifInterface(imagePath)
            for ((key, value) in exifDataBackup) {
                exif.setAttribute(key, value)
            }
            exif.saveAttributes()
        } catch (e: Throwable) {
            Timber.w(e)
        }
    }

    private val exifDataBackup = mutableMapOf<String, String?>(
        ExifInterface.TAG_DATETIME to null,
        ExifInterface.TAG_DATETIME_ORIGINAL to null,
        ExifInterface.TAG_DATETIME_DIGITIZED to null,
        ExifInterface.TAG_OFFSET_TIME to null,
        ExifInterface.TAG_OFFSET_TIME_ORIGINAL to null,
        ExifInterface.TAG_OFFSET_TIME_DIGITIZED to null,
        ExifInterface.TAG_SUBSEC_TIME to null,
        ExifInterface.TAG_SUBSEC_TIME_ORIGINAL to null,
        ExifInterface.TAG_SUBSEC_TIME_DIGITIZED to null,
        ExifInterface.TAG_IMAGE_DESCRIPTION to null,
        ExifInterface.TAG_MAKE to null,
        ExifInterface.TAG_MODEL to null,
        ExifInterface.TAG_SOFTWARE to null,
        ExifInterface.TAG_ARTIST to null,
        ExifInterface.TAG_COPYRIGHT to null,
        ExifInterface.TAG_MAKER_NOTE to null,
        ExifInterface.TAG_USER_COMMENT to null,
        ExifInterface.TAG_IMAGE_UNIQUE_ID to null,
        ExifInterface.TAG_CAMERA_OWNER_NAME to null,
        ExifInterface.TAG_BODY_SERIAL_NUMBER to null,
        ExifInterface.TAG_GPS_ALTITUDE to null,
        ExifInterface.TAG_GPS_ALTITUDE_REF to null,
        ExifInterface.TAG_GPS_DATESTAMP to null,
        ExifInterface.TAG_GPS_TIMESTAMP to null,
        ExifInterface.TAG_GPS_LATITUDE to null,
        ExifInterface.TAG_GPS_LATITUDE_REF to null,
        ExifInterface.TAG_GPS_LONGITUDE to null,
        ExifInterface.TAG_GPS_LONGITUDE_REF to null,
        ExifInterface.TAG_GPS_SATELLITES to null,
        ExifInterface.TAG_GPS_STATUS to null,
        ExifInterface.TAG_ORIENTATION to null
    )
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/bitmap/ImageFileUtils.kt
================================================
package org.odk.collect.androidshared.bitmap

import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.graphics.Matrix
import androidx.exifinterface.media.ExifInterface
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.lang.Exception
import java.util.Locale
import kotlin.math.ceil

object ImageFileUtils {
    // 80% JPEG quality gives a greater file size reduction with almost no loss in quality
    private const val IMAGE_COMPRESS_QUALITY = 80

    private val EXIF_ORIENTATION_ROTATIONS = arrayOf(
        ExifInterface.ORIENTATION_ROTATE_90,
        ExifInterface.ORIENTATION_ROTATE_180,
        ExifInterface.ORIENTATION_ROTATE_270
    )

    @JvmStatic
    fun saveBitmapToFile(bitmap: Bitmap?, path: String) {
        val compressFormat =
            if (path.lowercase(Locale.getDefault()).endsWith(".png")) {
                CompressFormat.PNG
            } else {
                CompressFormat.JPEG
            }
        try {
            if (bitmap != null) {
                FileOutputStream(path).use { out -> bitmap.compress(compressFormat, IMAGE_COMPRESS_QUALITY, out) }
            }
        } catch (e: Exception) {
            Timber.e(e)
        }
    }

    /*
    This method is used to avoid OutOfMemoryError exception during loading an image.
    If the exception occurs we catch it and try to load a smaller image.
     */
    @JvmStatic
    fun getBitmap(path: String?, originalOptions: BitmapFactory.Options): Bitmap? {
        val newOptions = BitmapFactory.Options()
        newOptions.inSampleSize = originalOptions.inSampleSize
        if (newOptions.inSampleSize <= 0) {
            newOptions.inSampleSize = 1
        }
        val bitmap: Bitmap? = try {
            BitmapFactory.decodeFile(path, originalOptions)
        } catch (e: OutOfMemoryError) {
            Timber.i(e)
            newOptions.inSampleSize++
            return getBitmap(path, newOptions)
        }
        return bitmap
    }

    @JvmStatic
    fun getBitmapScaledToDisplay(file: File, screenHeight: Int, screenWidth: Int): Bitmap? {
        return getBitmapScaledToDisplay(file, screenHeight, screenWidth, false)
    }

    /**
     * Scales image according to the given display
     *
     * @param file           containing the image
     * @param screenHeight   height of the display
     * @param screenWidth    width of the display
     * @param upscaleEnabled determines whether the image should be up-scaled or not
     * if the window size is greater than the image size
     * @return scaled bitmap
     */
    @JvmStatic
    fun getBitmapScaledToDisplay(
        file: File,
        screenHeight: Int,
        screenWidth: Int,
        upscaleEnabled: Boolean
    ): Bitmap? {
        // Determine image size of file
        var options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        getBitmap(file.absolutePath, options)
        var bitmap: Bitmap?
        val scale: Double
        if (upscaleEnabled) {
            // Load full size bitmap image
            options = BitmapFactory.Options()
            options.inInputShareable = true
            options.inPurgeable = true
            bitmap = getBitmap(file.absolutePath, options)
            val heightScale = options.outHeight.toDouble() / screenHeight
            val widthScale = options.outWidth.toDouble() / screenWidth
            scale = widthScale.coerceAtLeast(heightScale)
            val newHeight = ceil(options.outHeight / scale)
            val newWidth = ceil(options.outWidth / scale)
            if (bitmap != null) {
                bitmap = Bitmap.createScaledBitmap(
                    bitmap,
                    newWidth.toInt(),
                    newHeight.toInt(),
                    false
                )
            }
        } else {
            val heightScale = options.outHeight / screenHeight
            val widthScale = options.outWidth / screenWidth

            // Powers of 2 work faster, sometimes, according to the doc.
            // We're just doing closest size that still fills the screen.
            scale = widthScale.coerceAtLeast(heightScale).toDouble()

            // get bitmap with scale ( < 1 is the same as 1)
            options = BitmapFactory.Options()
            options.inInputShareable = true
            options.inPurgeable = true
            options.inSampleSize = scale.toInt()
            bitmap = getBitmap(file.absolutePath, options)
        }
        if (bitmap != null) {
            Timber.i(
                "Screen is %dx%d.  Image has been scaled down by %f to %dx%d",
                screenHeight,
                screenWidth,
                scale,
                bitmap.height,
                bitmap.width
            )
        }
        return bitmap
    }

    /**
     * While copying the file, apply the exif rotation of sourceFile to destinationFile
     * so that sourceFile with EXIF has same orientation as destinationFile without EXIF
     */
    @JvmStatic
    fun copyImageAndApplyExifRotation(sourceFile: File, destFile: File) {
        var sourceFileExif: ExifInterface? = null
        try {
            sourceFileExif = ExifInterface(sourceFile)
        } catch (e: IOException) {
            Timber.w(e)
        }
        if (sourceFileExif == null ||
            !EXIF_ORIENTATION_ROTATIONS.contains(
                sourceFileExif
                    .getAttributeInt(
                        ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_UNDEFINED
                    )
            )
        ) {
            // Source Image doesn't have any EXIF Rotations, so a normal file copy will suffice
            sourceFile.copyTo(destFile, true)
        } else {
            val sourceImage = getBitmap(sourceFile.absolutePath, BitmapFactory.Options())
            val orientation = sourceFileExif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED
            )
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmapAndSaveToFile(
                    sourceImage,
                    90,
                    destFile.absolutePath
                )
                ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmapAndSaveToFile(
                    sourceImage,
                    180,
                    destFile.absolutePath
                )
                ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmapAndSaveToFile(
                    sourceImage,
                    270,
                    destFile.absolutePath
                )
            }
        }
    }

    private fun rotateBitmapAndSaveToFile(image: Bitmap?, degrees: Int, filePath: String) {
        var imageToSave = image
        try {
            val matrix = Matrix()
            matrix.postRotate(degrees.toFloat())
            if (image != null) {
                imageToSave = Bitmap.createBitmap(image, 0, 0, image.width, image.height, matrix, true)
            }
        } catch (e: OutOfMemoryError) {
            Timber.w(e)
        }
        saveBitmapToFile(imageToSave, filePath)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/data/AppState.kt
================================================
package org.odk.collect.androidshared.data

import android.app.Activity
import android.app.Application
import android.app.Service
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

/**
 * [AppState] can be used as a shared store of state that lives at an "app"/"in-memory" level
 * rather than being tied to a specific component. This could be shared state between different
 * [Activity] objects or a way of communicating between a [Service] and other components.
 * [AppState] can be used as an alternative to Dagger singleton objects or static fields.
 *
 * [AppState] should not be used to share state between views or components on the same screen or make
 * up part of the same flow. For this, using Jetpack's [ViewModel] at either a [Fragment] or [Activity]
 * level is more appropriate.
 *
 * The easiest way to use [AppState] is have an instance owned by your app's [Application] object
 * and implement the [StateStore] interface:
 *
 * ```
 * class MyApplication : Application(), StateStore {
 *     private val appState = AppState()
 * }
 * ```
 *
 * The [AppState] instance can then be accessed anywhere the [Application] is available using the
 * [getState] extension function.
 *
 */
class AppState {

    private val map = mutableMapOf<String, Any?>()

    @Suppress("UNCHECKED_CAST")
    fun <T> get(key: String, default: T): T {
        return map.getOrPut(key) { default } as T
    }

    @Suppress("UNCHECKED_CAST")
    fun <T> get(key: String): T? {
        return map[key] as T?
    }

    fun <T> getFlow(key: String, default: T): StateFlow<T> {
        return get(key, MutableStateFlow(default))
    }

    fun set(key: String, value: Any?) {
        map[key] = value
    }

    fun <T> setFlow(key: String, value: T) {
        get<MutableStateFlow<T>>(key).let {
            if (it != null) {
                it.value = value
            } else {
                map[key] = MutableStateFlow(value)
            }
        }
    }

    fun clear() {
        map.clear()
    }

    fun clear(key: String) {
        map.remove(key)
    }
}

interface StateStore {
    fun getState(): AppState
}

fun Application.getState(): AppState {
    try {
        val stateStore = this as StateStore
        return stateStore.getState()
    } catch (e: ClassCastException) {
        throw ClassCastException("${this.javaClass} cannot be cast to StateStore")
    }
}

fun Context.getState(): AppState {
    return (applicationContext as Application).getState()
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/data/Consumable.kt
================================================
package org.odk.collect.androidshared.data

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData

/**
 * Useful for values that are read multiple times but only used
 * once (like an error that shows a dialog once).
 */
data class Consumable<T>(val value: T) {

    private var consumed = false

    fun isConsumed(): Boolean {
        return consumed
    }

    fun consume() {
        consumed = true
    }
}

fun <T> LiveData<out Consumable<T>?>.consume(lifecycleOwner: LifecycleOwner, consumer: (T) -> Unit) {
    observe(lifecycleOwner) { consumable ->
        if (consumable != null && !consumable.isConsumed()) {
            consumable.consume()
            consumer(consumable.value)
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/data/Data.kt
================================================
package org.odk.collect.androidshared.data

import kotlinx.coroutines.flow.StateFlow
import org.odk.collect.androidshared.data.Updatable.Data
import org.odk.collect.androidshared.data.Updatable.QualifiedData
import kotlin.reflect.KProperty

sealed interface Updatable<T> {
    class QualifiedData<T>(
        private val appState: AppState,
        private val key: String,
        private val default: T
    ) : Updatable<T> {
        fun flow(qualifier: String): StateFlow<T> {
            return appState.getFlow("$qualifier:$key", default)
        }

        fun set(qualifier: String?, value: T) {
            appState.setFlow("$qualifier:$key", value)
        }
    }

    class Data<T>(private val appState: AppState, private val key: String, private val default: T) :
        Updatable<T> {
        fun flow(): StateFlow<T> {
            return appState.getFlow(key, default)
        }

        fun set(value: T) {
            appState.setFlow(key, value)
        }
    }
}

abstract class DataService(
    private val appState: AppState,
    private val onUpdate: (() -> Unit)? = null
) {

    private val updaters = mutableListOf<Updater<*>>()

    fun update(qualifier: String? = null) {
        updaters.forEach { it.update(qualifier) }
        onUpdate?.invoke()
    }

    protected fun <T> data(key: String, default: T): DataDelegate<T> {
        val data = Data(appState, key, default)
        return DataDelegate(data)
    }

    protected fun <T> data(key: String, default: T, updater: () -> T): DataDelegate<T> {
        val data = Data(appState, key, default)
        updaters.add(Updater(data) { updater() })
        return DataDelegate(data)
    }

    protected fun <T> qualifiedData(
        key: String,
        default: T
    ): QualifiedDataDelegate<T> {
        val data = QualifiedData(appState, key, default)
        return QualifiedDataDelegate(data)
    }

    protected fun <T> qualifiedData(
        key: String,
        default: T,
        updater: (String) -> T
    ): QualifiedDataDelegate<T> {
        val data = QualifiedData(appState, key, default)
        updaters.add(Updater(data) { it: String? -> updater(it!!) })
        return QualifiedDataDelegate(data)
    }

    class QualifiedDataDelegate<T>(private val data: QualifiedData<T>) {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): QualifiedData<T> {
            return data
        }
    }

    class DataDelegate<T>(private val data: Data<T>) {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): Data<T> {
            return data
        }
    }

    private class Updater<T>(
        private val updatable: Updatable<T>,
        private val updater: (String?) -> T
    ) {
        fun update(qualifier: String? = null) {
            when (updatable) {
                is Data -> updatable.set(updater(qualifier))
                is QualifiedData -> updatable.set(qualifier, updater(qualifier))
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/livedata/LiveDataExt.kt
================================================
package org.odk.collect.androidshared.livedata

import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData

object LiveDataExt {
    fun <T, U> LiveData<T>.combine(other: LiveData<U>): LiveData<Pair<T?, U?>> {
        return LiveDataUtils.combine(this, other)
    }

    fun <T, U> LiveData<T>.runningFold(initial: U, operation: (U, T) -> U): LiveData<U> {
        val mediator = MediatorLiveData<U>()

        var accum = initial
        mediator.addSource(this) {
            accum = operation(accum, it)
            mediator.value = accum
        }

        return mediator
    }

    /**
     * Returns a [LiveData] where each value is a [Pair] made up of the latest value and the
     * previous value.
     */
    fun <T : Any?> LiveData<T>.withLast(): LiveData<Pair<T?, T?>> {
        return this.runningFold(Pair(null, null) as Pair<T?, T?>) { last, current ->
            Pair(last.second, current)
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/livedata/LiveDataUtils.java
================================================
package org.odk.collect.androidshared.livedata;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import org.odk.collect.async.Cancellable;

import java.util.function.Consumer;
import java.util.function.Function;

import kotlin.Pair;
import kotlin.Triple;

public class LiveDataUtils {

    private LiveDataUtils() {

    }

    public static <T> Cancellable observe(LiveData<T> liveData, Consumer<T> consumer) {
        Observer<T> observer = value -> {
            if (value != null) {
                consumer.accept(value);
            }
        };

        liveData.observeForever(observer);
        return () -> {
            liveData.removeObserver(observer);
            return true;
        };
    }

    public static <T> LiveData<T> liveDataOf(T value) {
        return new MutableLiveData<>(value);
    }

    public static <T, U> LiveData<Pair<T, U>> combine(LiveData<T> one, LiveData<U> two) {
        return new CombinedLiveData<>(
                new LiveData[]{one, two},
                values -> new Pair<>((T) values[0], (U) values[1])
        );
    }

    public static <T, U, V> LiveData<Triple<T, U, V>> combine3(LiveData<T> one, LiveData<U> two, LiveData<V> three) {
        return new CombinedLiveData<>(
                new LiveData[]{one, two, three},
                values -> new Triple<>((T) values[0], (U) values[1], (V) values[2])
        );
    }

    public static <T, U, V, W> LiveData<Quad<T, U, V, W>> combine4(LiveData<T> one, LiveData<U> two, LiveData<V> three, LiveData<W> four) {
        return new CombinedLiveData<>(
                new LiveData[]{one, two, three, four},
                values -> new Quad<>((T) values[0], (U) values[1], (V) values[2], (W) values[3])
        );
    }

    private static class CombinedLiveData<T> extends MediatorLiveData<T> {

        private final Object[] values;
        private final Function<Object[], T> map;
        private T lastEmitted;

        CombinedLiveData(LiveData<?>[] sources, Function<Object[], T> map) {
            this.map = map;
            values = new Object[sources.length];

            for (int i = 0; i < sources.length; i++) {
                int index = i;
                addSource(sources[i], value -> {
                    values[index] = value;
                    update();
                });
            }

            update();
        }

        private void update() {
            T newValue = map.apply(values);

            if (lastEmitted == null || !lastEmitted.equals(newValue)) {
                lastEmitted = newValue;
                setValue(newValue);
            }
        }
    }

    public static class Quad<T, U, V, W> {

        public final T first;
        public final U second;
        public final V third;
        public final W fourth;

        public Quad(T first, U second, V third, W fourth) {
            this.first = first;
            this.second = second;
            this.third = third;
            this.fourth = fourth;
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/livedata/NonNullLiveData.kt
================================================
package org.odk.collect.androidshared.livedata

import androidx.lifecycle.LiveData

/**
 * Allows creating LiveData values that can be used without null checks
 */
abstract class NonNullLiveData<T : Any>(value: T) : LiveData<T>(value) {

    override fun getValue(): T {
        return super.getValue() as T
    }
}

class MutableNonNullLiveData<T : Any>(value: T) : NonNullLiveData<T>(value) {

    public override fun postValue(value: T) {
        super.postValue(value)
    }

    public override fun setValue(value: T) {
        super.setValue(value)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/BroadcastReceiverRegister.kt
================================================
package org.odk.collect.androidshared.system

import android.content.BroadcastReceiver
import android.content.Context
import android.content.IntentFilter

interface BroadcastReceiverRegister {
    fun registerReceiver(receiver: BroadcastReceiver, filter: IntentFilter)

    fun unregisterReceiver(receiver: BroadcastReceiver)
}

class BroadcastReceiverRegisterImpl(private val context: Context) : BroadcastReceiverRegister {
    override fun registerReceiver(receiver: BroadcastReceiver, filter: IntentFilter) {
        context.registerReceiver(receiver, filter)
    }

    override fun unregisterReceiver(receiver: BroadcastReceiver) {
        context.unregisterReceiver(receiver)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/CameraUtils.java
================================================
package org.odk.collect.androidshared.system;

/*
Copyright 2018 Theodoros Tyrovouzis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

import android.content.Context;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;

import timber.log.Timber;

public class CameraUtils {
    public static int getFrontCameraId() {
        for (int camNo = 0; camNo < Camera.getNumberOfCameras(); camNo++) {
            Camera.CameraInfo camInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(camNo, camInfo);

            if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                return camNo;
            }
        }
        Timber.w("No Available front camera");
        return -1;
    }

    public boolean isFrontCameraAvailable(Context context) {
        try {
            //https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html
            CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
            if (cameraManager != null) {
                String[] cameraId = cameraManager.getCameraIdList();
                for (String id : cameraId) {
                    CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
                    Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                    if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                        return true;
                    }
                }
            }
        } catch (CameraAccessException | NullPointerException e) {
            Timber.e(e);
        }
        return false; // No front-facing camera found
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/ContextExt.kt
================================================
package org.odk.collect.androidshared.system

import android.app.Activity
import android.content.Context
import android.content.res.Configuration
import android.util.TypedValue
import androidx.annotation.AttrRes

object ContextExt {

    /**
     * Be careful when using this method to retrieve colors, especially for those defined
     * using selectors as it might not work well.
     * In such cases consider using [com.google.android.material.color.MaterialColors.getColor] instead.
     */
    @JvmStatic
    fun getThemeAttributeValue(context: Context, @AttrRes resId: Int): Int {
        val outValue = TypedValue()
        context.theme.resolveAttribute(resId, outValue, true)
        return outValue.data
    }

    @JvmStatic
    fun Context.isDarkTheme(): Boolean {
        val uiMode: Int = this.resources.configuration.uiMode
        return (uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/ExternalFilesUtils.kt
================================================
package org.odk.collect.androidshared.system

import android.content.Context
import java.io.File
import java.io.IOException

object ExternalFilesUtils {

    @JvmStatic
    fun testExternalFilesAccess(context: Context) {
        val externalFilesDir = context.getExternalFilesDir(null)

        if (externalFilesDir == null) {
            throw IllegalStateException("External files dir is null!")
        } else {
            try {
                val testFile = File(externalFilesDir, ".test")
                testFile.createNewFile()
                testFile.delete()
            } catch (e: IOException) {
                if (!externalFilesDir.exists()) {
                    throw IllegalStateException(
                        "External files dir does not exist: ${externalFilesDir.absolutePath}"
                    )
                } else {
                    throw IllegalStateException(
                        "App can't write to external files dir: ${externalFilesDir.absolutePath}",
                        e
                    )
                }
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/IntentLauncher.kt
================================================
package org.odk.collect.androidshared.system

import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher

object IntentLauncherImpl : IntentLauncher {
    override fun launch(context: Context, intent: Intent?, onError: () -> Unit) {
        try {
            context.startActivity(intent)
        } catch (e: Exception) {
            onError()
        } catch (e: Error) {
            onError()
        }
    }

    override fun launchForResult(
        activity: Activity,
        intent: Intent?,
        requestCode: Int,
        onError: () -> Unit
    ) {
        try {
            activity.startActivityForResult(intent, requestCode)
        } catch (e: Exception) {
            onError()
        } catch (e: Error) {
            onError()
        }
    }

    override fun launchForResult(
        resultLauncher: ActivityResultLauncher<Intent>,
        intent: Intent?,
        onError: () -> Unit
    ) {
        try {
            resultLauncher.launch(intent)
        } catch (e: Exception) {
            onError()
        } catch (e: Error) {
            onError()
        }
    }
}

interface IntentLauncher {
    fun launch(context: Context, intent: Intent?, onError: () -> Unit)

    fun launchForResult(activity: Activity, intent: Intent?, requestCode: Int, onError: () -> Unit)

    fun launchForResult(
        resultLauncher: ActivityResultLauncher<Intent>,
        intent: Intent?,
        onError: () -> Unit
    )
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/OpenGLVersionChecker.kt
================================================
package org.odk.collect.androidshared.system

import android.app.ActivityManager
import android.content.Context

/**
 * Checks if the device supports the given OpenGL ES version.
 *
 * Note: This approach may not be 100% reliable because `reqGlEsVersion` indicates
 * the highest version of OpenGL ES that the device's hardware is guaranteed to support
 * at runtime. However, it might not always reflect the actual version available.
 *
 * For a more reliable method, refer to https://developer.android.com/develop/ui/views/graphics/opengl/about-opengl#version-check.
 * This recommended approach is more complex to implement but offers better accuracy.
 */
object OpenGLVersionChecker {
    @JvmStatic
    fun isOpenGLv2Supported(context: Context): Boolean {
        return (context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
            .deviceConfigurationInfo.reqGlEsVersion >= 0x20000
    }

    @JvmStatic
    fun isOpenGLv3Supported(context: Context): Boolean {
        return (context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
            .deviceConfigurationInfo.reqGlEsVersion >= 0x30000
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/PlayServicesChecker.java
================================================
package org.odk.collect.androidshared.system;

import android.app.Activity;
import android.content.Context;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;

/** Created by Divya on 3/2/2017. */

public class PlayServicesChecker {
    private static final int PLAY_SERVICE_ERROR_REQUEST_CODE = 1000;
    private static int lastResultCode = ConnectionResult.SUCCESS;

    /** Returns true if Google Play Services is installed and up to date. */
    public boolean isGooglePlayServicesAvailable(Context context) {
        lastResultCode = GoogleApiAvailability.getInstance()
            .isGooglePlayServicesAvailable(context);
        return lastResultCode == ConnectionResult.SUCCESS;
    }

    /** Shows an error dialog for the last call to isGooglePlayServicesAvailable(). */
    public void showGooglePlayServicesAvailabilityErrorDialog(Context context) {
        GoogleApiAvailability.getInstance().getErrorDialog(
            (Activity) context, lastResultCode, PLAY_SERVICE_ERROR_REQUEST_CODE).show();
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/ProcessRestoreDetector.kt
================================================
package org.odk.collect.androidshared.system

import android.content.Context
import android.os.Bundle
import org.odk.collect.androidshared.data.getState
import org.odk.collect.shared.strings.UUIDGenerator

object ProcessRestoreDetector {

    @JvmStatic
    fun registerOnSaveInstanceState(context: Context, outState: Bundle) {
        val uuid = UUIDGenerator().generateUUID()
        context.getState().set("${getKey()}:$uuid", Any())
        outState.putString(getKey(), uuid)
    }

    @JvmStatic
    fun isProcessRestoring(context: Context, savedInstanceState: Bundle?): Boolean {
        return if (savedInstanceState != null) {
            val bundleUuid = savedInstanceState.getString(getKey())
            context.getState().get<Any>("${getKey()}:$bundleUuid") == null
        } else {
            false
        }
    }

    private fun getKey() = this::class.qualifiedName
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/UriExt.kt
================================================
package org.odk.collect.androidshared.system

import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import androidx.core.net.toFile
import java.io.File
import java.io.FileOutputStream

fun Uri.copyToFile(context: Context, dest: File) {
    try {
        context.contentResolver.openInputStream(this)?.use { inputStream ->
            FileOutputStream(dest).use { outputStream ->
                inputStream.copyTo(outputStream)
            }
        }
    } catch (e: Exception) {
        // ignore
    }
}

fun Uri.getFileExtension(context: Context): String? {
    var extension = getFileName(context)?.substringAfterLast(".", "")

    if (extension.isNullOrEmpty()) {
        val mimeType = context.contentResolver.getType(this)

        extension = if (scheme == ContentResolver.SCHEME_CONTENT) {
            MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
        } else {
            MimeTypeMap.getFileExtensionFromUrl(toString())
        }

        if (extension.isNullOrEmpty()) {
            extension = mimeType?.substringAfterLast("/", "")
        }
    }

    return if (extension.isNullOrEmpty()) {
        null
    } else {
        ".$extension"
    }
}

fun Uri.getFileName(context: Context): String? {
    var fileName: String? = null

    try {
        when (scheme) {
            ContentResolver.SCHEME_FILE -> fileName = toFile().name
            ContentResolver.SCHEME_CONTENT -> {
                val cursor = context.contentResolver.query(this, null, null, null, null)
                cursor?.use {
                    if (it.moveToFirst()) {
                        val fileNameColumnIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                        if (fileNameColumnIndex != -1) {
                            fileName = it.getString(fileNameColumnIndex)
                        }
                    }
                }
            }
            ContentResolver.SCHEME_ANDROID_RESOURCE -> {
                // for uris like [android.resource://com.example.app/1234567890]
                val resourceId = lastPathSegment?.toIntOrNull()
                if (resourceId != null) {
                    fileName = context.resources.getResourceName(resourceId)
                } else {
                    // for uris like [android.resource://com.example.app/raw/sample]
                    val packageName = authority
                    if (pathSegments.size >= 2) {
                        val resourceType = pathSegments[0]
                        val resourceEntryName = pathSegments[1]
                        val resId = context.resources.getIdentifier(resourceEntryName, resourceType, packageName)
                        if (resId != 0) {
                            fileName = context.resources.getResourceName(resId)
                        }
                    }
                }
            }
        }

        if (fileName == null) {
            fileName = path?.substringAfterLast("/")
        }
    } catch (e: Exception) {
        // ignore
    }

    return fileName
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/AlertStore.kt
================================================
package org.odk.collect.androidshared.ui

/**
 * Component for recording "alerts". This is useful for testing transient UI elements like toasts,
 * flashes or snackbars that are susceptible to flakiness with assertions running after they have
 * disappeared.
 */
class AlertStore {

    var enabled = false
    private var recordedAlerts = mutableListOf<String>()

    fun register(alert: String) {
        if (enabled) {
            recordedAlerts.add(alert)
        }
    }

    fun popAll(): List<String> {
        val copy = recordedAlerts.toList()
        recordedAlerts.clear()

        return copy
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/Animations.kt
================================================
package org.odk.collect.androidshared.ui

import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.view.View
import org.odk.collect.androidshared.ui.Animations.DISABLE_ANIMATIONS

/**
 * Helpers/extensions for running animations. These are "test safe" in that animations can be disabled
 * using [DISABLE_ANIMATIONS] - this should be set to `true` in Robolectric tests to avoid
 * infinite loops.
 */
object Animations {

    var DISABLE_ANIMATIONS = false

    @JvmStatic
    fun View.createAlphaAnimation(
        startValue: Float,
        endValue: Float,
        duration: Long
    ): DisableableAnimatorWrapper {
        val animation = ValueAnimator.ofFloat(startValue, endValue)
        animation.duration = duration
        animation.addUpdateListener {
            this.alpha = it.animatedValue as Float
        }

        return DisableableAnimatorWrapper(animation)
    }
}

class DisableableAnimatorWrapper(private val wrapped: Animator) {

    fun onEnd(onEnd: () -> Unit): DisableableAnimatorWrapper {
        wrapped.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
            }

            override fun onAnimationEnd(animation: Animator) {
                onEnd()
            }

            override fun onAnimationCancel(animation: Animator) {
            }

            override fun onAnimationRepeat(animation: Animator) {
            }
        })

        return this
    }

    fun then(other: DisableableAnimatorWrapper): DisableableAnimatorWrapper {
        val set = AnimatorSet()
        set.playSequentially(this.wrapped, other.wrapped)

        return DisableableAnimatorWrapper(set)
    }

    fun start() {
        if (!DISABLE_ANIMATIONS) {
            wrapped.start()
        } else {
            // Just run listeners immediately if we're not running the actual animations
            if (wrapped is AnimatorSet) {
                (wrapped.childAnimations + wrapped).forEach { anim ->
                    anim.listeners?.forEach {
                        it.onAnimationStart(wrapped)
                        it.onAnimationEnd(wrapped)
                    }
                }
            } else {
                wrapped.listeners?.forEach {
                    it.onAnimationStart(wrapped)
                    it.onAnimationEnd(wrapped)
                }
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ColorPickerDialog.kt
================================================
package org.odk.collect.androidshared

import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.odk.collect.androidshared.databinding.ColorPickerDialogLayoutBinding
import java.lang.Exception

class ColorPickerDialog : DialogFragment() {
    lateinit var binding: ColorPickerDialogLayoutBinding

    val model: ColorPickerViewModel by activityViewModels()

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        binding = ColorPickerDialogLayoutBinding.inflate(LayoutInflater.from(context))
        binding.hexColor.doOnTextChanged { color, _, _, _ ->
            updateCurrentColorCircle("#$color")
        }
        binding.currentColor.text = requireArguments().getString(CURRENT_ICON)!!

        fixHexColorPrefix()
        setListeners()
        setCurrentColor(requireArguments().getString(CURRENT_COLOR)!!)

        return MaterialAlertDialogBuilder(requireContext())
            .setView(binding.root)
            .setTitle(org.odk.collect.strings.R.string.project_color)
            .setNegativeButton(org.odk.collect.strings.R.string.cancel) { _, _ -> dismiss() }
            .setPositiveButton(org.odk.collect.strings.R.string.ok) { _, _ -> model.pickColor("#${binding.hexColor.text}") }
            .create()
    }

    private fun setListeners() {
        binding.color1.setOnClickListener { setCurrentColor(R.color.color1) }
        binding.color2.setOnClickListener { setCurrentColor(R.color.color2) }
        binding.color3.setOnClickListener { setCurrentColor(R.color.color3) }
        binding.color4.setOnClickListener { setCurrentColor(R.color.color4) }
        binding.color5.setOnClickListener { setCurrentColor(R.color.color5) }
        binding.color6.setOnClickListener { setCurrentColor(R.color.color6) }
        binding.color7.setOnClickListener { setCurrentColor(R.color.color7) }
        binding.color8.setOnClickListener { setCurrentColor(R.color.color8) }
        binding.color9.setOnClickListener { setCurrentColor(R.color.color9) }
        binding.color10.setOnClickListener { setCurrentColor(R.color.color10) }
        binding.color11.setOnClickListener { setCurrentColor(R.color.color11) }
        binding.color12.setOnClickListener { setCurrentColor(R.color.color12) }
        binding.color13.setOnClickListener { setCurrentColor(R.color.color13) }
        binding.color14.setOnClickListener { setCurrentColor(R.color.color14) }
        binding.color15.setOnClickListener { setCurrentColor(R.color.color15) }
    }

    private fun setCurrentColor(color: Int) {
        setCurrentColor("#${Integer.toHexString(ContextCompat.getColor(requireContext(), color)).substring(2)}")
    }

    private fun setCurrentColor(color: String) {
        binding.hexColor.setText(color.substring(1))
    }

    private fun updateCurrentColorCircle(color: String) {
        try {
            (binding.currentColor.background as GradientDrawable).setColor(Color.parseColor(color))
            binding.hexColor.error = null
            (dialog as? AlertDialog)?.also {
                it.getButton(AlertDialog.BUTTON_POSITIVE).alpha = 1f
                it.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
            }
        } catch (e: Exception) {
            binding.hexColor.error = getString(org.odk.collect.strings.R.string.invalid_hex_code)
            (dialog as? AlertDialog)?.also {
                it.getButton(AlertDialog.BUTTON_POSITIVE).alpha = 0.3f
                it.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
            }
        }
    }

    // https://github.com/material-components/material-components-android/issues/773#issuecomment-603759649
    private fun fixHexColorPrefix() {
        val prefixView = binding.hexColorLayout.findViewById<AppCompatTextView>(com.google.android.material.R.id.textinput_prefix_text)
        prefixView.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
        prefixView.gravity = Gravity.CENTER
    }

    companion object {
        const val CURRENT_COLOR = "CURRENT_COLOR"
        const val CURRENT_ICON = "CURRENT_ICON"
    }
}

class ColorPickerViewModel : ViewModel() {
    private val _pickedColor = MutableLiveData<String>()
    val pickedColor: LiveData<String> = _pickedColor

    fun pickColor(color: String) {
        _pickedColor.value = color
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ComposeThemeProvider.kt
================================================
package org.odk.collect.androidshared.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy

/**
 * Interface that allows a [android.content.Context] (such as an [android.app.Activity]) to
 * provide a Compose Theme to any child [ComposeView] instances:
 *
 * ```kotlin
 * class MyActivity : AppCompatActivity(), ComposeThemeProvider {
 *
 *     override fun onCreate(savedInstanceState: Bundle?) {
 *         super.onCreate(savedInstanceState)
 *         setContentView(R.layout.my_activity_layout)
 *         findViewById<ComposeView>(R.id.compose_view).setContextThemedContent {
 *             Text("Hello, world!")
 *         }
 *     }
 *
 *     @Composable
 *     override fun Theme(content: @Composable (() -> Unit)) {
 *         MyTheme { content() }
 *     }
 * }
 */
interface ComposeThemeProvider {
    @Composable
    fun Theme(content: @Composable () -> Unit)

    companion object {
        fun ComposeView.setContextThemedContent(
            viewCompositionStrategy: ViewCompositionStrategy,
            content: @Composable () -> Unit
        ) {
            setViewCompositionStrategy(viewCompositionStrategy)
            setContent {
                val themeProvider = context as? ComposeThemeProvider
                if (themeProvider != null) {
                    themeProvider.Theme {
                        content()
                    }
                } else {
                    content()
                }
            }
        }

        @Deprecated("Use overload instead")
        fun ComposeView.setContextThemedContent(content: @Composable () -> Unit) {
            setContextThemedContent(ViewCompositionStrategy.Default, content)
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/DialogFragmentUtils.kt
================================================
package org.odk.collect.androidshared.ui

import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import timber.log.Timber
import kotlin.reflect.KClass

object DialogFragmentUtils {

    @JvmStatic
    fun <T : DialogFragment> showIfNotShowing(
        dialogClass: Class<T>,
        fragmentManager: FragmentManager
    ) {
        showIfNotShowing(dialogClass, null, fragmentManager)
    }

    @JvmStatic
    fun <T : DialogFragment> showIfNotShowing(
        dialogClass: Class<T>,
        args: Bundle?,
        fragmentManager: FragmentManager
    ) {
        if (fragmentManager.isDestroyed) {
            return
        }

        val fragmentFactory = fragmentManager.fragmentFactory
        val instance = fragmentFactory.instantiate(dialogClass.classLoader, dialogClass.name) as T
        instance.arguments = args
        showIfNotShowing(instance, dialogClass, fragmentManager)
    }

    @JvmStatic
    fun <T : DialogFragment> showIfNotShowing(
        newDialog: T,
        dialogClass: Class<T>,
        fragmentManager: FragmentManager
    ) {
        showIfNotShowing(newDialog, dialogClass.name, fragmentManager)
    }

    @JvmStatic
    fun <T : DialogFragment> showIfNotShowing(
        newDialog: T,
        tag: String,
        fragmentManager: FragmentManager
    ) {
        if (fragmentManager.isStateSaved) {
            return
        }
        val existingDialog = fragmentManager.findFragmentByTag(tag) as T?
        if (existingDialog == null) {
            newDialog.show(fragmentManager.beginTransaction(), tag)

            // We need to execute this transaction. Otherwise a follow up call to this method
            // could happen before the Fragment exists in the Fragment Manager and so the
            // call to findFragmentByTag would return null and result in second dialog being show.
            try {
                fragmentManager.executePendingTransactions()
            } catch (e: IllegalStateException) {
                Timber.w(e)
            }
        }
    }

    @JvmStatic
    fun dismissDialog(dialogClazz: Class<*>, fragmentManager: FragmentManager) {
        dismissDialog(dialogClazz.name, fragmentManager)
    }

    @JvmStatic
    fun dismissDialog(tag: String, fragmentManager: FragmentManager) {
        val existingDialog = fragmentManager.findFragmentByTag(tag) as DialogFragment?
        if (existingDialog != null) {
            existingDialog.dismissAllowingStateLoss()

            // We need to execute this transaction. Otherwise a next attempt to display a dialog
            // could happen before the Fragment is dismissed in Fragment Manager and so the
            // call to findFragmentByTag would return something (not null) and as a result the
            // next dialog won't be displayed.
            try {
                fragmentManager.executePendingTransactions()
            } catch (e: IllegalStateException) {
                Timber.w(e)
            }
        }
    }

    fun <T : DialogFragment> FragmentManager.showIfNotShowing(dialogClass: KClass<T>) {
        showIfNotShowing(dialogClass.java, this)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/DialogUtils.kt
================================================
package org.odk.collect.androidshared.ui

import android.content.Context
import androidx.annotation.StringRes
import com.google.android.material.dialog.MaterialAlertDialogBuilder

object DialogUtils {
    @JvmStatic
    fun show(
        context: Context,
        @StringRes titleRes: Int,
        @StringRes messageRes: Int,
    ) {
        MaterialAlertDialogBuilder(context)
            .setTitle(titleRes)
            .setMessage(messageRes)
            .setPositiveButton(org.odk.collect.strings.R.string.ok, null)
            .show()
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/DisplayString.kt
================================================
package org.odk.collect.androidshared.ui

import android.content.Context

sealed class DisplayString {

    data class Raw(val value: String) : DisplayString()
    data class Resource(val resource: Int) : DisplayString()

    fun getString(context: Context): String {
        return when (this) {
            is Raw -> value
            is Resource -> context.getString(resource)
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/EdgeToEdge.kt
================================================
package org.odk.collect.androidshared.ui

import android.app.Activity
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.annotation.LayoutRes
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import org.odk.collect.androidshared.system.ContextExt.isDarkTheme

object EdgeToEdge {

    @JvmStatic
    fun Activity.setView(@LayoutRes layout: Int, edgeToEdge: Boolean) {
        window.handleEdgeToEdge(this, edgeToEdge)
        setContentView(layout)
    }

    @JvmStatic
    fun Activity.setView(view: View, edgeToEdge: Boolean) {
        window.handleEdgeToEdge(this, edgeToEdge)
        setContentView(view)
    }

    fun Window.handleEdgeToEdge(context: Context, edgeToEdge: Boolean = false) {
        WindowCompat.enableEdgeToEdge(this)
        WindowCompat.getInsetsController(this, this.decorView).let {
            val darkTheme = context.isDarkTheme()
            it.isAppearanceLightStatusBars = !darkTheme
            it.isAppearanceLightNavigationBars = !darkTheme
        }

        if (!edgeToEdge) {
            avoidEdgeToEdge()
        }
    }

    fun View.applyBottomBarInsetMargins() {
        ViewCompat.setOnApplyWindowInsetsListener(this) { v, windowInsets ->
            val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
            val keyboardInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())

            v.updatePadding(
                bottom = maxOf(0, keyboardInsets.bottom - systemBarsInsets.bottom)
            )

            windowInsets
        }
    }

    private fun Window.avoidEdgeToEdge() {
        val contentView = decorView.findViewById<View>(android.R.id.content)
        contentView.addSystemBarInsetMargins()
    }

    private fun View.addSystemBarInsetMargins() {
        ViewCompat.setOnApplyWindowInsetsListener(this) { v, windowInsets ->
            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                topMargin = insets.top
                bottomMargin = insets.bottom

                leftMargin = insets.left
                rightMargin = insets.right
            }

            windowInsets
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/FragmentFactoryBuilder.kt
================================================
package org.odk.collect.androidshared.ui

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import kotlin.reflect.KClass

/**
 * Convenience object for creating [FragmentFactory] instances without needing to use an inner,
 * private or anonymous class.
 */
class FragmentFactoryBuilder {

    private val classesAndFactories = mutableListOf<Pair<Class<*>, () -> Fragment>>()

    fun forClass(fragmentClass: KClass<*>, factory: () -> Fragment): FragmentFactoryBuilder {
        return forClass(fragmentClass.java, factory)
    }

    fun forClass(fragmentClass: Class<*>, factory: () -> Fragment): FragmentFactoryBuilder {
        classesAndFactories.add(Pair(fragmentClass, factory))
        return this
    }

    fun build(): FragmentFactory {
        return object : androidx.fragment.app.FragmentFactory() {
            override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
                val fragmentClass = loadFragmentClass(classLoader, className)

                val factory =
                    classesAndFactories.find { it.first.isAssignableFrom(fragmentClass) }?.second

                return if (factory != null) {
                    factory()
                } else {
                    super.instantiate(classLoader, className)
                }
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/GroupClickListener.kt
================================================
package org.odk.collect.androidshared.ui

import android.view.View
import androidx.constraintlayout.widget.Group

// https://stackoverflow.com/questions/59020818/group-multiple-views-in-constraint-layout-to-set-only-one-click-listener
fun Group.addOnClickListener(listener: (view: View) -> Unit) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener(listener)
    }
}

fun List<View>.addOnClickListener(listener: (view: View) -> Unit) {
    forEach {
        it.setOnClickListener(listener)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ListFragmentStateAdapter.kt
================================================
package org.odk.collect.androidshared.ui

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter

class ListFragmentStateAdapter(
    activity: FragmentActivity,
    private val fragments: List<Class<out Fragment>>
) : FragmentStateAdapter(activity) {

    private val fragmentFactory = activity.supportFragmentManager.fragmentFactory

    override fun createFragment(position: Int): Fragment {
        return fragmentFactory.instantiate(
            Thread.currentThread().contextClassLoader,
            fragments[position].name
        )
    }

    override fun getItemCount(): Int {
        return fragments.size
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/MenuExt.kt
================================================
package org.odk.collect.androidshared.ui

import android.annotation.SuppressLint
import android.view.Menu
import androidx.appcompat.view.menu.MenuBuilder

/**
 * Currently, there is no public API to add icons to popup menus.
 * The following workaround is for API 21+, and uses library-only APIs,
 * and is not guaranteed to work in future versions.
 */
@SuppressLint("RestrictedApi")
fun Menu.enableIconsVisibility() {
    if (this is MenuBuilder) {
        this.setOptionalIconsVisible(true)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt
================================================
package org.odk.collect.androidshared.ui

import android.content.Context
import android.os.Handler
import android.util.AttributeSet
import com.google.android.material.progressindicator.LinearProgressIndicator

/**
 * A progress bar that shows for a minimum amount fo time so it's obvious to the user that
 * something has happened.
 */
class ObviousProgressBar(
    context: Context,
    attrs: AttributeSet?
) : LinearProgressIndicator(context, attrs) {
    private val handler = Handler()
    private var shownAt: Long? = null

    init {
        super.setVisibility(GONE)
        super.setIndeterminate(true)
    }

    override fun show() {
        handler.removeCallbacksAndMessages(null)
        shownAt = System.currentTimeMillis()
        super.setVisibility(VISIBLE)
    }

    override fun hide() {
        if (shownAt != null) {
            val timeShown = System.currentTimeMillis() - shownAt!!

            if (timeShown < MINIMUM_SHOW_TIME) {
                val delay = MINIMUM_SHOW_TIME - timeShown

                handler.removeCallbacksAndMessages(null)
                handler.postDelayed({ this.makeGone() }, delay)
            } else {
                makeGone()
            }
        } else {
            makeGone()
        }
    }

    private fun makeGone() {
        super.setVisibility(GONE)
        shownAt = null
    }

    companion object {
        private const val MINIMUM_SHOW_TIME = 750
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/OneSignTextWatcher.kt
================================================
package org.odk.collect.androidshared.ui

import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import org.odk.collect.shared.strings.StringUtils

class OneSignTextWatcher(private val editText: EditText) : TextWatcher {
    lateinit var oldTextString: String

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        oldTextString = s.toString()
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    }

    override fun afterTextChanged(editable: Editable?) {
        editable.toString().let {
            if (it != oldTextString) {
                val trimmedString = StringUtils.firstCharacterOrEmoji(it)
                editText.setText(trimmedString)
                editText.setSelection(trimmedString.length)
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/PrefUtils.kt
================================================
package org.odk.collect.androidshared.ui

import android.content.Context
import androidx.preference.ListPreference
import org.odk.collect.shared.settings.Settings

object PrefUtils {

    @JvmStatic
    fun createListPref(
        context: Context,
        key: String,
        title: String,
        labelIds: IntArray,
        values: Array<String>,
        settings: Settings
    ): ListPreference {
        val labels: Array<String?> = labelIds.map { context.getString(it) }.toTypedArray()
        return createListPref(context, key, title, labels, values, settings)
    }

    /**
     * Gets an integer value from the shared preferences. If the preference has
     * a string value, attempts to convert it to an integer. If the preference
     * is not found or is not a valid integer, returns the defaultValue.
     */
    @JvmStatic
    fun getInt(key: String?, defaultValue: Int, settings: Settings): Int {
        val value: Any? = settings.getAll()[key]
        if (value is Int) {
            return value
        }

        if (value is String) {
            try {
                return Integer.parseInt(value)
            } catch (e: NumberFormatException) {
                // ignore
            }
        }

        return defaultValue
    }

    private fun createListPref(
        context: Context,
        key: String,
        title: String,
        labels: Array<String?>,
        values: Array<String>,
        settings: Settings
    ): ListPreference {
        ensurePrefHasValidValue(key, values, settings)
        return ListPreference(context).also {
            it.key = key
            it.isPersistent = true
            it.title = title
            it.dialogTitle = title
            it.entries = labels
            it.entryValues = values
            it.summary = "%s"
        }
    }

    private fun ensurePrefHasValidValue(
        key: String,
        validValues: Array<String>,
        settings: Settings
    ) {
        val value = settings.getString(key)
        if (validValues.indexOf(value) < 0) {
            if (validValues.isNotEmpty()) {
                settings.save(key, validValues[0])
            } else {
                settings.remove(key)
            }
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ReturnToAppActivity.kt
================================================
package org.odk.collect.androidshared.ui

import android.app.Activity
import android.os.Bundle

/**
 * This Activity will close as soon as it is started. This means it can be used as the content
 * intent of a notification so clicking it will effectively return to the screen the user
 * was last on (knowing what that Activity was).
 */
class ReturnToAppActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        finish()
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/SnackbarUtils.kt
================================================
/*

Copyright 2018 Shobhit
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.odk.collect.androidshared.ui

import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.google.android.material.R
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import org.odk.collect.androidshared.data.Consumable

/**
 * Convenience wrapper around Android's [Snackbar] API.
 */
object SnackbarUtils {

    @JvmStatic
    val alertStore = AlertStore()

    const val DURATION_SHORT = 3500
    const val DURATION_LONG = 5500

    private var lastSnackbar: Snackbar? = null

    /**
     * Displays snackbar with {@param message} and multi-line message enabled.
     *
     * @param parentView            The view to find a parent from.
     * @param anchorView            The view this snackbar should be anchored above.
     * @param message               The text to show. Can be formatted text.
     * @param displayDismissButton  True if the dismiss button should be displayed, false otherwise.
     */
    @JvmStatic
    @JvmOverloads
    fun showSnackbar(
        parentView: View,
        message: String,
        duration: Int,
        anchorView: View? = null,
        action: Action? = null,
        displayDismissButton: Boolean = false,
        onDismiss: () -> Unit = {}
    ) {
        if (message.isBlank()) {
            return
        }

        val snackbar = make(
            parentView,
            message,
            duration,
            anchorView,
            action,
            displayDismissButton,
            onDismiss
        )

        show(snackbar)
    }

    fun show(snackbar: Snackbar) {
        if (snackbar != lastSnackbar) {
            lastSnackbar?.dismiss()
        }

        snackbar.show()

        lastSnackbar = snackbar
        val message = snackbar.view.findViewById<TextView>(R.id.snackbar_text).text.toString()
        alertStore.register(message)
    }

    fun make(
        parentView: View,
        message: String,
        duration: Int,
        anchorView: View? = null,
        action: Action? = null,
        displayDismissButton: Boolean = false,
        onDismiss: () -> Unit = {}
    ): Snackbar = Snackbar.make(parentView, message.trim(), duration).apply {
        val textView =
            view.findViewById<TextView>(R.id.snackbar_text)
        textView.isSingleLine = false

        if (anchorView?.visibility != View.GONE) {
            this.anchorView = anchorView
        }

        if (displayDismissButton) {
            view.findViewById<Button>(R.id.snackbar_action).let {
                val dismissButton = ImageView(view.context).apply {
                    setImageResource(org.odk.collect.androidshared.R.drawable.ic_close_24)
                    setOnClickListener {
                        dismiss()
                    }
                    contentDescription =
                        context.getString(org.odk.collect.strings.R.string.close_snackbar)
                }

                val params = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.MATCH_PARENT
                )
                params.setMargins(16, 0, 0, 0)

                (it.parent as ViewGroup).addView(dismissButton, params)
            }
        }

        if (action != null) {
            setAction(action.text) {
                action.beforeDismiss.invoke()
                dismiss()
            }
        }
    }.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
        override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
            super.onDismissed(transientBottomBar, event)
            onDismiss()
            lastSnackbar = null
        }
    })

    data class SnackbarDetails @JvmOverloads constructor(
        val text: String,
        val action: Action? = null
    )

    data class Action(val text: String, val beforeDismiss: () -> Unit = {})

    abstract class SnackbarPresenterObserver<T : Any?>(private val parentView: View) :
        Observer<Consumable<T>?> {

        abstract fun getSnackbarDetails(value: T): SnackbarDetails

        override fun onChanged(consumable: Consumable<T>?) {
            if (consumable != null && !consumable.isConsumed()) {
                showSnackbar(
                    parentView,
                    getSnackbarDetails(consumable.value).text,
                    DURATION_LONG,
                    action = getSnackbarDetails(consumable.value).action
                )
                consumable.consume()
            }
        }
    }

    fun <T : Any?> LiveData<Consumable<T>?>.showSnackbar(lifecycleOwner: LifecycleOwner, parentView: View, details: (T) -> SnackbarDetails) {
        observe(lifecycleOwner, object : SnackbarPresenterObserver<T>(parentView) {
            override fun getSnackbarDetails(value: T): SnackbarDetails {
                return details(value)
            }
        })
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/ToastUtils.kt
================================================
package org.odk.collect.androidshared.ui

import android.app.Activity
import android.app.Application
import android.os.Build
import android.view.Gravity
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.odk.collect.strings.localization.getLocalizedString

/**
 * Convenience wrapper around Android's [Toast] API.
 */
object ToastUtils {

    @JvmStatic
    val alertStore = AlertStore()

    private lateinit var lastToast: Toast
    private lateinit var application: Application

    @JvmStatic
    fun showShortToast(message: String) {
        showToast(message)
    }

    @JvmStatic
    fun showShortToast(messageResource: Int) {
        showToast(
            application.getLocalizedString(messageResource)
        )
    }

    @JvmStatic
    fun showLongToast(message: String) {
        showToast(message, Toast.LENGTH_LONG)
    }

    @JvmStatic
    fun showLongToast(messageResource: Int) {
        showToast(
            application.getLocalizedString(messageResource),
            Toast.LENGTH_LONG
        )
    }

    @JvmStatic
    @Deprecated("Toast position cannot be customized on API 30 and above. A dialog is shown instead for this API levels.")
    fun showShortToastInMiddle(activity: Activity, message: String) {
        showToastInMiddle(activity, message)
    }

    @JvmStatic
    fun setApplication(application: Application) {
        this.application = application
    }

    private fun showToast(
        message: String,
        duration: Int = Toast.LENGTH_SHORT
    ) {
        hideLastToast()
        lastToast = Toast.makeText(application, message, duration)
        lastToast.show()

        alertStore.register(message)
    }

    private fun showToastInMiddle(
        activity: Activity,
        message: String,
        duration: Int = Toast.LENGTH_SHORT
    ) {
        if (Build.VERSION.SDK_INT < 30) {
            hideLastToast()
            lastToast = Toast.makeText(activity.applicationContext, message, duration)
            try {
                val group = lastToast.view as ViewGroup?
                val messageTextView = group!!.getChildAt(0) as TextView
                messageTextView.textSize = 21f
                messageTextView.gravity = Gravity.CENTER
            } catch (ignored: Exception) {
                // ignored
            }
            lastToast.setGravity(Gravity.CENTER, 0, 0)
            lastToast.show()

            alertStore.register(message)
        } else {
            MaterialAlertDialogBuilder(activity)
                .setMessage(message)
                .setPositiveButton(org.odk.collect.strings.R.string.ok, null)
                .create()
                .show()
        }
    }

    private fun hideLastToast() {
        if (ToastUtils::lastToast.isInitialized) {
            lastToast.cancel()
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/compose/Margins.kt
================================================
package org.odk.collect.androidshared.ui.compose

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import org.odk.collect.androidshared.R.dimen

@Composable
fun marginStandard(): Dp {
    return dimensionResource(id = dimen.margin_standard)
}

@Composable
fun marginSmall(): Dp {
    return dimensionResource(id = dimen.margin_small)
}

@Composable
fun marginExtraSmall(): Dp {
    return dimensionResource(id = dimen.margin_extra_small)
}

================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/DoubleClickSafeMaterialButton.kt
================================================
package org.odk.collect.androidshared.ui.multiclicksafe

import android.content.Context
import android.util.AttributeSet
import com.google.android.material.button.MaterialButton

class DoubleClickSafeMaterialButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : MaterialButton(context, attrs, defStyleAttr) {

    override fun performClick(): Boolean {
        return allowClick() && super.performClick()
    }

    /**
     * Use [MultiClickGuard] with a scope unique to this object (class name + hash).
     */
    private fun allowClick(): Boolean {
        val scope = javaClass.name + hashCode()
        return MultiClickGuard.allowClick(scope)
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickGuard.kt
================================================
package org.odk.collect.androidshared.ui.multiclicksafe

import android.os.SystemClock

object MultiClickGuard {
    @JvmField
    var test = false

    private var lastClickTime: Long = 0
    private var lastClickName: String = javaClass.name

    @JvmStatic
    fun allowClickFast(className: String = javaClass.name): Boolean {
        return allowClick(className, 500)
    }

    /**
     * Debounce multiple clicks within the same scope
     *
     * @param scope If not provided, the Java class name of the element
     * is used. However, this approach is imperfect, as elements on the same screen might belong to
     * different classes. Consequently, clicks on these elements are treated as interactions occurring
     * on two distinct screens, not protecting from rapid clicking.
     */
    @JvmStatic
    @JvmOverloads
    fun allowClick(scope: String = javaClass.name, clickDebounceMs: Long = 1000): Boolean {
        if (test) {
            return true
        }
        val elapsedRealtime = SystemClock.elapsedRealtime()
        val isSameClass = scope == lastClickName
        val isBeyondThreshold = elapsedRealtime - lastClickTime > clickDebounceMs
        val isBeyondTestThreshold =
            lastClickTime == 0L || lastClickTime == elapsedRealtime // just for tests

        val allowClick = !isSameClass || isBeyondThreshold || isBeyondTestThreshold

        if (allowClick) {
            lastClickTime = elapsedRealtime
            lastClickName = scope
        }
        return allowClick
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSafeMaterialButton.kt
================================================
package org.odk.collect.androidshared.ui.multiclicksafe

import android.content.Context
import android.util.AttributeSet
import androidx.core.content.withStyledAttributes
import com.google.android.material.button.MaterialButton
import org.odk.collect.androidshared.R
import org.odk.collect.androidshared.ui.multiclicksafe.MultiClickGuard.allowClick

open class MultiClickSafeMaterialButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : MaterialButton(context, attrs, defStyleAttr) {
    private lateinit var screenName: String

    init {
        context.withStyledAttributes(attrs, R.styleable.MultiClickSafeMaterialButton) {
            screenName = getString(R.styleable.MultiClickSafeMaterialButton_screenName) ?: javaClass.name
        }
    }

    override fun performClick(): Boolean {
        return allowClick(screenName) && super.performClick()
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSafeTextInputEditText.kt
================================================
package org.odk.collect.androidshared.ui.multiclicksafe

import android.content.Context
import android.util.AttributeSet
import com.google.android.material.textfield.TextInputEditText
import org.odk.collect.androidshared.ui.multiclicksafe.MultiClickGuard.allowClick

class MultiClickSafeTextInputEditText : TextInputEditText {
    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(
        context,
        attrs
    )

    override fun performClick(): Boolean {
        return allowClick() && super.performClick()
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSaveOnClickListener.kt
================================================
package org.odk.collect.androidshared.ui.multiclicksafe

import android.view.View

abstract class MultiClickSafeOnClickListener : View.OnClickListener {

    abstract fun onSafeClick(v: View)

    override fun onClick(v: View) {
        if (MultiClickGuard.allowClick()) {
            onSafeClick(v)
        }
    }
}

fun View.setMultiClickSafeOnClickListener(listener: (View) -> Unit) {
    setOnClickListener(object : MultiClickSafeOnClickListener() {
        override fun onSafeClick(v: View) {
            listener(v)
        }
    })
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/AppBarUtils.kt
================================================
package org.odk.collect.androidshared.utils

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar

object AppBarUtils {

    @JvmStatic
    fun setupAppBarLayout(activity: Activity, title: CharSequence) {
        val toolbar = activity.findViewById<Toolbar>(org.odk.collect.androidshared.R.id.toolbar)
        if (toolbar != null && activity is AppCompatActivity) {
            toolbar.title = title
            activity.setSupportActionBar(toolbar)
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/ColorUtils.kt
================================================
package org.odk.collect.androidshared.utils

import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.toColorInt

@ColorInt
fun String.sanitizeToColorInt() = try {
    var sanitizedColor = if (this.startsWith("#")) {
        this
    } else {
        "#$this"
    }

    if (sanitizedColor.length == 4) {
        sanitizedColor = shorthandToLonghandHexColor(sanitizedColor)
    }

    sanitizedColor.toColorInt()
} catch (e: IllegalArgumentException) {
    null
}

fun Int.opaque(): Int {
    return ColorUtils.setAlphaComponent(this, 100)
}

private fun shorthandToLonghandHexColor(shorthandColor: String): String {
    return shorthandColor.substring(1).fold("#") { accum, char ->
        "$accum$char$char"
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/CompressionUtils.kt
================================================
/*
 * Copyright (C) 2017 Shobhit
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.odk.collect.androidshared.utils

import android.util.Base64
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.lang.IllegalArgumentException
import java.util.zip.DataFormatException
import java.util.zip.Deflater
import java.util.zip.Inflater

object CompressionUtils {

    @Throws(IOException::class)
    fun compress(data: String?): String {
        if (data == null || data.isEmpty()) {
            return ""
        }

        // Encode string into bytes
        val input = data.toByteArray(charset("UTF-8"))
        val deflater = Deflater()
        deflater.setInput(input)

        // Compress the bytes
        val outputStream = ByteArrayOutputStream(data.length)
        deflater.finish()
        val buffer = ByteArray(1024)
        while (!deflater.finished()) {
            val count = deflater.deflate(buffer) // returns the generated code... index
            outputStream.write(buffer, 0, count)
        }
        outputStream.close()
        val output = outputStream.toByteArray()

        // Encode to base64
        return Base64.encodeToString(output, Base64.NO_WRAP)
    }

    @Throws(
        IOException::class,
        DataFormatException::class,
        IllegalArgumentException::class
    )
    fun decompress(compressedString: String?): String {
        if (compressedString == null || compressedString.isEmpty()) {
            return ""
        }

        // Decode from base64
        val output = Base64.decode(compressedString, Base64.NO_WRAP)
        val inflater = Inflater()
        inflater.setInput(output)

        // Decompresses the bytes
        val outputStream = ByteArrayOutputStream(output.size)
        val buffer = ByteArray(1024)
        while (!inflater.finished()) {
            val count = inflater.inflate(buffer)
            outputStream.write(buffer, 0, count)
        }
        outputStream.close()
        inflater.end()
        val result = outputStream.toByteArray()

        // Decode the bytes into a String
        return String(result, charset("UTF-8"))
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/FileExt.kt
================================================
package org.odk.collect.androidshared.utils

import android.content.Context
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import androidx.core.net.toUri
import timber.log.Timber
import java.io.File

fun File.getVideoThumbnail(context: Context): Bitmap? {
    val retriever = MediaMetadataRetriever()
    return try {
        retriever.setDataSource(context, this.toUri())
        retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
    } catch (e: Exception) {
        Timber.w(e)
        null
    } finally {
        retriever.release()
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/InMemUniqueIdGenerator.kt
================================================
package org.odk.collect.androidshared.utils

import java.util.concurrent.atomic.AtomicInteger

class InMemUniqueIdGenerator() : UniqueIdGenerator {

    private val ids = mutableMapOf<String, Int>()
    private var next = AtomicInteger(1)

    override fun getInt(identifier: String): Int {
        return ids.getOrPut(identifier) { next.getAndIncrement() }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/PathUtils.kt
================================================
package org.odk.collect.androidshared.utils

import org.odk.collect.shared.files.FileExt.sanitizedCanonicalPath
import timber.log.Timber
import java.io.File
import java.io.IOException

object PathUtils {
    @JvmStatic
    fun getAbsoluteFilePath(dirPath: String, filePath: String): String {
        val absoluteFilePath =
            if (filePath.startsWith(dirPath)) filePath else dirPath + File.separator + filePath

        val absoluteFile = File(absoluteFilePath)
        return try {
            if (absoluteFile.sanitizedCanonicalPath().startsWith(File(dirPath).sanitizedCanonicalPath())) {
                absoluteFilePath
            } else {
                throw SecurityException("Contact support@getodk.org. Attempt to access file outside of Collect directory: $absoluteFilePath")
            }
        } catch (e: IOException) {
            Timber.e(
                "Failed attempt to access canonicalPath:\n" +
                    "dirPath: $dirPath\n" +
                    "filePath: $filePath\n" +
                    "absoluteFilePath: $absoluteFilePath\n" +
                    "absoluteFilePath exists: ${absoluteFile.exists()}\n"
            )
            absoluteFilePath
        }
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/PreferenceFragmentCompatUtils.kt
================================================
package org.odk.collect.androidshared.utils

import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat

fun <T : Preference> PreferenceFragmentCompat.getPreference(key: String): T {
    return this.findPreference(key)!!
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/ScreenUtils.java
================================================
/*
 * Copyright 2019 Nafundi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.odk.collect.androidshared.utils;

import android.content.Context;
import android.content.res.Configuration;
import android.util.DisplayMetrics;

public class ScreenUtils {

    private final Context context;

    public ScreenUtils(Context context) {
        this.context = context;
    }

    public static int getScreenWidth(Context context) {
        return getDisplayMetrics(context).widthPixels;
    }

    public static int getScreenHeight(Context context) {
        return getDisplayMetrics(context).heightPixels;
    }

    public static float xdpi(Context context) {
        return getDisplayMetrics(context).xdpi;
    }

    public static float ydpi(Context context) {
        return getDisplayMetrics(context).ydpi;
    }

    private static DisplayMetrics getDisplayMetrics(Context context) {
        return context.getResources().getDisplayMetrics();
    }

    public int getScreenSizeConfiguration() {
        return context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/SettingsUniqueIdGenerator.kt
================================================
package org.odk.collect.androidshared.utils

import org.odk.collect.shared.settings.Settings

class SettingsUniqueIdGenerator(private val settings: Settings) : UniqueIdGenerator {

    override fun getInt(identifier: String): Int {
        return synchronized(this) {
            val identifierKey = identifierKey(identifier)

            if (settings.contains(identifierKey)) {
                settings.getInt(identifierKey)
            } else {
                val next = getNextInt()
                settings.save(identifierKey, next)
                next
            }
        }
    }

    private fun getNextInt(): Int {
        val next = if (settings.contains(NEXT_ID_KEY)) {
            settings.getInt(NEXT_ID_KEY)
        } else {
            1
        }

        settings.save(NEXT_ID_KEY, next + 1)
        return next
    }

    companion object {
        private const val KEY_PREFIX = "uniqueId"
        private const val NEXT_ID_KEY = "$KEY_PREFIX:next"
        private fun identifierKey(identifier: String) = "$KEY_PREFIX:identifier:$identifier"
    }
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/UniqueIdGenerator.kt
================================================
package org.odk.collect.androidshared.utils

interface UniqueIdGenerator {
    fun getInt(identifier: String): Int
}


================================================
FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/Validator.kt
================================================
/*
 * Copyright 2016 Nafundi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.odk.collect.androidshared.utils

import android.util.Patterns
import android.webkit.URLUtil
import java.util.regex.Pattern

object Validator {
    /*
    There are lots of ways to validate email addresses and it's hard to find one perfect.
    That's why we use here a very simple approach just to confirm that passed string contains:
        -any number of characters before @ (at least one)
        -one @ char
        -any number of characters after @ (at least one)
     */
    @JvmStatic
    fun isEmailAddressValid(emailAddress: String): Boolean {
        return Pattern
            .compile(".+@.+")
            .matcher(emailAddress)
            .matches()
    }

    @JvmStatic
    fun isUrlValid(url: String): Boolean {
        return URLUtil.isValidUrl(url) && Patterns.WEB_URL.matcher(url).matches()
    }
}


================================================
FILE: androidshared/src/main/res/color/color_error_button_icon.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="?colorError" android:state_enabled="true"/>
    <item android:alpha="@dimen/material_emphasis_disabled_background" android:color="?colorOnSurface"/>
</selector>

================================================
FILE: androidshared/src/main/res/color/color_on_primary_low_emphasis.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<!--
Provides a medium emphasis version of the `colorOnPrimary` Material Theming attribute (found
here: https://m3.material.io/styles/color/the-color-system/tokens#7fd4440e-986d-443f-8b3a-4933bff16646).
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/low_emphasis" android:color="?attr/colorOnPrimary" />
</selector>


================================================
FILE: androidshared/src/main/res/color/color_on_surface_high_emphasis.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<!--
Provides a medium emphasis version of the `colorOnSurface` Material Theming attribute (found
here: https://material.io/develop/android/theming/typography/). Material Themes suggest using
different emphasis/transparency values on text but Android doesn't have a way to set this on a
`TextView` itself.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/high_emphasis" android:color="?attr/colorOnSurface" />
</selector>


================================================
FILE: androidshared/src/main/res/color/color_on_surface_low_emphasis.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<!--
Provides a medium emphasis version of the `colorOnSurface` Material Theming attribute (found
here: https://material.io/develop/android/theming/typography/). Material Themes suggest using
different emphasis/transparency values on text but Android doesn't have a way to set this on a
`TextView` itself.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/low_emphasis" android:color="?attr/colorOnSurface" />
</selector>


================================================
FILE: androidshared/src/main/res/color/color_on_surface_medium_emphasis.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<!--
Provides a medium emphasis version of the `colorOnSurface` Material Theming attribute (found
here: https://material.io/develop/android/theming/typography/). Material Themes suggest using
different emphasis/transparency values on text but Android doesn't have a way to set this on a
`TextView` itself.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/medium_emphasis" android:color="?attr/colorOnSurface" />
</selector>


================================================
FILE: androidshared/src/main/res/color/color_primary_low_emphasis.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<!--
Provides a medium emphasis version of the `colorPrimary` Material Theming attribute (found
here: https://material.io/develop/android/theming/typography/). Material Themes suggest using
different emphasis/transparency values on text but Android doesn't have a way to set this on a
`TextView` itself.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/low_emphasis" android:color="?attr/colorPrimary" />
</selector>


================================================
FILE: androidshared/src/main/res/drawable/color_circle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" />

================================================
FILE: androidshared/src/main/res/drawable/ic_close_24.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24"
    android:viewportWidth="24"
    android:tint="?colorSurface">
    <path
        android:fillColor="?colorSurface"
        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>


================================================
FILE: androidshared/src/main/res/drawable/list_item_divider.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Material Design reference: https://material.io/design/components/dividers.html#specs -->

    <item>
        <shape android:shape="rectangle">
            <size android:height="1dp" />
            <solid android:color="@color/color_on_surface_low_emphasis"/>
        </shape>
    </item>

</layer-list>


================================================
FILE: androidshared/src/main/res/drawable/radio_button_inset.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="?android:attr/listChoiceIndicatorSingle"
    android:insetLeft="11dp"
    android:insetRight="@dimen/margin_standard"/>

================================================
FILE: androidshared/src/main/res/drawable/shadow_up.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape
            android:dither="true"
            android:shape="rectangle">
            <gradient
                android:angle="270"
                android:endColor="#22000000"
                android:startColor="#00000000"/>

            <size android:height="10dp"/>
        </shape>
    </item>
</layer-list>



================================================
FILE: androidshared/src/main/res/layout/app_bar_layout.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
     When scrolling, the top app bar fills with a contrasting color to create a visual separation.
     This works automatically if your scrolling view (e.g., `RecyclerView`, `ListView`) is placed directly
     beneath the `AppBarLayout`. However, if the scrolling view is nested within another view
     (such as a `ConstraintLayout`, which is common in this app), you need to help the app bar determine
     whether it should lift by setting `app:liftOnScrollTargetViewId` to the ID of the scrolling view.
     Since this `AppBarLayout` is used throughout the app with various scrolling views, it’s best to
     use a shared ID like `scrollable_container`.
     If the scrollable view is added programmatically or it is displayed in a `ViewPager` with a
     shared id, it may not work as expected anyway, and `app:liftOnScrollTargetViewId` might
     need to be updated programmatically after adding such a view.
     The `ODKView` and its `odk_view_container` or `DeleteFormsActivity` are good examples of this scenario.
-->
<com.google.android.material.appbar.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/appBarLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:liftOnScrollTargetViewId="@+id/scrollable_container">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:title="Title" />

        <org.odk.collect.androidshared.ui.ObviousProgressBar
            android:id="@+id/progressBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>


================================================
FILE: androidshared/src/main/res/layout/color_picker_dialog_layout.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/margin_standard">

        <!-- 1st row -->
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color1"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color1" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color1"
            app:layout_constraintTop_toTopOf="parent" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color2" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color3"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color2"
            app:layout_constraintTop_toTopOf="parent" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color3" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color4"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color3"
            app:layout_constraintTop_toTopOf="parent" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color4" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color5"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color4"
            app:layout_constraintTop_toTopOf="parent" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color5" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <!-- 2nd row -->
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color6"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/color1" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color6" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color7"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color6"
            app:layout_constraintTop_toBottomOf="@id/color2" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color7" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color8"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color7"
            app:layout_constraintTop_toBottomOf="@id/color3" >

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/color_circle"
                android:backgroundTint="@color/color8" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/color9"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/margin_extra_small"
            android:background="?attr/selectableItemBackgroundBorderless"
            app:layout_constraintWidth_percent="0.2"
            app:layout_constraintDimensionRatio="w,1:1"
            app:layout_constraintStart_toEndOf="@id/color8"
            app:layout_constraintTop_toBottomOf="@id/color4" >

      
Download .txt
Showing preview only (215K chars total). Download the full file or copy to clipboard to get everything.
gitextract_2lkczetw/

├── .circleci/
│   ├── config.yml
│   ├── generate-app-test-list.sh
│   ├── gradle-large.properties
│   ├── gradle.properties
│   └── test_modules.txt
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── ISSUE_TEMPLATE/
│   │   └── config.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── TESTING_RESULT_TEMPLATES.md
├── .gitignore
├── .hgtags
├── LICENSE.md
├── README.md
├── SECURITY.md
├── analytics/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── analytics/
│                               ├── Analytics.kt
│                               ├── BlockableFirebaseAnalytics.kt
│                               └── NoopAnalytics.kt
├── androidshared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── androidshared/
│       │                       └── bitmap/
│       │                           ├── ImageCompressorTest.kt
│       │                           └── ImageFileUtilsTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── androidshared/
│       │   │                   ├── async/
│       │   │                   │   └── TrackableWorker.kt
│       │   │                   ├── bitmap/
│       │   │                   │   ├── ImageCompressor.kt
│       │   │                   │   └── ImageFileUtils.kt
│       │   │                   ├── data/
│       │   │                   │   ├── AppState.kt
│       │   │                   │   ├── Consumable.kt
│       │   │                   │   └── Data.kt
│       │   │                   ├── livedata/
│       │   │                   │   ├── LiveDataExt.kt
│       │   │                   │   ├── LiveDataUtils.java
│       │   │                   │   └── NonNullLiveData.kt
│       │   │                   ├── system/
│       │   │                   │   ├── BroadcastReceiverRegister.kt
│       │   │                   │   ├── CameraUtils.java
│       │   │                   │   ├── ContextExt.kt
│       │   │                   │   ├── ExternalFilesUtils.kt
│       │   │                   │   ├── IntentLauncher.kt
│       │   │                   │   ├── OpenGLVersionChecker.kt
│       │   │                   │   ├── PlayServicesChecker.java
│       │   │                   │   ├── ProcessRestoreDetector.kt
│       │   │                   │   └── UriExt.kt
│       │   │                   ├── ui/
│       │   │                   │   ├── AlertStore.kt
│       │   │                   │   ├── Animations.kt
│       │   │                   │   ├── ColorPickerDialog.kt
│       │   │                   │   ├── ComposeThemeProvider.kt
│       │   │                   │   ├── DialogFragmentUtils.kt
│       │   │                   │   ├── DialogUtils.kt
│       │   │                   │   ├── DisplayString.kt
│       │   │                   │   ├── EdgeToEdge.kt
│       │   │                   │   ├── FragmentFactoryBuilder.kt
│       │   │                   │   ├── GroupClickListener.kt
│       │   │                   │   ├── ListFragmentStateAdapter.kt
│       │   │                   │   ├── MenuExt.kt
│       │   │                   │   ├── ObviousProgressBar.kt
│       │   │                   │   ├── OneSignTextWatcher.kt
│       │   │                   │   ├── PrefUtils.kt
│       │   │                   │   ├── ReturnToAppActivity.kt
│       │   │                   │   ├── SnackbarUtils.kt
│       │   │                   │   ├── ToastUtils.kt
│       │   │                   │   ├── compose/
│       │   │                   │   │   └── Margins.kt
│       │   │                   │   └── multiclicksafe/
│       │   │                   │       ├── DoubleClickSafeMaterialButton.kt
│       │   │                   │       ├── MultiClickGuard.kt
│       │   │                   │       ├── MultiClickSafeMaterialButton.kt
│       │   │                   │       ├── MultiClickSafeTextInputEditText.kt
│       │   │                   │       └── MultiClickSaveOnClickListener.kt
│       │   │                   └── utils/
│       │   │                       ├── AppBarUtils.kt
│       │   │                       ├── ColorUtils.kt
│       │   │                       ├── CompressionUtils.kt
│       │   │                       ├── FileExt.kt
│       │   │                       ├── InMemUniqueIdGenerator.kt
│       │   │                       ├── PathUtils.kt
│       │   │                       ├── PreferenceFragmentCompatUtils.kt
│       │   │                       ├── ScreenUtils.java
│       │   │                       ├── SettingsUniqueIdGenerator.kt
│       │   │                       ├── UniqueIdGenerator.kt
│       │   │                       └── Validator.kt
│       │   └── res/
│       │       ├── color/
│       │       │   ├── color_error_button_icon.xml
│       │       │   ├── color_on_primary_low_emphasis.xml
│       │       │   ├── color_on_surface_high_emphasis.xml
│       │       │   ├── color_on_surface_low_emphasis.xml
│       │       │   ├── color_on_surface_medium_emphasis.xml
│       │       │   └── color_primary_low_emphasis.xml
│       │       ├── drawable/
│       │       │   ├── color_circle.xml
│       │       │   ├── ic_close_24.xml
│       │       │   ├── list_item_divider.xml
│       │       │   ├── radio_button_inset.xml
│       │       │   └── shadow_up.xml
│       │       ├── layout/
│       │       │   ├── app_bar_layout.xml
│       │       │   └── color_picker_dialog_layout.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── color_picker_dialog_colors.xml
│       │           ├── dimens.xml
│       │           └── styles.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── androidshared/
│           │                   ├── async/
│           │                   │   └── TrackableWorkerTest.kt
│           │                   ├── livedata/
│           │                   │   └── LiveDataUtilsTest.kt
│           │                   ├── system/
│           │                   │   └── UriExtTest.kt
│           │                   ├── ui/
│           │                   │   ├── ColorPickerDialogTest.kt
│           │                   │   ├── OneSignTextWatcherTest.kt
│           │                   │   └── ReturnToAppActivityTest.kt
│           │                   └── utils/
│           │                       ├── ColorUtilsTest.kt
│           │                       ├── CompressionUtilsTest.kt
│           │                       ├── DialogFragmentUtilsTest.java
│           │                       ├── InMemUniqueIdGeneratorTest.kt
│           │                       ├── IntentLauncherImplTest.kt
│           │                       ├── PathUtilsTest.kt
│           │                       ├── SettingsUniqueIdGeneratorTest.kt
│           │                       ├── UniqueIdGeneratorTest.kt
│           │                       └── ValidatorTest.kt
│           └── resources/
│               └── robolectric.properties
├── androidtest/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── androidtest/
│                               ├── ActivityScenarioExtensions.kt
│                               ├── ActivityScenarioLauncherRule.kt
│                               ├── DrawableMatcher.kt
│                               ├── FakeLifecycleOwner.kt
│                               ├── FragmentScenarioExtensions.kt
│                               ├── LiveDataTestUtils.kt
│                               ├── MainDispatcherRule.kt
│                               ├── NodeInteractionExtensions.kt
│                               └── RecordedIntentsRule.kt
├── async/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── async/
│       │                       ├── Cancellable.kt
│       │                       ├── OngoingWorkListener.kt
│       │                       ├── Scheduler.kt
│       │                       ├── SchedulerAsyncTaskMimic.kt
│       │                       ├── SchedulerBuilder.kt
│       │                       ├── ScopeCancellable.kt
│       │                       ├── TaskRunner.kt
│       │                       ├── TaskSpec.kt
│       │                       ├── TaskSpecRunner.kt
│       │                       ├── TaskSpecScheduler.kt
│       │                       ├── coroutines/
│       │                       │   └── CoroutineTaskRunner.kt
│       │                       ├── network/
│       │                       │   ├── ConnectivityProvider.kt
│       │                       │   └── NetworkStateProvider.kt
│       │                       ├── services/
│       │                       │   └── ForegroundServiceTaskSpecRunner.kt
│       │                       └── workmanager/
│       │                           ├── TaskSpecWorker.kt
│       │                           └── WorkManagerTaskSpecScheduler.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── async/
│                               ├── TaskSpecTest.kt
│                               └── workmanager/
│                                   └── TaskSpecWorkerTest.kt
├── audio-clips/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── audioclips/
│       │                       ├── AudioClipViewModel.kt
│       │                       ├── AudioPlayer.kt
│       │                       ├── AudioPlayerFactory.kt
│       │                       ├── Clip.kt
│       │                       ├── PlaybackFailedException.kt
│       │                       └── ThreadSafeMediaPlayerWrapper.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── audioclips/
│                               └── AudioClipViewModelTest.kt
├── audio-recorder/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── audiorecorder/
│       │                       ├── DaggerSetup.kt
│       │                       ├── mediarecorder/
│       │                       │   └── MediaRecorderRecordingResource.kt
│       │                       ├── recorder/
│       │                       │   ├── Recorder.kt
│       │                       │   ├── RecordingResource.kt
│       │                       │   └── RecordingResourceRecorder.kt
│       │                       ├── recording/
│       │                       │   ├── AudioRecorder.kt
│       │                       │   ├── AudioRecorderFactory.kt
│       │                       │   ├── AudioRecorderService.kt
│       │                       │   └── internal/
│       │                       │       ├── ForegroundServiceAudioRecorder.kt
│       │                       │       ├── RecordingForegroundServiceNotification.kt
│       │                       │       └── RecordingRepository.kt
│       │                       └── testsupport/
│       │                           └── StubAudioRecorder.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── audiorecorder/
│           │                   ├── mediarecorder/
│           │                   │   └── AMRRecordingResourceTest.kt
│           │                   ├── recorder/
│           │                   │   └── RecordingResourceRecorderTest.kt
│           │                   ├── recording/
│           │                   │   ├── AudioRecorderTest.kt
│           │                   │   └── internal/
│           │                   │       ├── AudioRecorderServiceTest.kt
│           │                   │       ├── ForegroundServiceAudioRecorderTest.kt
│           │                   │       └── RecordingForegroundServiceNotificationTest.kt
│           │                   ├── support/
│           │                   │   └── FakeRecorder.kt
│           │                   └── testsupport/
│           │                       ├── RobolectricApplication.kt
│           │                       └── StubAudioRecorderTest.kt
│           └── resources/
│               └── robolectric.properties
├── benchmark.sh
├── build.gradle
├── check-size.sh
├── codecov.yml
├── collect_app/
│   ├── build.gradle
│   ├── google-services.json
│   ├── libs/
│   │   └── bikram-sambat-1.8.0.jar
│   ├── proguard-rules.txt
│   └── src/
│       ├── androidTest/
│       │   ├── assets/
│       │   │   └── instances/
│       │   │       ├── One Question_2021-06-22_15-55-50.xml
│       │   │       └── one-question-google_2023-08-08_14-51-00.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── android/
│       │                       ├── benchmark/
│       │                       │   ├── EntitiesBenchmarkTest.kt
│       │                       │   ├── FormsUpdateBenchmarkTest.kt
│       │                       │   ├── SearchBenchmarkTest.kt
│       │                       │   └── support/
│       │                       │       └── Benchmarker.kt
│       │                       ├── feature/
│       │                       │   ├── entitymanagement/
│       │                       │   │   └── ViewEntitiesTest.kt
│       │                       │   ├── external/
│       │                       │   │   ├── AndroidShortcutsTest.kt
│       │                       │   │   ├── FormDownloadActionTest.kt
│       │                       │   │   ├── FormEditActionTest.kt
│       │                       │   │   ├── FormPickActionTest.kt
│       │                       │   │   ├── InstanceEditActionTest.kt
│       │                       │   │   ├── InstancePickActionTest.kt
│       │                       │   │   └── InstanceUploadActionTest.kt
│       │                       │   ├── formentry/
│       │                       │   │   ├── AddRepeatTest.kt
│       │                       │   │   ├── AudioAutoplayTest.kt
│       │                       │   │   ├── AudioRecordingTest.java
│       │                       │   │   ├── BackgroundAudioRecordingTest.java
│       │                       │   │   ├── CascadingSelectTest.kt
│       │                       │   │   ├── CatchFormDesignExceptionsTest.kt
│       │                       │   │   ├── ContextMenuTest.java
│       │                       │   │   ├── DeletingRepeatGroupsTest.java
│       │                       │   │   ├── EncryptedFormTest.kt
│       │                       │   │   ├── ExternalAudioRecordingTest.java
│       │                       │   │   ├── ExternalSecondaryInstanceTest.java
│       │                       │   │   ├── ExternalSelectsTest.kt
│       │                       │   │   ├── FieldListUpdateTest.kt
│       │                       │   │   ├── FillBlankFormWithRepeatGroupTest.kt
│       │                       │   │   ├── FormEndTest.kt
│       │                       │   │   ├── FormHierarchyTest.java
│       │                       │   │   ├── FormLanguageTest.java
│       │                       │   │   ├── FormMediaTest.kt
│       │                       │   │   ├── FormMetadataTest.kt
│       │                       │   │   ├── FormNavigationTest.kt
│       │                       │   │   ├── FormSaveTest.kt
│       │                       │   │   ├── FormStylingTest.kt
│       │                       │   │   ├── GuidanceTest.kt
│       │                       │   │   ├── ImageLoadingTest.kt
│       │                       │   │   ├── IntentGroupTest.kt
│       │                       │   │   ├── InvalidFormTest.kt
│       │                       │   │   ├── LikertTest.java
│       │                       │   │   ├── NestedIntentGroupTest.kt
│       │                       │   │   ├── QuickSaveTest.java
│       │                       │   │   ├── QuittingFormTest.java
│       │                       │   │   ├── RankingWidgetWithCSVTest.java
│       │                       │   │   ├── RequiredAndConstraintQuestionTest.kt
│       │                       │   │   ├── SaveIncompleteTest.kt
│       │                       │   │   ├── SavePointTest.kt
│       │                       │   │   ├── SearchAppearancesTest.kt
│       │                       │   │   ├── audit/
│       │                       │   │   │   ├── AuditTest.kt
│       │                       │   │   │   ├── IdentifyUserTest.kt
│       │                       │   │   │   └── TrackChangesReasonTest.kt
│       │                       │   │   ├── backgroundlocation/
│       │                       │   │   │   ├── LocationTrackingAuditTest.java
│       │                       │   │   │   └── SetGeopointActionTest.java
│       │                       │   │   ├── dynamicpreload/
│       │                       │   │   │   ├── DynamicPreLoadedDataPullTest.kt
│       │                       │   │   │   └── DynamicPreLoadedDataSelects.java
│       │                       │   │   └── entities/
│       │                       │   │       ├── EntityFormApprovalTest.kt
│       │                       │   │       ├── EntityFormCreateUpdateTest.kt
│       │                       │   │       ├── EntityFormEditTest.kt
│       │                       │   │       ├── EntityFormLockingTest.kt
│       │                       │   │       ├── EntityFormSpecVersionTest.kt
│       │                       │   │       └── EntityListSyncTest.kt
│       │                       │   ├── formmanagement/
│       │                       │   │   ├── BulkFinalizationTest.kt
│       │                       │   │   ├── DeleteBlankFormTest.java
│       │                       │   │   ├── FormUpdateTest.kt
│       │                       │   │   ├── FormsAdbTest.java
│       │                       │   │   ├── GetBlankFormsTest.java
│       │                       │   │   ├── HideOldVersionsTest.java
│       │                       │   │   ├── ManualUpdatesTest.java
│       │                       │   │   ├── MatchExactlyTest.kt
│       │                       │   │   └── PreviouslyDownloadedOnlyTest.kt
│       │                       │   ├── instancemanagement/
│       │                       │   │   ├── AutoSendTest.kt
│       │                       │   │   ├── DeleteSavedFormTest.kt
│       │                       │   │   ├── EditSavedFormTest.kt
│       │                       │   │   ├── InstancesAdbTest.kt
│       │                       │   │   ├── PartialSubmissionTest.kt
│       │                       │   │   └── SendFinalizedFormTest.kt
│       │                       │   ├── maps/
│       │                       │   │   └── FormMapTest.kt
│       │                       │   ├── projects/
│       │                       │   │   ├── AddNewProjectTest.kt
│       │                       │   │   ├── DeleteProjectTest.kt
│       │                       │   │   ├── GoogleDriveDeprecationTest.kt
│       │                       │   │   ├── LaunchScreenTest.kt
│       │                       │   │   ├── MobileDeviceManagementTest.kt
│       │                       │   │   ├── ProjectsAdbTest.kt
│       │                       │   │   ├── SwitchProjectTest.kt
│       │                       │   │   └── UpdateProjectTest.kt
│       │                       │   ├── settings/
│       │                       │   │   ├── ConfigureWithQRCodeTest.java
│       │                       │   │   ├── FormEntrySettingsTest.kt
│       │                       │   │   ├── FormManagementSettingsTest.kt
│       │                       │   │   ├── FormMetadataSettingsTest.kt
│       │                       │   │   ├── MovingBackwardsTest.kt
│       │                       │   │   ├── ResetProjectTest.kt
│       │                       │   │   ├── ServerSettingsTest.java
│       │                       │   │   └── SettingLanguageTest.kt
│       │                       │   └── smoke/
│       │                       │       ├── AllWidgetsFormTest.kt
│       │                       │       ├── BadServerTest.java
│       │                       │       └── GetAndSubmitFormTest.java
│       │                       ├── instrumented/
│       │                       │   ├── forms/
│       │                       │   │   └── FormUtilsTest.java
│       │                       │   ├── tasks/
│       │                       │   │   └── FormLoaderTaskTest.java
│       │                       │   └── utilities/
│       │                       │       ├── CustomSQLiteQueryExecutionTest.java
│       │                       │       └── DateTimeUtilsTest.java
│       │                       └── support/
│       │                           ├── ActivityHelpers.java
│       │                           ├── CollectHelpers.kt
│       │                           ├── ContentProviderUtils.kt
│       │                           ├── CountingTaskExecutorIdlingResource.java
│       │                           ├── DummyActivityLauncher.kt
│       │                           ├── FakeClickableMapFragment.kt
│       │                           ├── FakeLocationClient.java
│       │                           ├── FakeNetworkStateProvider.kt
│       │                           ├── StorageUtils.kt
│       │                           ├── StubOpenRosaServer.kt
│       │                           ├── SubmissionParser.kt
│       │                           ├── TestDependencies.kt
│       │                           ├── TranslatedStringBuilder.kt
│       │                           ├── actions/
│       │                           │   └── RotateAction.java
│       │                           ├── async/
│       │                           │   ├── AsyncWorkTracker.kt
│       │                           │   ├── AsyncWorkTrackerIdlingResource.kt
│       │                           │   ├── TrackingCoroutineAndWorkManagerScheduler.kt
│       │                           │   └── TrackingCoroutineDispatcher.kt
│       │                           ├── matchers/
│       │                           │   ├── CustomMatchers.kt
│       │                           │   └── ToastMatcher.java
│       │                           ├── pages/
│       │                           │   ├── AboutPage.java
│       │                           │   ├── AccessControlPage.kt
│       │                           │   ├── AddNewRepeatDialog.kt
│       │                           │   ├── AppClosedPage.kt
│       │                           │   ├── AsyncPage.kt
│       │                           │   ├── BlankFormSearchPage.java
│       │                           │   ├── BulkFinalizationConfirmationDialogPage.kt
│       │                           │   ├── CancelRecordingDialog.java
│       │                           │   ├── ChangesReasonPromptPage.java
│       │                           │   ├── DeleteSavedFormPage.java
│       │                           │   ├── DeleteSelectedDialog.java
│       │                           │   ├── EditSavedFormPage.java
│       │                           │   ├── EntitiesPage.kt
│       │                           │   ├── EntityListPage.kt
│       │                           │   ├── ErrorDialog.kt
│       │                           │   ├── ErrorPage.kt
│       │                           │   ├── ExperimentalPage.java
│       │                           │   ├── FillBlankFormPage.java
│       │                           │   ├── FirstLaunchPage.kt
│       │                           │   ├── FormEndPage.java
│       │                           │   ├── FormEntryPage.java
│       │                           │   ├── FormHierarchyPage.kt
│       │                           │   ├── FormManagementPage.java
│       │                           │   ├── FormMapPage.java
│       │                           │   ├── FormMetadataPage.java
│       │                           │   ├── FormsDownloadResultPage.kt
│       │                           │   ├── GetBlankFormPage.java
│       │                           │   ├── IdentifyUserPromptPage.java
│       │                           │   ├── ListPreferenceDialog.java
│       │                           │   ├── MainMenuPage.java
│       │                           │   ├── MainMenuSettingsPage.kt
│       │                           │   ├── ManualProjectCreatorDialogPage.kt
│       │                           │   ├── MapsSettingsPage.java
│       │                           │   ├── NotificationDrawer.kt
│       │                           │   ├── OkDialog.java
│       │                           │   ├── OpenSourceLicensesPage.java
│       │                           │   ├── Page.kt
│       │                           │   ├── PreferencePage.java
│       │                           │   ├── ProjectDisplayPage.kt
│       │                           │   ├── ProjectManagementPage.kt
│       │                           │   ├── ProjectSettingsDialogPage.kt
│       │                           │   ├── ProjectSettingsPage.java
│       │                           │   ├── QRCodePage.java
│       │                           │   ├── QrCodeProjectCreatorDialogPage.kt
│       │                           │   ├── ResetApplicationDialog.java
│       │                           │   ├── SaveOrDiscardFormDialog.kt
│       │                           │   ├── SaveOrIgnoreDrawingDialog.kt
│       │                           │   ├── SavepointRecoveryDialogPage.kt
│       │                           │   ├── SelectMinimalDialogPage.kt
│       │                           │   ├── SendFinalizedFormPage.kt
│       │                           │   ├── ServerAuthDialog.java
│       │                           │   ├── ServerSettingsPage.java
│       │                           │   ├── ShortcutsPage.java
│       │                           │   ├── UserAndDeviceIdentitySettingsPage.java
│       │                           │   ├── UserInterfacePage.java
│       │                           │   ├── ViewFormPage.kt
│       │                           │   └── ViewSentFormPage.java
│       │                           └── rules/
│       │                               ├── BlankFormTestRule.kt
│       │                               ├── CollectTestRule.kt
│       │                               ├── FormEntryActivityTestRule.kt
│       │                               ├── IdlingResourceRule.kt
│       │                               ├── NotificationDrawerRule.kt
│       │                               ├── PageComposeRule.kt
│       │                               ├── PrepDeviceForTestsRule.kt
│       │                               ├── RecentAppsRule.kt
│       │                               ├── ResetRotationRule.kt
│       │                               ├── ResetStateRule.kt
│       │                               ├── RetryOnDeviceErrorRule.kt
│       │                               ├── RunnableRule.kt
│       │                               └── TestRuleChain.kt
│       ├── debug/
│       │   ├── AndroidManifest.xml
│       │   └── google-services.json
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── svg_map_helper.js
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               ├── android/
│       │   │               │   ├── activities/
│       │   │               │   │   ├── AboutActivity.kt
│       │   │               │   │   ├── ActivityUtils.java
│       │   │               │   │   ├── AppListActivity.java
│       │   │               │   │   ├── BearingActivity.java
│       │   │               │   │   ├── CrashHandlerActivity.kt
│       │   │               │   │   ├── DeleteFormsActivity.kt
│       │   │               │   │   ├── FirstLaunchActivity.kt
│       │   │               │   │   ├── FormDownloadListActivity.java
│       │   │               │   │   ├── FormEntryViewModelFactory.kt
│       │   │               │   │   ├── FormFillingActivity.java
│       │   │               │   │   ├── FormListActivity.java
│       │   │               │   │   ├── FormMapActivity.kt
│       │   │               │   │   ├── InstanceChooserList.java
│       │   │               │   │   ├── ScannerWithFlashlightActivity.kt
│       │   │               │   │   └── viewmodels/
│       │   │               │   │       └── FormDownloadListViewModel.java
│       │   │               │   ├── adapters/
│       │   │               │   │   ├── AboutListAdapter.kt
│       │   │               │   │   ├── AbstractSelectListAdapter.java
│       │   │               │   │   ├── FormDownloadListAdapter.java
│       │   │               │   │   ├── InstanceListCursorAdapter.java
│       │   │               │   │   ├── InstanceUploaderAdapter.java
│       │   │               │   │   ├── RankingListAdapter.java
│       │   │               │   │   ├── SelectMultipleListAdapter.java
│       │   │               │   │   └── SelectOneListAdapter.java
│       │   │               │   ├── analytics/
│       │   │               │   │   ├── AnalyticsEvents.kt
│       │   │               │   │   └── AnalyticsUtils.kt
│       │   │               │   ├── application/
│       │   │               │   │   ├── Collect.java
│       │   │               │   │   ├── CollectSettingsChangeHandler.kt
│       │   │               │   │   ├── ComposeTheme.kt
│       │   │               │   │   ├── FeatureFlags.kt
│       │   │               │   │   ├── MapboxClassInstanceCreator.kt
│       │   │               │   │   └── initialization/
│       │   │               │   │       ├── AnalyticsInitializer.kt
│       │   │               │   │       ├── ApplicationInitializer.kt
│       │   │               │   │       ├── CachedFormsCleaner.kt
│       │   │               │   │       ├── CrashReportingTree.kt
│       │   │               │   │       ├── ExistingProjectMigrator.kt
│       │   │               │   │       ├── ExistingSettingsMigrator.kt
│       │   │               │   │       ├── GoogleDriveProjectsDeleter.kt
│       │   │               │   │       ├── JavaRosaInitializer.kt
│       │   │               │   │       ├── MapsInitializer.kt
│       │   │               │   │       ├── SavepointsImporter.kt
│       │   │               │   │       ├── ScheduledWorkUpgrade.kt
│       │   │               │   │       ├── UserPropertiesInitializer.kt
│       │   │               │   │       └── upgrade/
│       │   │               │   │           ├── BeforeProjectsInstallDetector.kt
│       │   │               │   │           └── UpgradeInitializer.kt
│       │   │               │   ├── audio/
│       │   │               │   │   ├── AMRAppender.java
│       │   │               │   │   ├── AudioButton.java
│       │   │               │   │   ├── AudioControllerView.java
│       │   │               │   │   ├── AudioFileAppender.java
│       │   │               │   │   ├── AudioRecordingControllerFragment.java
│       │   │               │   │   ├── AudioRecordingErrorDialogFragment.java
│       │   │               │   │   ├── BackgroundAudioHelpDialogFragment.java
│       │   │               │   │   ├── M4AAppender.java
│       │   │               │   │   ├── VolumeBar.java
│       │   │               │   │   └── Waveform.java
│       │   │               │   ├── backgroundwork/
│       │   │               │   │   ├── AutoUpdateTaskSpec.kt
│       │   │               │   │   ├── BackgroundWorkUtils.java
│       │   │               │   │   ├── FormUpdateAndInstanceSubmitScheduler.java
│       │   │               │   │   ├── FormUpdateScheduler.java
│       │   │               │   │   ├── InstanceSubmitScheduler.java
│       │   │               │   │   ├── SendFormsTaskSpec.kt
│       │   │               │   │   ├── SyncFormsTaskSpec.kt
│       │   │               │   │   └── TaskData.kt
│       │   │               │   ├── configure/
│       │   │               │   │   └── qr/
│       │   │               │   │       ├── AppConfigurationGenerator.kt
│       │   │               │   │       ├── CachingQRCodeGenerator.kt
│       │   │               │   │       ├── QRCodeActivityResultDelegate.kt
│       │   │               │   │       ├── QRCodeMenuProvider.kt
│       │   │               │   │       ├── QRCodeScannerFragment.kt
│       │   │               │   │       ├── QRCodeTabsActivity.kt
│       │   │               │   │       ├── QRCodeViewModel.kt
│       │   │               │   │       ├── SettingsBarcodeScannerViewFactory.kt
│       │   │               │   │       └── ShowQRCodeFragment.kt
│       │   │               │   ├── dao/
│       │   │               │   │   ├── CursorLoaderFactory.java
│       │   │               │   │   └── helpers/
│       │   │               │   │       └── InstancesDaoHelper.java
│       │   │               │   ├── database/
│       │   │               │   │   ├── DatabaseConstants.java
│       │   │               │   │   ├── DatabaseObjectMapper.kt
│       │   │               │   │   ├── entities/
│       │   │               │   │   │   └── DatabaseEntitiesRepository.kt
│       │   │               │   │   ├── forms/
│       │   │               │   │   │   ├── DatabaseFormColumns.kt
│       │   │               │   │   │   ├── DatabaseFormsRepository.java
│       │   │               │   │   │   └── FormDatabaseMigrator.java
│       │   │               │   │   ├── instances/
│       │   │               │   │   │   ├── DatabaseInstanceColumns.kt
│       │   │               │   │   │   ├── DatabaseInstancesRepository.java
│       │   │               │   │   │   └── InstanceDatabaseMigrator.java
│       │   │               │   │   ├── itemsets/
│       │   │               │   │   │   └── DatabaseFastExternalItemsetsRepository.kt
│       │   │               │   │   └── savepoints/
│       │   │               │   │       ├── DatabaseSavepointsColumns.kt
│       │   │               │   │       ├── DatabaseSavepointsRepository.kt
│       │   │               │   │       └── SavepointsDatabaseMigrator.kt
│       │   │               │   ├── dynamicpreload/
│       │   │               │   │   ├── DynamicPreloadXFormParserFactory.kt
│       │   │               │   │   ├── ExternalAnswerResolver.java
│       │   │               │   │   ├── ExternalAppsUtils.java
│       │   │               │   │   ├── ExternalDataHandler.java
│       │   │               │   │   ├── ExternalDataManager.java
│       │   │               │   │   ├── ExternalDataManagerImpl.java
│       │   │               │   │   ├── ExternalDataReader.java
│       │   │               │   │   ├── ExternalDataReaderImpl.java
│       │   │               │   │   ├── ExternalDataUseCases.kt
│       │   │               │   │   ├── ExternalDataUtil.java
│       │   │               │   │   ├── ExternalSQLiteOpenHelper.java
│       │   │               │   │   ├── ExternalSelectChoice.java
│       │   │               │   │   └── handler/
│       │   │               │   │       ├── ExternalDataHandlerBase.java
│       │   │               │   │       ├── ExternalDataHandlerPull.java
│       │   │               │   │       ├── ExternalDataHandlerSearch.java
│       │   │               │   │       └── ExternalDataSearchType.java
│       │   │               │   ├── entities/
│       │   │               │   │   └── EntitiesRepositoryProvider.kt
│       │   │               │   ├── exception/
│       │   │               │   │   ├── EncryptionException.java
│       │   │               │   │   ├── ExternalDataException.java
│       │   │               │   │   ├── ExternalParamsException.java
│       │   │               │   │   └── JavaRosaException.java
│       │   │               │   ├── external/
│       │   │               │   │   ├── AndroidShortcutsActivity.kt
│       │   │               │   │   ├── FormUriActivity.kt
│       │   │               │   │   ├── FormsContract.java
│       │   │               │   │   ├── FormsProvider.java
│       │   │               │   │   ├── InstanceProvider.java
│       │   │               │   │   └── InstancesContract.java
│       │   │               │   ├── fastexternalitemset/
│       │   │               │   │   ├── ItemsetDao.java
│       │   │               │   │   ├── ItemsetDbAdapter.java
│       │   │               │   │   └── XPathParseTool.java
│       │   │               │   ├── formentry/
│       │   │               │   │   ├── BackgroundAudioPermissionDialogFragment.java
│       │   │               │   │   ├── BackgroundAudioViewModel.java
│       │   │               │   │   ├── CurrentFormIndex.kt
│       │   │               │   │   ├── FormAnimation.kt
│       │   │               │   │   ├── FormDefCache.kt
│       │   │               │   │   ├── FormEnd.kt
│       │   │               │   │   ├── FormEndView.kt
│       │   │               │   │   ├── FormEndViewModel.kt
│       │   │               │   │   ├── FormEntryMenuProvider.kt
│       │   │               │   │   ├── FormEntryUseCases.kt
│       │   │               │   │   ├── FormEntryViewModel.java
│       │   │               │   │   ├── FormError.kt
│       │   │               │   │   ├── FormIndexAnimationHandler.kt
│       │   │               │   │   ├── FormLoadingDialogFragment.java
│       │   │               │   │   ├── FormOpeningMode.kt
│       │   │               │   │   ├── FormSessionRepository.kt
│       │   │               │   │   ├── ODKView.java
│       │   │               │   │   ├── PrinterWidgetViewModel.kt
│       │   │               │   │   ├── QuitFormDialog.kt
│       │   │               │   │   ├── RecordingHandler.java
│       │   │               │   │   ├── RecordingWarningDialogFragment.java
│       │   │               │   │   ├── RefreshFormListDialogFragment.java
│       │   │               │   │   ├── SwipeHandler.kt
│       │   │               │   │   ├── audit/
│       │   │               │   │   │   ├── AsyncTaskAuditEventWriter.java
│       │   │               │   │   │   ├── AuditConfig.java
│       │   │               │   │   │   ├── AuditEvent.java
│       │   │               │   │   │   ├── AuditEventCSVLine.java
│       │   │               │   │   │   ├── AuditEventLogger.java
│       │   │               │   │   │   ├── AuditEventSaveTask.java
│       │   │               │   │   │   ├── AuditUtils.kt
│       │   │               │   │   │   ├── ChangesReasonPromptDialogFragment.java
│       │   │               │   │   │   ├── IdentifyUserPromptDialogFragment.java
│       │   │               │   │   │   └── IdentityPromptViewModel.java
│       │   │               │   │   ├── backgroundlocation/
│       │   │               │   │   │   ├── BackgroundLocationHelper.java
│       │   │               │   │   │   ├── BackgroundLocationManager.java
│       │   │               │   │   │   └── BackgroundLocationViewModel.java
│       │   │               │   │   ├── media/
│       │   │               │   │   │   ├── FormMediaUtils.java
│       │   │               │   │   │   └── PromptAutoplayer.java
│       │   │               │   │   ├── questions/
│       │   │               │   │   │   ├── AnswersProvider.java
│       │   │               │   │   │   ├── AudioVideoImageTextLabel.java
│       │   │               │   │   │   ├── NoButtonsItem.java
│       │   │               │   │   │   ├── QuestionDetails.java
│       │   │               │   │   │   └── SelectChoiceUtils.kt
│       │   │               │   │   ├── repeats/
│       │   │               │   │   │   ├── AddRepeatDialog.kt
│       │   │               │   │   │   └── DeleteRepeatDialogFragment.java
│       │   │               │   │   └── saving/
│       │   │               │   │       ├── DiskFormSaver.java
│       │   │               │   │       ├── FormSaveViewModel.java
│       │   │               │   │       ├── FormSaver.java
│       │   │               │   │       ├── SaveAnswerFileErrorDialogFragment.java
│       │   │               │   │       ├── SaveAnswerFileProgressDialogFragment.java
│       │   │               │   │       └── SaveFormProgressDialogFragment.java
│       │   │               │   ├── formhierarchy/
│       │   │               │   │   ├── FormHierarchyFragment.java
│       │   │               │   │   ├── FormHierarchyFragmentHostActivity.kt
│       │   │               │   │   ├── FormHierarchyViewModel.kt
│       │   │               │   │   ├── HierarchyItem.kt
│       │   │               │   │   ├── HierarchyListAdapter.kt
│       │   │               │   │   ├── HierarchyListItemView.kt
│       │   │               │   │   └── QuestionAnswerProcessor.kt
│       │   │               │   ├── formlists/
│       │   │               │   │   ├── blankformlist/
│       │   │               │   │   │   ├── BlankFormListActivity.kt
│       │   │               │   │   │   ├── BlankFormListAdapter.kt
│       │   │               │   │   │   ├── BlankFormListItem.kt
│       │   │               │   │   │   ├── BlankFormListItemView.kt
│       │   │               │   │   │   ├── BlankFormListMenuProvider.kt
│       │   │               │   │   │   ├── BlankFormListViewModel.kt
│       │   │               │   │   │   └── DeleteBlankFormFragment.kt
│       │   │               │   │   ├── savedformlist/
│       │   │               │   │   │   ├── DeleteSavedFormFragment.kt
│       │   │               │   │   │   ├── SavedFormListItemView.kt
│       │   │               │   │   │   ├── SavedFormListListMenuProvider.kt
│       │   │               │   │   │   ├── SavedFormListViewModel.kt
│       │   │               │   │   │   └── SelectableSavedFormListItemViewHolder.kt
│       │   │               │   │   └── sorting/
│       │   │               │   │       ├── FormListSortingAdapter.kt
│       │   │               │   │       ├── FormListSortingBottomSheetDialog.kt
│       │   │               │   │       └── FormListSortingOption.kt
│       │   │               │   ├── formmanagement/
│       │   │               │   │   ├── CollectFormEntryControllerFactory.kt
│       │   │               │   │   ├── FormFillingIntentFactory.kt
│       │   │               │   │   ├── FormSourceExceptionMapper.kt
│       │   │               │   │   ├── FormsDataService.kt
│       │   │               │   │   ├── LocalFormUseCases.kt
│       │   │               │   │   ├── OpenRosaClientProvider.kt
│       │   │               │   │   ├── ServerFormDetails.kt
│       │   │               │   │   ├── ServerFormUseCases.kt
│       │   │               │   │   ├── download/
│       │   │               │   │   │   ├── FormDownloadException.kt
│       │   │               │   │   │   ├── FormDownloadExceptionMapper.kt
│       │   │               │   │   │   ├── FormDownloader.kt
│       │   │               │   │   │   └── ServerFormDownloader.java
│       │   │               │   │   ├── drafts/
│       │   │               │   │   │   ├── BulkFinalizationViewModel.kt
│       │   │               │   │   │   └── DraftsMenuProvider.kt
│       │   │               │   │   ├── finalization/
│       │   │               │   │   │   └── EditedFormFinalizationProcessor.kt
│       │   │               │   │   ├── formmap/
│       │   │               │   │   │   └── FormMapViewModel.kt
│       │   │               │   │   ├── matchexactly/
│       │   │               │   │   │   └── ServerFormsSynchronizer.java
│       │   │               │   │   └── metadata/
│       │   │               │   │       ├── FormMetadata.kt
│       │   │               │   │       └── FormMetadataParser.kt
│       │   │               │   ├── fragments/
│       │   │               │   │   ├── BarCodeScannerFragment.kt
│       │   │               │   │   ├── BarcodeWidgetScannerFragment.kt
│       │   │               │   │   ├── MediaLoadingFragment.java
│       │   │               │   │   ├── dialogs/
│       │   │               │   │   │   ├── FormsDownloadResultDialog.kt
│       │   │               │   │   │   ├── LocationProvidersDisabledDialog.java
│       │   │               │   │   │   ├── MovingBackwardsDialog.java
│       │   │               │   │   │   ├── RangePickerDialogFragment.kt
│       │   │               │   │   │   ├── RankingWidgetDialog.java
│       │   │               │   │   │   ├── ResetSettingsResultDialog.java
│       │   │               │   │   │   ├── SelectMinimalDialog.java
│       │   │               │   │   │   ├── SelectMultiMinimalDialog.java
│       │   │               │   │   │   ├── SelectOneMinimalDialog.java
│       │   │               │   │   │   └── SimpleDialog.java
│       │   │               │   │   └── viewmodels/
│       │   │               │   │       ├── RankingViewModel.java
│       │   │               │   │       └── SelectMinimalViewModel.java
│       │   │               │   ├── geo/
│       │   │               │   │   ├── MapConfiguratorProvider.java
│       │   │               │   │   └── MapFragmentFactoryImpl.kt
│       │   │               │   ├── injection/
│       │   │               │   │   ├── DaggerUtils.kt
│       │   │               │   │   └── config/
│       │   │               │   │       ├── AppDependencyComponent.kt
│       │   │               │   │       ├── AppDependencyModule.java
│       │   │               │   │       ├── CollectDrawDependencyModule.kt
│       │   │               │   │       ├── CollectEntitiesDependencyModule.kt
│       │   │               │   │       ├── CollectGeoDependencyModule.kt
│       │   │               │   │       ├── CollectGoogleMapsDependencyModule.kt
│       │   │               │   │       ├── CollectOsmDroidDependencyModule.kt
│       │   │               │   │       ├── CollectProjectsDependencyModule.kt
│       │   │               │   │       ├── CollectSelfieCameraDependencyModule.kt
│       │   │               │   │       └── ProjectDependencyModuleFactory.kt
│       │   │               │   ├── instancemanagement/
│       │   │               │   │   ├── FinalizeAllSnackbarPresenter.kt
│       │   │               │   │   ├── InstanceDeleter.kt
│       │   │               │   │   ├── InstanceDiskSynchronizer.java
│       │   │               │   │   ├── InstanceExt.kt
│       │   │               │   │   ├── InstanceListItemView.kt
│       │   │               │   │   ├── InstanceSubmitter.kt
│       │   │               │   │   ├── InstancesDataService.kt
│       │   │               │   │   ├── LocalInstancesUseCases.kt
│       │   │               │   │   ├── autosend/
│       │   │               │   │   │   ├── AutoSendSettingsProvider.kt
│       │   │               │   │   │   ├── FormExt.kt
│       │   │               │   │   │   └── InstanceAutoSendFetcher.kt
│       │   │               │   │   └── send/
│       │   │               │   │       ├── InstanceUploaderActivity.java
│       │   │               │   │       ├── InstanceUploaderListActivity.java
│       │   │               │   │       ├── ReadyToSendBanner.kt
│       │   │               │   │       └── ReadyToSendViewModel.kt
│       │   │               │   ├── itemsets/
│       │   │               │   │   └── FastExternalItemsetsRepository.kt
│       │   │               │   ├── javarosawrapper/
│       │   │               │   │   ├── FormController.kt
│       │   │               │   │   ├── FormControllerExt.kt
│       │   │               │   │   ├── FormDesignException.kt
│       │   │               │   │   ├── FormIndexUtils.java
│       │   │               │   │   ├── InstanceMetadata.java
│       │   │               │   │   ├── JavaRosaFormController.java
│       │   │               │   │   └── ValidationResult.kt
│       │   │               │   ├── listeners/
│       │   │               │   │   ├── AdvanceToNextListener.java
│       │   │               │   │   ├── DeleteInstancesListener.java
│       │   │               │   │   ├── DownloadFormsTaskListener.java
│       │   │               │   │   ├── FormListDownloaderListener.java
│       │   │               │   │   ├── FormLoaderListener.java
│       │   │               │   │   ├── InstanceUploaderListener.java
│       │   │               │   │   ├── Result.java
│       │   │               │   │   ├── SelectItemClickListener.java
│       │   │               │   │   ├── ThousandsSeparatorTextWatcher.java
│       │   │               │   │   └── WidgetValueChangedListener.java
│       │   │               │   ├── location/
│       │   │               │   │   └── client/
│       │   │               │   │       └── MaxAccuracyWithinTimeoutLocationClientWrapper.java
│       │   │               │   ├── logic/
│       │   │               │   │   ├── FileReference.java
│       │   │               │   │   ├── FileReferenceFactory.java
│       │   │               │   │   ├── ImmutableDisplayableQuestion.java
│       │   │               │   │   └── actions/
│       │   │               │   │       └── setgeopoint/
│       │   │               │   │           ├── CollectSetGeopointAction.java
│       │   │               │   │           └── CollectSetGeopointActionHandler.java
│       │   │               │   ├── mainmenu/
│       │   │               │   │   ├── CurrentProjectViewModel.kt
│       │   │               │   │   ├── MainMenuActivity.kt
│       │   │               │   │   ├── MainMenuButton.kt
│       │   │               │   │   ├── MainMenuFragment.kt
│       │   │               │   │   ├── MainMenuViewModel.kt
│       │   │               │   │   ├── MainMenuViewModelFactory.kt
│       │   │               │   │   ├── PermissionsDialogFragment.kt
│       │   │               │   │   ├── RequestPermissionsViewModel.kt
│       │   │               │   │   └── StartNewFormButton.kt
│       │   │               │   ├── notifications/
│       │   │               │   │   ├── NotificationManagerNotifier.kt
│       │   │               │   │   ├── NotificationUtils.kt
│       │   │               │   │   ├── Notifier.kt
│       │   │               │   │   └── builders/
│       │   │               │   │       ├── FormUpdatesAvailableNotificationBuilder.kt
│       │   │               │   │       ├── FormUpdatesDownloadedNotificationBuilder.kt
│       │   │               │   │       ├── FormsSubmissionNotificationBuilder.kt
│       │   │               │   │       ├── FormsSyncFailedNotificationBuilder.kt
│       │   │               │   │       └── FormsSyncStoppedNotificationBuilder.kt
│       │   │               │   ├── preferences/
│       │   │               │   │   ├── Defaults.kt
│       │   │               │   │   ├── PreferenceVisibilityHandler.kt
│       │   │               │   │   ├── ProjectPreferencesViewModel.kt
│       │   │               │   │   ├── ServerPreferencesAdder.java
│       │   │               │   │   ├── SettingsExt.kt
│       │   │               │   │   ├── dialogs/
│       │   │               │   │   │   ├── AdminPasswordDialogFragment.kt
│       │   │               │   │   │   ├── ChangeAdminPasswordDialog.kt
│       │   │               │   │   │   ├── DeleteProjectDialog.kt
│       │   │               │   │   │   ├── ResetDialogPreference.java
│       │   │               │   │   │   ├── ResetDialogPreferenceFragmentCompat.java
│       │   │               │   │   │   ├── ResetProgressDialog.kt
│       │   │               │   │   │   └── ServerAuthDialogFragment.java
│       │   │               │   │   ├── filters/
│       │   │               │   │   │   └── ControlCharacterFilter.java
│       │   │               │   │   ├── screens/
│       │   │               │   │   │   ├── AccessControlPreferencesFragment.kt
│       │   │               │   │   │   ├── BaseAdminPreferencesFragment.java
│       │   │               │   │   │   ├── BasePreferencesFragment.kt
│       │   │               │   │   │   ├── BaseProjectPreferencesFragment.java
│       │   │               │   │   │   ├── DevToolsPreferencesFragment.kt
│       │   │               │   │   │   ├── ExperimentalPreferencesFragment.java
│       │   │               │   │   │   ├── FormEntryAccessPreferencesFragment.kt
│       │   │               │   │   │   ├── FormManagementPreferencesFragment.java
│       │   │               │   │   │   ├── FormMetadataPreferencesFragment.java
│       │   │               │   │   │   ├── IdentityPreferencesFragment.kt
│       │   │               │   │   │   ├── MainMenuAccessPreferencesFragment.kt
│       │   │               │   │   │   ├── MapsPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectDisplayPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectManagementPreferencesFragment.kt
│       │   │               │   │   │   ├── ProjectPreferencesActivity.kt
│       │   │               │   │   │   ├── ProjectPreferencesFragment.kt
│       │   │               │   │   │   ├── ServerPreferencesFragment.java
│       │   │               │   │   │   ├── UserInterfacePreferencesFragment.java
│       │   │               │   │   │   └── UserSettingsAccessPreferencesFragment.java
│       │   │               │   │   ├── source/
│       │   │               │   │   │   ├── SettingsStore.kt
│       │   │               │   │   │   ├── SharedPreferencesSettings.kt
│       │   │               │   │   │   └── SharedPreferencesSettingsProvider.kt
│       │   │               │   │   └── utilities/
│       │   │               │   │       └── PreferencesUtils.java
│       │   │               │   ├── projects/
│       │   │               │   │   ├── DuplicateProjectConfirmationDialog.kt
│       │   │               │   │   ├── FileDebugLogger.kt
│       │   │               │   │   ├── ManualProjectCreatorDialog.kt
│       │   │               │   │   ├── ProjectCreatorImpl.kt
│       │   │               │   │   ├── ProjectDeleter.kt
│       │   │               │   │   ├── ProjectDependencyModule.kt
│       │   │               │   │   ├── ProjectIconView.kt
│       │   │               │   │   ├── ProjectListItemView.kt
│       │   │               │   │   ├── ProjectResetter.kt
│       │   │               │   │   ├── ProjectSettingsDialog.kt
│       │   │               │   │   ├── ProjectsDataService.kt
│       │   │               │   │   ├── QrCodeProjectCreatorDialog.kt
│       │   │               │   │   └── SettingsConnectionMatcherImpl.kt
│       │   │               │   ├── savepoints/
│       │   │               │   │   ├── SavepointTask.kt
│       │   │               │   │   └── SavepointUseCases.kt
│       │   │               │   ├── state/
│       │   │               │   │   └── DataKeys.kt
│       │   │               │   ├── storage/
│       │   │               │   │   ├── StoragePathProvider.kt
│       │   │               │   │   ├── StoragePaths.kt
│       │   │               │   │   └── StorageSubdirectory.java
│       │   │               │   ├── tasks/
│       │   │               │   │   ├── DownloadFormListTask.java
│       │   │               │   │   ├── DownloadFormsTask.java
│       │   │               │   │   ├── FormLoaderTask.java
│       │   │               │   │   ├── InstanceUploaderTask.java
│       │   │               │   │   ├── MediaLoadingTask.java
│       │   │               │   │   ├── ProgressNotifier.java
│       │   │               │   │   ├── SaveFormIndexTask.java
│       │   │               │   │   ├── SaveFormToDisk.java
│       │   │               │   │   └── SaveToDiskResult.java
│       │   │               │   ├── upload/
│       │   │               │   │   ├── FormUploadException.kt
│       │   │               │   │   ├── InstanceServerUploader.java
│       │   │               │   │   └── InstanceUploader.java
│       │   │               │   ├── utilities/
│       │   │               │   │   ├── ActionRegister.kt
│       │   │               │   │   ├── AdminPasswordProvider.java
│       │   │               │   │   ├── AndroidUserAgent.java
│       │   │               │   │   ├── AnimationUtils.java
│       │   │               │   │   ├── Appearances.kt
│       │   │               │   │   ├── ApplicationConstants.java
│       │   │               │   │   ├── ArrayUtils.java
│       │   │               │   │   ├── AuthDialogUtility.java
│       │   │               │   │   ├── CSVUtils.java
│       │   │               │   │   ├── ChangeLockProvider.kt
│       │   │               │   │   ├── CollectStrictMode.kt
│       │   │               │   │   ├── ContentUriHelper.kt
│       │   │               │   │   ├── ContentUriProvider.java
│       │   │               │   │   ├── ControllableLifecyleOwner.kt
│       │   │               │   │   ├── DialogUtils.java
│       │   │               │   │   ├── EncryptionUtils.java
│       │   │               │   │   ├── ExternalAppIntentProvider.java
│       │   │               │   │   ├── ExternalizableFormDefCache.java
│       │   │               │   │   ├── FileProvider.java
│       │   │               │   │   ├── FileUtils.java
│       │   │               │   │   ├── FormEntryPromptUtils.java
│       │   │               │   │   ├── FormNameUtils.java
│       │   │               │   │   ├── FormUtils.java
│       │   │               │   │   ├── FormsDownloadResultInterpreter.kt
│       │   │               │   │   ├── FormsRepositoryProvider.kt
│       │   │               │   │   ├── FormsUploadResultInterpreter.kt
│       │   │               │   │   ├── HtmlUtils.java
│       │   │               │   │   ├── ImageCompressionController.kt
│       │   │               │   │   ├── InstanceAutoDeleteChecker.kt
│       │   │               │   │   ├── InstanceUploaderUtils.java
│       │   │               │   │   ├── InstancesRepositoryProvider.kt
│       │   │               │   │   ├── LocaleHelper.kt
│       │   │               │   │   ├── MediaUtils.kt
│       │   │               │   │   ├── MyanmarDateUtils.java
│       │   │               │   │   ├── QuestionMediaManager.java
│       │   │               │   │   ├── RankingItemTouchHelperCallback.java
│       │   │               │   │   ├── ReplaceCallback.java
│       │   │               │   │   ├── ResponseMessageParser.java
│       │   │               │   │   ├── SavepointsRepositoryProvider.kt
│       │   │               │   │   ├── SelectOneWidgetUtils.java
│       │   │               │   │   ├── SoftKeyboardController.kt
│       │   │               │   │   ├── ThemeUtils.java
│       │   │               │   │   ├── UnderlyingValuesConcat.java
│       │   │               │   │   ├── ViewUtils.kt
│       │   │               │   │   ├── WebCredentialsUtils.java
│       │   │               │   │   └── ZipUtils.java
│       │   │               │   ├── version/
│       │   │               │   │   ├── VersionDescriptionProvider.java
│       │   │               │   │   └── VersionInformation.java
│       │   │               │   ├── views/
│       │   │               │   │   ├── ChoicesRecyclerView.java
│       │   │               │   │   ├── CustomNumberPicker.kt
│       │   │               │   │   ├── CustomWebView.java
│       │   │               │   │   ├── DayNightProgressDialog.java
│       │   │               │   │   ├── DecoratedBarcodeView.kt
│       │   │               │   │   ├── SlidingTabLayout.java
│       │   │               │   │   ├── SlidingTabStrip.java
│       │   │               │   │   ├── TrackingTouchSlider.kt
│       │   │               │   │   ├── TransparentProgressScreen.kt
│       │   │               │   │   ├── TwoItemMultipleChoiceView.java
│       │   │               │   │   └── WidgetAnswerText.kt
│       │   │               │   └── widgets/
│       │   │               │       ├── AnnotateWidget.java
│       │   │               │       ├── AudioWidget.java
│       │   │               │       ├── BaseImageWidget.java
│       │   │               │       ├── BearingWidget.java
│       │   │               │       ├── CounterWidget.kt
│       │   │               │       ├── DecimalWidget.java
│       │   │               │       ├── DrawWidget.java
│       │   │               │       ├── ExAudioWidget.java
│       │   │               │       ├── ExDecimalWidget.java
│       │   │               │       ├── ExImageWidget.java
│       │   │               │       ├── ExIntegerWidget.java
│       │   │               │       ├── ExStringWidget.java
│       │   │               │       ├── GeoPointMapWidget.java
│       │   │               │       ├── GeoPointWidget.java
│       │   │               │       ├── GeoShapeWidget.java
│       │   │               │       ├── GeoTraceWidget.java
│       │   │               │       ├── ImageWidget.java
│       │   │               │       ├── IntegerWidget.java
│       │   │               │       ├── MediaWidgetAnswerViewModel.kt
│       │   │               │       ├── OSMWidget.java
│       │   │               │       ├── PrinterWidget.kt
│       │   │               │       ├── QuestionWidget.java
│       │   │               │       ├── RatingWidget.java
│       │   │               │       ├── SignatureWidget.java
│       │   │               │       ├── StringNumberWidget.java
│       │   │               │       ├── StringWidget.java
│       │   │               │       ├── TextWidgetAnswer.kt
│       │   │               │       ├── TimedGridWidget.kt
│       │   │               │       ├── TriggerWidget.java
│       │   │               │       ├── UrlWidget.java
│       │   │               │       ├── WidgetAnswer.kt
│       │   │               │       ├── WidgetAnswerView.kt
│       │   │               │       ├── WidgetFactory.java
│       │   │               │       ├── WidgetIconButton.kt
│       │   │               │       ├── arbitraryfile/
│       │   │               │       │   ├── ArbitraryFileWidget.kt
│       │   │               │       │   ├── ArbitraryFileWidgetContent.kt
│       │   │               │       │   ├── ArbitraryFileWidgetDelegate.kt
│       │   │               │       │   ├── ExArbitraryFileWidget.kt
│       │   │               │       │   └── ExArbitraryFileWidgetContent.kt
│       │   │               │       ├── barcode/
│       │   │               │       │   ├── BarcodeWidget.kt
│       │   │               │       │   └── BarcodeWidgetContent.kt
│       │   │               │       ├── datetime/
│       │   │               │       │   ├── DatePickerDetails.java
│       │   │               │       │   ├── DateTimeUtils.java
│       │   │               │       │   ├── DateTimeWidget.java
│       │   │               │       │   ├── DateWidget.java
│       │   │               │       │   ├── TimeWidget.java
│       │   │               │       │   └── pickers/
│       │   │               │       │       ├── BikramSambatDatePickerDialog.java
│       │   │               │       │       ├── BuddhistDatePickerDialog.kt
│       │   │               │       │       ├── CopticDatePickerDialog.java
│       │   │               │       │       ├── CustomDatePickerDialog.java
│       │   │               │       │       ├── CustomTimePickerDialog.java
│       │   │               │       │       ├── EthiopianDatePickerDialog.java
│       │   │               │       │       ├── FixedDatePickerDialog.java
│       │   │               │       │       ├── IslamicDatePickerDialog.java
│       │   │               │       │       ├── MyanmarDatePickerDialog.java
│       │   │               │       │       └── PersianDatePickerDialog.java
│       │   │               │       ├── interfaces/
│       │   │               │       │   ├── FileWidget.java
│       │   │               │       │   ├── GeoDataRequester.kt
│       │   │               │       │   ├── MultiChoiceWidget.java
│       │   │               │       │   ├── Printer.kt
│       │   │               │       │   ├── SelectChoiceLoader.kt
│       │   │               │       │   ├── Widget.java
│       │   │               │       │   └── WidgetDataReceiver.kt
│       │   │               │       ├── items/
│       │   │               │       │   ├── BaseSelectListWidget.java
│       │   │               │       │   ├── ItemsWidgetUtils.kt
│       │   │               │       │   ├── LabelWidget.java
│       │   │               │       │   ├── LikertWidget.java
│       │   │               │       │   ├── ListMultiWidget.java
│       │   │               │       │   ├── ListWidget.java
│       │   │               │       │   ├── RankingWidget.java
│       │   │               │       │   ├── SelectImageMapWidget.java
│       │   │               │       │   ├── SelectMinimalWidget.java
│       │   │               │       │   ├── SelectMultiImageMapWidget.java
│       │   │               │       │   ├── SelectMultiMinimalWidget.java
│       │   │               │       │   ├── SelectMultiWidget.java
│       │   │               │       │   ├── SelectOneFromMapDialogFragment.kt
│       │   │               │       │   ├── SelectOneFromMapWidget.kt
│       │   │               │       │   ├── SelectOneImageMapWidget.java
│       │   │               │       │   ├── SelectOneMinimalWidget.java
│       │   │               │       │   └── SelectOneWidget.java
│       │   │               │       ├── range/
│       │   │               │       │   ├── RangeDecimalWidget.java
│       │   │               │       │   ├── RangeIntegerWidget.java
│       │   │               │       │   ├── RangePickerWidget.java
│       │   │               │       │   └── RangePickerWidgetUtils.kt
│       │   │               │       ├── utilities/
│       │   │               │       │   ├── ActivityGeoDataRequester.kt
│       │   │               │       │   ├── AdditionalAttributes.kt
│       │   │               │       │   ├── AudioFileRequester.java
│       │   │               │       │   ├── AudioRecorderRecordingStatusHandler.java
│       │   │               │       │   ├── BindAttributes.kt
│       │   │               │       │   ├── DateTimeWidgetUtils.java
│       │   │               │       │   ├── ExternalAppRecordingRequester.kt
│       │   │               │       │   ├── FileRequester.kt
│       │   │               │       │   ├── FormControllerWaitingForDataRegistry.java
│       │   │               │       │   ├── GeoPolyDialogFragment.kt
│       │   │               │       │   ├── GeoWidgetUtils.kt
│       │   │               │       │   ├── GetContentAudioFileRequester.kt
│       │   │               │       │   ├── ImageCaptureIntentCreator.kt
│       │   │               │       │   ├── InternalRecordingRequester.java
│       │   │               │       │   ├── QuestionFontSizeUtils.kt
│       │   │               │       │   ├── RangeWidgetUtils.java
│       │   │               │       │   ├── RecordingRequester.java
│       │   │               │       │   ├── RecordingRequesterProvider.java
│       │   │               │       │   ├── RecordingStatusHandler.java
│       │   │               │       │   ├── SearchQueryViewModel.java
│       │   │               │       │   ├── StringRequester.kt
│       │   │               │       │   ├── StringWidgetUtils.java
│       │   │               │       │   ├── ViewModelAudioPlayer.kt
│       │   │               │       │   ├── WaitingForDataRegistry.java
│       │   │               │       │   └── WidgetAnswerDialogFragment.kt
│       │   │               │       ├── video/
│       │   │               │       │   ├── ExVideoWidget.kt
│       │   │               │       │   ├── ExVideoWidgetContent.kt
│       │   │               │       │   ├── VideoWidget.kt
│       │   │               │       │   ├── VideoWidgetAnswer.kt
│       │   │               │       │   └── VideoWidgetContent.kt
│       │   │               │       ├── viewmodels/
│       │   │               │       │   ├── DateTimeViewModel.java
│       │   │               │       │   └── QuestionViewModel.kt
│       │   │               │       └── warnings/
│       │   │               │           └── SpacesInUnderlyingValuesWarning.java
│       │   │               └── utilities/
│       │   │                   ├── Result.java
│       │   │                   └── UserAgentProvider.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── fade_in.xml
│       │       │   ├── fade_out.xml
│       │       │   ├── push_left_in.xml
│       │       │   ├── push_left_out.xml
│       │       │   ├── push_right_in.xml
│       │       │   └── push_right_out.xml
│       │       ├── drawable/
│       │       │   ├── counter_minus_button_background.xml
│       │       │   ├── counter_plus_button_background.xml
│       │       │   ├── counter_value_background.xml
│       │       │   ├── ic_access_time.xml
│       │       │   ├── ic_add_circle_24.xml
│       │       │   ├── ic_arrow_back.xml
│       │       │   ├── ic_arrow_drop_down.xml
│       │       │   ├── ic_arrow_up.xml
│       │       │   ├── ic_baseline_delete_72.xml
│       │       │   ├── ic_baseline_delete_outline_24.xml
│       │       │   ├── ic_baseline_download_72.xml
│       │       │   ├── ic_baseline_edit_72.xml
│       │       │   ├── ic_baseline_error_24.xml
│       │       │   ├── ic_baseline_help_outline_24.xml
│       │       │   ├── ic_baseline_inbox_72.xml
│       │       │   ├── ic_baseline_note_72.xml
│       │       │   ├── ic_baseline_notifications_24.xml
│       │       │   ├── ic_baseline_qr_code_scanner_24.xml
│       │       │   ├── ic_baseline_refresh_24.xml
│       │       │   ├── ic_baseline_refresh_error_24.xml
│       │       │   ├── ic_baseline_search_24.xml
│       │       │   ├── ic_baseline_send_72.xml
│       │       │   ├── ic_baseline_sort_24.xml
│       │       │   ├── ic_cancel.xml
│       │       │   ├── ic_chat_bubble_24dp.xml
│       │       │   ├── ic_check_circle_24.xml
│       │       │   ├── ic_download_24.xml
│       │       │   ├── ic_edit_24.xml
│       │       │   ├── ic_folder_open.xml
│       │       │   ├── ic_form_state_blank.xml
│       │       │   ├── ic_form_state_finalized.xml
│       │       │   ├── ic_form_state_saved.xml
│       │       │   ├── ic_form_state_submission_failed.xml
│       │       │   ├── ic_form_state_submitted.xml
│       │       │   ├── ic_information_outline.xml
│       │       │   ├── ic_map.xml
│       │       │   ├── ic_menu_share.xml
│       │       │   ├── ic_navigate_back.xml
│       │       │   ├── ic_navigate_forward.xml
│       │       │   ├── ic_ondemand_video_black_24dp.xml
│       │       │   ├── ic_outline_assignment_accent_24.xml
│       │       │   ├── ic_outline_cloud_accent_24.xml
│       │       │   ├── ic_outline_color_lens_accent_24.xml
│       │       │   ├── ic_outline_delete_accent_24.xml
│       │       │   ├── ic_outline_edit_24.xml
│       │       │   ├── ic_outline_face_accent_24.xml
│       │       │   ├── ic_outline_forum_24.xml
│       │       │   ├── ic_outline_info_small.xml
│       │       │   ├── ic_outline_lock_24.xml
│       │       │   ├── ic_outline_lock_accent_24.xml
│       │       │   ├── ic_outline_lock_open_24.xml
│       │       │   ├── ic_outline_map_accent_24.xml
│       │       │   ├── ic_outline_menu_accent_24.xml
│       │       │   ├── ic_outline_phonelink_setup_accent_24.xml
│       │       │   ├── ic_outline_qr_code_scanner_accent_24.xml
│       │       │   ├── ic_outline_rate_review_24.xml
│       │       │   ├── ic_outline_refresh_accent_24.xml
│       │       │   ├── ic_outline_settings_accent_24.xml
│       │       │   ├── ic_outline_settings_applications_accent_24.xml
│       │       │   ├── ic_outline_share_24.xml
│       │       │   ├── ic_outline_stars_24.xml
│       │       │   ├── ic_outline_vpn_key_accent_24.xml
│       │       │   ├── ic_outline_warning_accent_24.xml
│       │       │   ├── ic_outline_website_24.xml
│       │       │   ├── ic_pause_24dp.xml
│       │       │   ├── ic_person_24dp.xml
│       │       │   ├── ic_play_arrow_24dp.xml
│       │       │   ├── ic_repeat.xml
│       │       │   ├── ic_room_form_state_complete_24dp.xml
│       │       │   ├── ic_room_form_state_complete_48dp.xml
│       │       │   ├── ic_room_form_state_incomplete_24dp.xml
│       │       │   ├── ic_room_form_state_incomplete_48dp.xml
│       │       │   ├── ic_room_form_state_submission_failed_24dp.xml
│       │       │   ├── ic_room_form_state_submission_failed_48dp.xml
│       │       │   ├── ic_room_form_state_submitted_24dp.xml
│       │       │   ├── ic_room_form_state_submitted_48dp.xml
│       │       │   ├── ic_save_menu_24.xml
│       │       │   ├── ic_send_24.xml
│       │       │   ├── ic_sort.xml
│       │       │   ├── ic_sort_by_alpha.xml
│       │       │   ├── ic_sort_by_last_saved.xml
│       │       │   ├── ic_splash_screen_icon.xml
│       │       │   ├── ic_stop_black_24dp.xml
│       │       │   ├── ic_visibility.xml
│       │       │   ├── ic_volume_up_black_24dp.xml
│       │       │   ├── inset_divider_64dp.xml
│       │       │   ├── main_menu_button_background.xml
│       │       │   ├── odk_logo.xml
│       │       │   ├── pill_filled.xml
│       │       │   ├── pill_unfilled.xml
│       │       │   ├── project_icon_background.xml
│       │       │   ├── question_with_error_border.xml
│       │       │   ├── select_item_border.xml
│       │       │   └── start_new_form_button_background.xml
│       │       ├── drawable-ldrtl/
│       │       │   ├── counter_minus_button_background.xml
│       │       │   └── counter_plus_button_background.xml
│       │       ├── layout/
│       │       │   ├── about_item_layout.xml
│       │       │   ├── about_layout.xml
│       │       │   ├── activity_blank_form_list.xml
│       │       │   ├── activity_custom_scanner.xml
│       │       │   ├── activity_preferences_layout.xml
│       │       │   ├── add_repeat_dialog_layout.xml
│       │       │   ├── admin_password_dialog_layout.xml
│       │       │   ├── annotate_widget.xml
│       │       │   ├── audio_controller_layout.xml
│       │       │   ├── audio_player_layout.xml
│       │       │   ├── audio_recording_controller_fragment.xml
│       │       │   ├── audio_video_image_text_label.xml
│       │       │   ├── audio_widget_answer.xml
│       │       │   ├── background_audio_help_fragment_layout.xml
│       │       │   ├── bearing_widget_answer.xml
│       │       │   ├── blank_form_list_item.xml
│       │       │   ├── bottom_sheet.xml
│       │       │   ├── captioned_item.xml
│       │       │   ├── captioned_list_dialog.xml
│       │       │   ├── changes_reason_dialog.xml
│       │       │   ├── checkbox.xml
│       │       │   ├── circular_progress_indicator.xml
│       │       │   ├── counter_widget.xml
│       │       │   ├── current_project_menu_icon.xml
│       │       │   ├── custom_date_picker_dialog.xml
│       │       │   ├── date_time_widget_answer.xml
│       │       │   ├── date_widget_answer.xml
│       │       │   ├── delete_form_layout.xml
│       │       │   ├── delete_project_dialog_layout.xml
│       │       │   ├── draw_widget.xml
│       │       │   ├── ex_audio_widget_answer.xml
│       │       │   ├── ex_image_widget_answer.xml
│       │       │   ├── ex_string_question_type.xml
│       │       │   ├── first_launch_layout.xml
│       │       │   ├── form_chooser_list.xml
│       │       │   ├── form_chooser_list_item.xml
│       │       │   ├── form_chooser_list_item_icon.xml
│       │       │   ├── form_chooser_list_item_map_button.xml
│       │       │   ├── form_chooser_list_item_multiple_choice.xml
│       │       │   ├── form_chooser_list_item_text.xml
│       │       │   ├── form_download_list.xml
│       │       │   ├── form_entry.xml
│       │       │   ├── form_entry_end.xml
│       │       │   ├── form_hierarchy_layout.xml
│       │       │   ├── form_map_activity.xml
│       │       │   ├── fragment_scan.xml
│       │       │   ├── geopoint_question.xml
│       │       │   ├── geoshape_question.xml
│       │       │   ├── geotrace_question.xml
│       │       │   ├── google_drive_deprecation_banner.xml
│       │       │   ├── help_layout.xml
│       │       │   ├── hierarchy_group_item.xml
│       │       │   ├── hierarchy_host_layout.xml
│       │       │   ├── hierarchy_question_item.xml
│       │       │   ├── hierarchy_repeatable_group_instance_item.xml
│       │       │   ├── hierarchy_repeatable_group_item.xml
│       │       │   ├── identify_user_dialog.xml
│       │       │   ├── image_widget.xml
│       │       │   ├── instance_uploader_list.xml
│       │       │   ├── label_widget.xml
│       │       │   ├── launch_intent_button_layout.xml
│       │       │   ├── main_menu.xml
│       │       │   ├── main_menu_activity.xml
│       │       │   ├── main_menu_button.xml
│       │       │   ├── manual_project_creator_dialog_layout.xml
│       │       │   ├── map_button.xml
│       │       │   ├── no_buttons_item_layout.xml
│       │       │   ├── number_picker_dialog.xml
│       │       │   ├── odk_view.xml
│       │       │   ├── osm_widget_answer.xml
│       │       │   ├── password_dialog_layout.xml
│       │       │   ├── permissions_dialog_layout.xml
│       │       │   ├── printer_widget.xml
│       │       │   ├── progress_bar_view.xml
│       │       │   ├── project_icon_view.xml
│       │       │   ├── project_list_item.xml
│       │       │   ├── project_settings_dialog_layout.xml
│       │       │   ├── qr_code_project_creator_dialog_layout.xml
│       │       │   ├── question_error_layout.xml
│       │       │   ├── question_widget.xml
│       │       │   ├── quit_form_dialog_layout.xml
│       │       │   ├── range_picker_widget_answer.xml
│       │       │   ├── range_widget_horizontal.xml
│       │       │   ├── range_widget_vertical.xml
│       │       │   ├── ranking_item.xml
│       │       │   ├── ranking_widget.xml
│       │       │   ├── rating_widget_answer.xml
│       │       │   ├── ready_to_send_banner.xml
│       │       │   ├── reset_dialog_layout.xml
│       │       │   ├── select_image_map_widget_answer.xml
│       │       │   ├── select_list_widget_answer.xml
│       │       │   ├── select_minimal_dialog_layout.xml
│       │       │   ├── select_minimal_widget_answer.xml
│       │       │   ├── select_multi_item.xml
│       │       │   ├── select_one_from_map_widget_answer.xml
│       │       │   ├── select_one_item.xml
│       │       │   ├── server_auth_dialog.xml
│       │       │   ├── show_qrcode_fragment.xml
│       │       │   ├── signature_widget.xml
│       │       │   ├── sort_item_layout.xml
│       │       │   ├── start_new_from_button.xml
│       │       │   ├── tabs_layout.xml
│       │       │   ├── time_widget_answer.xml
│       │       │   ├── transparent_progress_screen.xml
│       │       │   ├── trigger_widget_answer.xml
│       │       │   ├── url_widget_answer.xml
│       │       │   ├── waveform_layout.xml
│       │       │   ├── widget_answer_dialog_layout.xml
│       │       │   └── widget_answer_text.xml
│       │       ├── menu/
│       │       │   ├── blank_form_list_menu.xml
│       │       │   ├── changes_reason_dialog.xml
│       │       │   ├── drafts.xml
│       │       │   ├── form_hierarchy_menu.xml
│       │       │   ├── form_menu.xml
│       │       │   ├── instance_uploader_menu.xml
│       │       │   ├── main_menu.xml
│       │       │   ├── project_preferences_menu.xml
│       │       │   ├── qr_code_scan_menu.xml
│       │       │   ├── saved_form_list_menu.xml
│       │       │   └── select_minimal_dialog_menu.xml
│       │       ├── navigation/
│       │       │   └── form_entry.xml
│       │       ├── raw/
│       │       │   ├── isrgrootx1.pem
│       │       │   └── keep.xml
│       │       ├── values/
│       │       │   ├── arrays.xml
│       │       │   ├── attrs.xml
│       │       │   ├── buttons.xml
│       │       │   ├── colors.xml
│       │       │   ├── date_time_pickers.xml
│       │       │   ├── dimens.xml
│       │       │   ├── form_entry_activity_theme.xml
│       │       │   ├── form_state_colors.xml
│       │       │   ├── leak_canary_config.xml
│       │       │   ├── material_colors.xml
│       │       │   ├── screen_names.xml
│       │       │   ├── settings_theme.xml
│       │       │   ├── shape.xml
│       │       │   ├── styles.xml
│       │       │   ├── theme.xml
│       │       │   └── typography.xml
│       │       ├── values-night/
│       │       │   └── material_colors.xml
│       │       └── xml/
│       │           ├── access_control_preferences.xml
│       │           ├── dev_tools_preferences.xml
│       │           ├── experimental_preferences.xml
│       │           ├── form_entry_access_preferences.xml
│       │           ├── form_management_preferences.xml
│       │           ├── form_metadata_preferences.xml
│       │           ├── identity_preferences.xml
│       │           ├── main_menu_access_preferences.xml
│       │           ├── maps_preferences.xml
│       │           ├── network_security_config.xml
│       │           ├── odk_server_preferences.xml
│       │           ├── project_display_preferences.xml
│       │           ├── project_management_preferences.xml
│       │           ├── project_preferences.xml
│       │           ├── provider_paths.xml
│       │           ├── server_preferences.xml
│       │           ├── user_interface_preferences.xml
│       │           └── user_settings_access_preferences.xml
│       ├── release/
│       │   └── google-services.json
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               ├── android/
│           │               │   ├── TestSettingsProvider.kt
│           │               │   ├── activities/
│           │               │   │   ├── CrashHandlerActivityTest.kt
│           │               │   │   ├── FirstLaunchActivityTest.kt
│           │               │   │   ├── FormFillingActivityTest.kt
│           │               │   │   └── FormHierarchyFragmentHostActivityTest.kt
│           │               │   ├── application/
│           │               │   │   ├── CollectSettingsChangeHandlerTest.kt
│           │               │   │   ├── RobolectricApplication.java
│           │               │   │   └── initialization/
│           │               │   │       ├── AnalyticsInitializerTest.kt
│           │               │   │       ├── CachedFormsCleanerTest.kt
│           │               │   │       ├── ExistingSettingsMigratorTest.kt
│           │               │   │       ├── GoogleDriveProjectsDeleterTest.kt
│           │               │   │       ├── SavepointsImporterTest.kt
│           │               │   │       ├── ScheduledWorkUpgradeTest.kt
│           │               │   │       └── upgrade/
│           │               │   │           └── BeforeProjectsInstallDetectorTest.kt
│           │               │   ├── audio/
│           │               │   │   ├── AudioButtonTest.java
│           │               │   │   ├── AudioControllerViewTest.java
│           │               │   │   ├── AudioRecordingControllerFragmentTest.java
│           │               │   │   ├── AudioRecordingFormErrorDialogFragmentTest.java
│           │               │   │   └── BackgroundAudioHelpDialogFragmentTest.java
│           │               │   ├── backgroundwork/
│           │               │   │   ├── AutoUpdateTaskSpecTest.kt
│           │               │   │   ├── FormUpdateAndInstanceSubmitSchedulerTest.kt
│           │               │   │   ├── SendFormsTaskSpecTest.kt
│           │               │   │   └── SyncFormsTaskSpecTest.kt
│           │               │   ├── configure/
│           │               │   │   └── qr/
│           │               │   │       ├── QRCodeActivityResultDelegateTest.kt
│           │               │   │       ├── QRCodeMenuProviderTest.kt
│           │               │   │       ├── QRCodeScannerFragmentTest.kt
│           │               │   │       └── QRCodeViewModelTest.kt
│           │               │   ├── database/
│           │               │   │   ├── DatabaseFormsRepositoryTest.java
│           │               │   │   ├── DatabaseInstancesRepositoryTest.kt
│           │               │   │   ├── DatabaseSavepointsRepositoryTest.kt
│           │               │   │   ├── FormDatabaseMigratorTest.java
│           │               │   │   ├── InstanceDatabaseMigratorTest.kt
│           │               │   │   └── entities/
│           │               │   │       └── EntitiesDatabaseMigratorTest.kt
│           │               │   ├── dependencies/
│           │               │   │   ├── BikramSambatTest.java
│           │               │   │   └── PersianCalendarTest.java
│           │               │   ├── dynamicpreload/
│           │               │   │   ├── DynamicPreloadExtraTest.kt
│           │               │   │   ├── DynamicPreloadParseProcessorTest.kt
│           │               │   │   ├── ExternalDataReaderTest.java
│           │               │   │   ├── ExternalDataUseCasesTest.kt
│           │               │   │   └── ExternalDataUtilTest.java
│           │               │   ├── entities/
│           │               │   │   ├── DatabaseEntitiesRepositoryTest.kt
│           │               │   │   ├── EntitiesRepositoryTest.kt
│           │               │   │   ├── InMemEntitiesRepositoryTest.kt
│           │               │   │   └── support/
│           │               │   │       └── EntitySameAsMatcher.kt
│           │               │   ├── external/
│           │               │   │   ├── FormUriActivityTest.kt
│           │               │   │   ├── FormsProviderTest.java
│           │               │   │   └── InstanceProviderTest.java
│           │               │   ├── fakes/
│           │               │   │   └── FakePermissionsProvider.kt
│           │               │   ├── formentry/
│           │               │   │   ├── AppStateFormSessionRepositoryTest.kt
│           │               │   │   ├── AudioVideoImageTextLabelTest.java
│           │               │   │   ├── AudioVideoImageTextLabelVisibilityTest.kt
│           │               │   │   ├── BackgroundAudioPermissionDialogFragmentTest.java
│           │               │   │   ├── BackgroundAudioViewModelTest.java
│           │               │   │   ├── FormEndTest.kt
│           │               │   │   ├── FormEndViewModelTest.kt
│           │               │   │   ├── FormEntryMenuProviderTest.kt
│           │               │   │   ├── FormEntryUseCasesTest.kt
│           │               │   │   ├── FormEntryViewModelTest.java
│           │               │   │   ├── FormLoadingDialogFragmentTest.java
│           │               │   │   ├── FormSessionRepositoryTest.kt
│           │               │   │   ├── InMemoryFormSessionRepositoryTest.kt
│           │               │   │   ├── PrinterWidgetViewModelTest.kt
│           │               │   │   ├── QuitFormDialogTest.kt
│           │               │   │   ├── RecordingHandlerTest.java
│           │               │   │   ├── RefreshFormListDialogFragmentTest.java
│           │               │   │   ├── SaveFormProgressDialogFragmentTest.java
│           │               │   │   ├── audit/
│           │               │   │   │   ├── AsyncTaskAuditEventWriterTest.java
│           │               │   │   │   ├── AuditConfigTest.java
│           │               │   │   │   ├── AuditEventCSVLineTest.java
│           │               │   │   │   ├── AuditEventLoggerTest.java
│           │               │   │   │   ├── AuditEventTest.java
│           │               │   │   │   ├── FormSaveViewModelTest.java
│           │               │   │   │   └── IdentityPromptViewModelTest.java
│           │               │   │   ├── backgroundlocation/
│           │               │   │   │   └── BackgroundLocationManagerTest.java
│           │               │   │   ├── repeats/
│           │               │   │   │   └── DeleteRepeatDialogFragmentTest.java
│           │               │   │   └── support/
│           │               │   │       └── InMemFormSessionRepository.kt
│           │               │   ├── formhierarchy/
│           │               │   │   ├── HierarchyListItemViewTest.kt
│           │               │   │   └── QuestionAnswerProcessorTest.kt
│           │               │   ├── formlists/
│           │               │   │   ├── DeleteBlankFormFragmentTest.kt
│           │               │   │   ├── blankformlist/
│           │               │   │   │   ├── BlankFormListItemTest.kt
│           │               │   │   │   ├── BlankFormListItemViewTest.kt
│           │               │   │   │   ├── BlankFormListMenuProviderTest.kt
│           │               │   │   │   └── BlankFormListViewModelTest.kt
│           │               │   │   └── savedformlist/
│           │               │   │       ├── DeleteSavedFormFragmentTest.kt
│           │               │   │       ├── SavedFormListListMenuProviderTest.kt
│           │               │   │       └── SavedFormListViewModelTest.kt
│           │               │   ├── formmanagement/
│           │               │   │   ├── DownloadMediaFilesServerFormUseCasesTest.kt
│           │               │   │   ├── DownloadUpdatesServerFormUseCasesTest.kt
│           │               │   │   ├── FetchFormDetailsServerFormUseCasesTest.kt
│           │               │   │   ├── FilterFormsToAddTest.kt
│           │               │   │   ├── FormFillingIntentFactoryTest.kt
│           │               │   │   ├── FormSourceExceptionMapperTest.kt
│           │               │   │   ├── FormsDataServiceTest.kt
│           │               │   │   ├── LocalFormUseCasesTest.java
│           │               │   │   ├── ServerFormsSynchronizerTest.java
│           │               │   │   ├── ShouldAddFormFileTest.java
│           │               │   │   ├── download/
│           │               │   │   │   ├── FormDownloadExceptionMapperTest.kt
│           │               │   │   │   └── ServerFormDownloaderTest.java
│           │               │   │   ├── drafts/
│           │               │   │   │   └── DraftsMenuProviderTest.kt
│           │               │   │   ├── formmap/
│           │               │   │   │   └── FormMapViewModelTest.kt
│           │               │   │   └── metadata/
│           │               │   │       └── FormMetadataParserTest.kt
│           │               │   ├── fragments/
│           │               │   │   ├── dialogs/
│           │               │   │   │   ├── FormsDownloadResultDialogTest.kt
│           │               │   │   │   ├── RangePickerDialogFragmentTest.kt
│           │               │   │   │   ├── SelectMinimalDialogTest.java
│           │               │   │   │   ├── SelectMultiMinimalDialogTest.java
│           │               │   │   │   └── SelectOneMinimalDialogTest.java
│           │               │   │   └── support/
│           │               │   │       └── DialogFragmentHelpers.java
│           │               │   ├── geo/
│           │               │   │   └── MapFragmentFactoryImplTest.kt
│           │               │   ├── instancemanagement/
│           │               │   │   ├── InstanceDeleterTest.kt
│           │               │   │   ├── InstanceExtKtTest.kt
│           │               │   │   ├── InstanceListItemViewTest.kt
│           │               │   │   ├── InstancesDataServiceTest.kt
│           │               │   │   ├── LocalInstancesUseCasesTest.kt
│           │               │   │   ├── autosend/
│           │               │   │   │   ├── AutoSendSettingsProviderTest.kt
│           │               │   │   │   ├── FormExtTest.kt
│           │               │   │   │   └── InstanceAutoSendFetcherTest.kt
│           │               │   │   └── send/
│           │               │   │       ├── ReadyToSendBannerTest.kt
│           │               │   │       └── ReadyToSendViewModelTest.kt
│           │               │   ├── javarosawrapper/
│           │               │   │   ├── FakeFormController.java
│           │               │   │   └── FormControllerTest.java
│           │               │   ├── location/
│           │               │   │   └── client/
│           │               │   │       ├── FakeLocationClient.java
│           │               │   │       └── MaxAccuracyWithinTimeoutLocationClientWrapperTest.java
│           │               │   ├── mainmenu/
│           │               │   │   ├── CurrentProjectViewModelTest.kt
│           │               │   │   ├── MainMenuActivityTest.kt
│           │               │   │   ├── MainMenuButtonTest.kt
│           │               │   │   ├── MainMenuViewModelTest.kt
│           │               │   │   ├── PermissionsDialogFragmentTest.kt
│           │               │   │   └── RequestPermissionsViewModelTest.kt
│           │               │   ├── notifications/
│           │               │   │   └── NotificationManagerNotifierTest.kt
│           │               │   ├── preferences/
│           │               │   │   ├── AppConfigurationGeneratorTest.kt
│           │               │   │   ├── ProjectPreferencesViewModelTest.kt
│           │               │   │   ├── ServerPreferencesAdderTest.java
│           │               │   │   ├── dialogs/
│           │               │   │   │   ├── AdminPasswordDialogFragmentTest.kt
│           │               │   │   │   ├── ChangeAdminPasswordDialogTest.kt
│           │               │   │   │   ├── DeleteProjectDialogTest.kt
│           │               │   │   │   ├── ResetProgressDialogTest.kt
│           │               │   │   │   └── ServerAuthDialogFragmentTest.java
│           │               │   │   ├── screens/
│           │               │   │   │   ├── FormEntryAccessPreferencesFragmentTest.kt
│           │               │   │   │   ├── FormManagementPreferencesFragmentTest.kt
│           │               │   │   │   ├── FormMetadataPreferencesFragmentTest.kt
│           │               │   │   │   ├── IdentityPreferencesFragmentTest.kt
│           │               │   │   │   ├── MainMenuAccessPreferencesTest.kt
│           │               │   │   │   ├── MapsPreferencesFragmentTest.kt
│           │               │   │   │   ├── ProjectDisplayPreferencesFragmentTest.kt
│           │               │   │   │   ├── ProjectPreferencesFragmentTest.kt
│           │               │   │   │   └── UserInterfacePreferencesFragmentTest.kt
│           │               │   │   └── source/
│           │               │   │       ├── SettingsStoreTest.kt
│           │               │   │       ├── SharedPreferencesSettingsProviderTest.kt
│           │               │   │       └── SharedPreferencesSettingsTest.kt
│           │               │   ├── projects/
│           │               │   │   ├── ExistingProjectMigratorTest.kt
│           │               │   │   ├── ManualProjectCreatorDialogTest.kt
│           │               │   │   ├── ProjectCreatorImplTest.kt
│           │               │   │   ├── ProjectDeleterTest.kt
│           │               │   │   ├── ProjectIconViewTest.kt
│           │               │   │   ├── ProjectListItemViewTest.kt
│           │               │   │   ├── ProjectResetterTest.kt
│           │               │   │   ├── ProjectSettingsDialogTest.kt
│           │               │   │   ├── ProjectsDataServiceTest.kt
│           │               │   │   ├── QrCodeProjectCreatorDialogTest.kt
│           │               │   │   └── SettingsConnectionMatcherImplTest.kt
│           │               │   ├── savepoints/
│           │               │   │   └── SavepointUseCasesTest.kt
│           │               │   ├── storage/
│           │               │   │   └── StoragePathProviderTest.kt
│           │               │   ├── support/
│           │               │   │   ├── CollectHelpers.java
│           │               │   │   ├── Matchers.kt
│           │               │   │   ├── MockFormEntryPromptBuilder.java
│           │               │   │   ├── SwipableParentActivity.kt
│           │               │   │   └── WidgetTestActivity.kt
│           │               │   ├── tasks/
│           │               │   │   └── SaveFormIndexTaskTest.java
│           │               │   ├── utilities/
│           │               │   │   ├── AdminPasswordProviderTest.java
│           │               │   │   ├── AppearancesTest.kt
│           │               │   │   ├── ArrayUtilsTest.java
│           │               │   │   ├── CSVUtilsTest.java
│           │               │   │   ├── ChangeLockProviderTest.kt
│           │               │   │   ├── ExternalAppIntentProviderTest.kt
│           │               │   │   ├── ExternalAppUtilsTest.java
│           │               │   │   ├── FileUtilsTest.java
│           │               │   │   ├── FormNameUtilsTest.java
│           │               │   │   ├── FormsDownloadResultInterpreterTest.kt
│           │               │   │   ├── FormsRepositoryProviderTest.kt
│           │               │   │   ├── FormsUploadResultInterpreterTest.kt
│           │               │   │   ├── HtmlUtilsTest.kt
│           │               │   │   ├── ImageCompressionControllerTest.kt
│           │               │   │   ├── InstanceAutoDeleteCheckerTest.kt
│           │               │   │   ├── InstanceUploaderUtilsTest.java
│           │               │   │   ├── InstancesRepositoryProviderTest.kt
│           │               │   │   ├── MediaUtilsTest.kt
│           │               │   │   ├── MyanmarDateUtilsTest.java
│           │               │   │   ├── QuestionFontSizeUtilsTest.java
│           │               │   │   ├── StubFormController.kt
│           │               │   │   └── WebCredentialsUtilsTest.java
│           │               │   ├── version/
│           │               │   │   └── VersionInformationTest.java
│           │               │   ├── views/
│           │               │   │   ├── ChoicesRecyclerViewTest.java
│           │               │   │   ├── TrackingTouchSliderTest.java
│           │               │   │   └── helpers/
│           │               │   │       └── PromptAutoplayerTest.java
│           │               │   └── widgets/
│           │               │       ├── AnnotateWidgetTest.java
│           │               │       ├── ArbitraryFileWidgetTest.kt
│           │               │       ├── AudioWidgetTest.java
│           │               │       ├── BarcodeWidgetTest.kt
│           │               │       ├── BearingWidgetTest.java
│           │               │       ├── CounterWidgetTest.kt
│           │               │       ├── DecimalWidgetTest.java
│           │               │       ├── DrawWidgetTest.java
│           │               │       ├── ExArbitraryFileWidgetTest.kt
│           │               │       ├── ExAudioWidgetTest.java
│           │               │       ├── ExDecimalWidgetTest.java
│           │               │       ├── ExImageWidgetTest.java
│           │               │       ├── ExIntegerWidgetTest.java
│           │               │       ├── ExStringWidgetTest.kt
│           │               │       ├── ExVideoWidgetTest.kt
│           │               │       ├── GeoPointMapWidgetTest.java
│           │               │       ├── GeoPointWidgetTest.java
│           │               │       ├── GeoShapeWidgetTest.java
│           │               │       ├── GeoTraceWidgetTest.java
│           │               │       ├── ImageWidgetTest.java
│           │               │       ├── IntegerWidgetTest.java
│           │               │       ├── OSMWidgetTest.java
│           │               │       ├── PrinterWidgetTest.kt
│           │               │       ├── QuestionWidgetTest.java
│           │               │       ├── RatingWidgetTest.java
│           │               │       ├── SignatureWidgetTest.java
│           │               │       ├── StringNumberWidgetTest.java
│           │               │       ├── StringWidgetTest.kt
│           │               │       ├── TriggerWidgetTest.java
│           │               │       ├── UrlWidgetTest.java
│           │               │       ├── VideoWidgetTest.kt
│           │               │       ├── WidgetFactoryTest.kt
│           │               │       ├── base/
│           │               │       │   ├── BinaryWidgetTest.java
│           │               │       │   ├── FileWidgetTest.java
│           │               │       │   ├── GeneralExStringWidgetTest.java
│           │               │       │   ├── GeneralSelectMultiWidgetTest.java
│           │               │       │   ├── GeneralSelectOneWidgetTest.java
│           │               │       │   ├── GeneralStringWidgetTest.java
│           │               │       │   ├── QuestionWidgetTest.java
│           │               │       │   ├── SelectWidgetTest.java
│           │               │       │   └── WidgetTest.java
│           │               │       ├── datetime/
│           │               │       │   ├── DateTimeUtilsTest.java
│           │               │       │   ├── DateTimeWidgetTest.java
│           │               │       │   ├── DateTimeWidgetUtilsTest.java
│           │               │       │   ├── DateWidgetTest.java
│           │               │       │   ├── DaylightSavingTest.java
│           │               │       │   ├── TimeWidgetTest.java
│           │               │       │   └── pickers/
│           │               │       │       ├── BikramSambatDatePickerDialogTest.java
│           │               │       │       ├── BuddhistDatePickerDialogTest.kt
│           │               │       │       ├── CopticDatePickerDialogTest.java
│           │               │       │       ├── EthiopianDatePickerDialogTest.java
│           │               │       │       ├── IslamicDatePickerDialogTest.java
│           │               │       │       ├── MyanmarDatePickerDialogTest.java
│           │               │       │       └── PersianDatePickerDialogTest.java
│           │               │       ├── items/
│           │               │       │   ├── LikertWidgetTest.java
│           │               │       │   ├── ListMultiWidgetTest.java
│           │               │       │   ├── ListWidgetTest.java
│           │               │       │   ├── RankingWidgetTest.java
│           │               │       │   ├── SelectChoicesMapDataTest.kt
│           │               │       │   ├── SelectImageMapWidgetTest.java
│           │               │       │   ├── SelectMultiImageMapWidgetTest.java
│           │               │       │   ├── SelectMultiMinimalWidgetTest.java
│           │               │       │   ├── SelectMultiWidgetTest.java
│           │               │       │   ├── SelectOneFromMapDialogFragmentTest.kt
│           │               │       │   ├── SelectOneFromMapWidgetTest.kt
│           │               │       │   ├── SelectOneImageMapWidgetTest.java
│           │               │       │   ├── SelectOneMinimalWidgetTest.java
│           │               │       │   └── SelectOneWidgetTest.java
│           │               │       ├── range/
│           │               │       │   ├── RangeDecimalWidgetTest.java
│           │               │       │   ├── RangeIntegerWidgetTest.java
│           │               │       │   ├── RangePickerWidgetTest.kt
│           │               │       │   └── RangePickerWidgetUtilsTest.kt
│           │               │       ├── support/
│           │               │       │   ├── FakeQuestionMediaManager.java
│           │               │       │   ├── FakeWaitingForDataRegistry.java
│           │               │       │   ├── FormElementFixtures.kt
│           │               │       │   ├── FormEntryPromptSelectChoiceLoader.kt
│           │               │       │   ├── GeoWidgetHelpers.java
│           │               │       │   ├── NoOpMapFragment.kt
│           │               │       │   ├── QuestionWidgetHelpers.java
│           │               │       │   └── SynchronousImageLoader.kt
│           │               │       ├── utilities/
│           │               │       │   ├── ActivityGeoDataRequesterTest.java
│           │               │       │   ├── AudioRecorderRecordingStatusHandlerTest.java
│           │               │       │   ├── ExternalAppRecordingRequesterTest.kt
│           │               │       │   ├── FileRequesterImplTest.kt
│           │               │       │   ├── GeoPolyDialogFragmentTest.kt
│           │               │       │   ├── GeoWidgetUtilsTest.kt
│           │               │       │   ├── GetContentAudioFileRequesterTest.kt
│           │               │       │   ├── InternalRecordingRequesterTest.java
│           │               │       │   ├── RangeWidgetUtilsTest.java
│           │               │       │   ├── RecordingRequesterProviderTest.java
│           │               │       │   ├── StringRequesterImplTest.kt
│           │               │       │   └── StringWidgetUtilsTest.java
│           │               │       ├── viewmodels/
│           │               │       │   ├── DateTimeViewModelTest.java
│           │               │       │   └── QuestionViewModelTest.kt
│           │               │       └── warnings/
│           │               │           ├── SpacesInUnderlyingValuesTest.java
│           │               │           └── SpacesInUnderlyingValuesWarningTest.java
│           │               └── geo/
│           │                   └── javarosa/
│           │                       └── IntersectsFunctionHandlerTest.kt
│           └── resources/
│               ├── forms/
│               │   └── simple-search-external-csv.xml
│               ├── media/
│               │   └── simple-search-external-csv-fruits.csv
│               └── robolectric.properties
├── config/
│   ├── checkstyle.xml
│   ├── lint.xml
│   ├── pmd-ruleset.xml
│   └── quality.gradle
├── crash-handler/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── crashhandler/
│       │   │                   ├── CrashHandler.kt
│       │   │                   ├── CrashView.kt
│       │   │                   └── MockCrashView.kt
│       │   └── res/
│       │       └── layout/
│       │           └── crash_layout.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── crashhandler/
│                               └── CrashHandlerTest.kt
├── create-release.sh
├── db/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── db/
│       │                       └── sqlite/
│       │                           ├── AltDatabasePathContext.kt
│       │                           ├── CursorExt.kt
│       │                           ├── CustomSQLiteQueryBuilder.java
│       │                           ├── CustomSQLiteQueryExecutor.java
│       │                           ├── DatabaseConnection.kt
│       │                           ├── DatabaseMigrator.java
│       │                           ├── MigrationListDatabaseMigrator.kt
│       │                           ├── RowNumbers.kt
│       │                           ├── SQLiteColumns.kt
│       │                           ├── SQLiteDatabaseExt.kt
│       │                           ├── SQLiteUtils.java
│       │                           ├── SqlQuery.kt
│       │                           └── SynchronizedDatabaseConnection.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── db/
│                               └── sqlite/
│                                   ├── CustomSQLiteQueryBuilderTest.java
│                                   ├── DatabaseConnectionTest.kt
│                                   ├── RowNumbersTest.kt
│                                   ├── SQLiteUtilsTest.java
│                                   ├── SqlQueryTest.kt
│                                   ├── SqliteDatabaseExtTest.kt
│                                   └── support/
│                                       └── NoopMigrator.kt
├── debug.keystore
├── docs/
│   ├── ANALYTICS-QUESTIONS.md
│   ├── CODE-GUIDELINES.md
│   ├── CONTRIBUTING.md
│   ├── STATE.md
│   ├── TEST-GUIDELINES.md
│   ├── WIDGETS.md
│   └── WINDOWS-DEV-SETUP.md
├── download-robolectric-deps.sh
├── draw/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── draw/
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── DrawActivity.java
│       │   │                   ├── DrawView.kt
│       │   │                   ├── DrawViewModel.kt
│       │   │                   ├── PenColorPickerDialog.kt
│       │   │                   ├── PenColorPickerViewModel.kt
│       │   │                   ├── QuitDrawingDialog.kt
│       │   │                   └── RobolectricApplication.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── draw_layout.xml
│       │           └── quit_drawing_dialog_layout.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── draw/
│           │                   ├── DrawActivityTest.kt
│           │                   ├── PenColorPickerDialogTest.kt
│           │                   └── PenColorPickerViewModelTest.kt
│           └── resources/
│               └── robolectric.properties
├── entities/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── entities/
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── LocalEntityUseCases.kt
│       │   │                   ├── browser/
│       │   │                   │   ├── EntitiesFragment.kt
│       │   │                   │   ├── EntitiesViewModel.kt
│       │   │                   │   ├── EntityBrowserActivity.kt
│       │   │                   │   ├── EntityItem.kt
│       │   │                   │   └── EntityListsFragment.kt
│       │   │                   ├── javarosa/
│       │   │                   │   ├── filter/
│       │   │                   │   │   ├── LocalEntitiesFilterStrategy.kt
│       │   │                   │   │   └── PullDataFunctionHandler.kt
│       │   │                   │   ├── finalization/
│       │   │                   │   │   ├── EntitiesExtra.kt
│       │   │                   │   │   ├── EntityFormFinalizationProcessor.kt
│       │   │                   │   │   ├── FormEntity.kt
│       │   │                   │   │   └── InvalidEntity.kt
│       │   │                   │   ├── intance/
│       │   │                   │   │   ├── LocalEntitiesExternalInstanceParserFactory.kt
│       │   │                   │   │   ├── LocalEntitiesInstanceAdapter.kt
│       │   │                   │   │   └── LocalEntitiesInstanceProvider.kt
│       │   │                   │   ├── parse/
│       │   │                   │   │   ├── EntityFormExtra.kt
│       │   │                   │   │   ├── EntityFormParseProcessor.kt
│       │   │                   │   │   ├── EntitySchema.kt
│       │   │                   │   │   ├── EntityXFormParserFactory.kt
│       │   │                   │   │   ├── SaveTo.kt
│       │   │                   │   │   ├── StringExt.kt
│       │   │                   │   │   └── XPathExpressionExt.kt
│       │   │                   │   └── spec/
│       │   │                   │       ├── EntityAction.kt
│       │   │                   │       ├── EntityFormParser.kt
│       │   │                   │       ├── FormEntityElement.kt
│       │   │                   │       └── UnrecognizedEntityVersionException.kt
│       │   │                   ├── server/
│       │   │                   │   └── EntitySource.kt
│       │   │                   └── storage/
│       │   │                       ├── EntitiesRepository.kt
│       │   │                       ├── Entity.kt
│       │   │                       ├── EntityList.kt
│       │   │                       ├── InMemEntitiesRepository.kt
│       │   │                       └── QueryException.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── entities_layout.xml
│       │       │   ├── entity_list_item_layout.xml
│       │       │   └── list_layout.xml
│       │       └── navigation/
│       │           └── entities_nav.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── entities/
│                               ├── LocalEntityUseCasesTest.kt
│                               ├── browser/
│                               │   └── EntityItemTest.kt
│                               └── javarosa/
│                                   ├── EntitiesTest.kt
│                                   ├── EntityFormFinalizationProcessorTest.kt
│                                   ├── EntityFormParseProcessorTest.kt
│                                   ├── EntityFormParserTest.kt
│                                   ├── LocalEntitiesInstanceProviderTest.kt
│                                   ├── filter/
│                                   │   ├── LocalEntitiesFilterStrategyTest.kt
│                                   │   └── PullDataFunctionHandlerTest.kt
│                                   ├── parse/
│                                   │   ├── StringExtTest.kt
│                                   │   └── XPathExpressionExtTest.kt
│                                   └── support/
│                                       └── EntityXFormsElement.kt
├── errors/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── errors/
│       │   │                   ├── ErrorActivity.kt
│       │   │                   ├── ErrorAdapter.kt
│       │   │                   └── ErrorItem.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── activity_error.xml
│       │           └── error_item.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── errors/
│           │                   └── ErrorActivityTest.kt
│           └── resources/
│               └── robolectric.properties
├── external-app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── externalapp/
│       │                       └── ExternalAppUtils.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── externalapp/
│                               └── ExternalAppUtilsTest.kt
├── forms/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── forms/
│       │                       ├── Form.java
│       │                       ├── FormListItem.kt
│       │                       ├── FormSource.java
│       │                       ├── FormSourceException.kt
│       │                       ├── FormsRepository.java
│       │                       ├── ManifestFile.kt
│       │                       ├── MediaFile.kt
│       │                       ├── instances/
│       │                       │   ├── Instance.java
│       │                       │   └── InstancesRepository.java
│       │                       └── savepoints/
│       │                           ├── Savepoint.kt
│       │                           └── SavepointsRepository.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── forms/
│                               └── instances/
│                                   └── InstanceTest.kt
├── forms-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── formstest/
│       │                       ├── FormFixtures.kt
│       │                       ├── FormUtils.kt
│       │                       ├── FormsRepositoryTest.java
│       │                       ├── InMemFormsRepository.java
│       │                       ├── InMemInstancesRepository.java
│       │                       ├── InMemSavepointsRepository.kt
│       │                       ├── InstanceFixtures.kt
│       │                       ├── InstanceUtils.kt
│       │                       ├── InstancesRepositoryTest.kt
│       │                       └── SavepointsRepositoryTest.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── formstest/
│                               ├── InMemFormsRepositoryTest.java
│                               ├── InMemInstancesRepositoryTest.kt
│                               └── InMemSavepointsRepositoryTest.kt
├── fragments-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── fragmentstest/
│                               └── FragmentScenarioLauncherRule.kt
├── geo/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── geo/
│       │   │                   ├── Constants.kt
│       │   │                   ├── DaggerSetup.kt
│       │   │                   ├── GeoActivityUtils.kt
│       │   │                   ├── GeoUtils.kt
│       │   │                   ├── analytics/
│       │   │                   │   └── AnalyticsEvents.kt
│       │   │                   ├── geopoint/
│       │   │                   │   ├── AccuracyProgressView.kt
│       │   │                   │   ├── AccuracyStatusView.kt
│       │   │                   │   ├── GeoPointActivity.kt
│       │   │                   │   ├── GeoPointDialogFragment.kt
│       │   │                   │   ├── GeoPointMapActivity.java
│       │   │                   │   ├── GeoPointViewModel.kt
│       │   │                   │   └── LocationAccuracy.kt
│       │   │                   ├── geopoly/
│       │   │                   │   ├── GeoPolyFragment.kt
│       │   │                   │   ├── GeoPolySettingsDialogFragment.java
│       │   │                   │   ├── GeoPolyUtils.kt
│       │   │                   │   ├── GeoPolyViewModel.kt
│       │   │                   │   └── InfoDialog.kt
│       │   │                   ├── javarosa/
│       │   │                   │   └── IntersectsFunctionHandler.kt
│       │   │                   └── selection/
│       │   │                       ├── MappableSelectItem.kt
│       │   │                       ├── SelectionMapFragment.kt
│       │   │                       └── SelectionSummarySheet.kt
│       │   └── res/
│       │       ├── color/
│       │       │   └── fab_surface_background_color_less_transparent_disabled.xml
│       │       ├── drawable/
│       │       │   ├── ic_add_location.xml
│       │       │   ├── ic_backspace.xml
│       │       │   ├── ic_crop_frame.xml
│       │       │   ├── ic_distance.xml
│       │       │   ├── ic_info.xml
│       │       │   ├── ic_layers.xml
│       │       │   ├── ic_my_location.xml
│       │       │   ├── ic_note_add.xml
│       │       │   ├── ic_pause_36.xml
│       │       │   └── property_divider.xml
│       │       ├── layout/
│       │       │   ├── accuracy_progress_layout.xml
│       │       │   ├── accuracy_status_layout.xml
│       │       │   ├── geopoint_dialog.xml
│       │       │   ├── geopoint_layout.xml
│       │       │   ├── geopoly_dialog.xml
│       │       │   ├── geopoly_layout.xml
│       │       │   ├── property.xml
│       │       │   ├── selection_map_layout.xml
│       │       │   ├── selection_summary_sheet_layout.xml
│       │       │   └── simple_spinner_dropdown_item.xml
│       │       ├── layout-land/
│       │       │   ├── geopoint_layout.xml
│       │       │   └── geopoly_layout.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── fab_surface.xml
│       │           └── force_light_surface_overlay.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── geo/
│           │                   ├── GeoUtilsTest.kt
│           │                   ├── geopoint/
│           │                   │   ├── AccuracyProgressViewTest.kt
│           │                   │   ├── AccuracyStatusViewTest.kt
│           │                   │   ├── GeoPointActivityTest.kt
│           │                   │   ├── GeoPointDialogFragmentTest.kt
│           │                   │   ├── GeoPointMapActivityTest.java
│           │                   │   └── LocationTrackerGeoPointViewModelTest.kt
│           │                   ├── geopoly/
│           │                   │   ├── GeoPolyFragmentTest.kt
│           │                   │   ├── GeoPolySettingsDialogFragmentTest.java
│           │                   │   ├── GeoPolyUtilsTest.kt
│           │                   │   ├── GeoPolyViewModelTest.kt
│           │                   │   └── InfoContentTest.kt
│           │                   ├── selection/
│           │                   │   ├── SelectionMapFragmentTest.kt
│           │                   │   └── SelectionSummarySheetTest.kt
│           │                   └── support/
│           │                       ├── AccuracyStatusViewMatcher.kt
│           │                       ├── FakeLocationTracker.kt
│           │                       ├── FakeMapFragment.kt
│           │                       ├── Fixtures.kt
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── google-maps/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── googlemaps/
│           │                   ├── BitmapDescriptorCache.kt
│           │                   ├── DaggerSetup.kt
│           │                   ├── GoogleMapConfigurator.java
│           │                   ├── GoogleMapFragment.java
│           │                   ├── GoogleMapsMapBoxOfflineTileProvider.java
│           │                   ├── MapPointExt.kt
│           │                   ├── circles/
│           │                   │   └── CircleFeature.kt
│           │                   └── scaleview/
│           │                       ├── Drawer.java
│           │                       ├── MapScaleModel.java
│           │                       ├── MapScaleView.java
│           │                       ├── Scale.java
│           │                       ├── Scales.java
│           │                       └── ViewConfig.java
│           └── res/
│               ├── layout/
│               │   └── map_layout.xml
│               └── values/
│                   └── attrs.xml
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── icons/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── res/
│               └── drawable/
│                   ├── ic_add_white_24.xml
│                   ├── ic_baseline_add_24.xml
│                   ├── ic_baseline_barcode_scanner_white_24.xml
│                   ├── ic_baseline_calendar_today_white_24.xml
│                   ├── ic_baseline_check_24.xml
│                   ├── ic_baseline_collapse_24.xml
│                   ├── ic_baseline_done_all_24.xml
│                   ├── ic_baseline_draw_white_24.xml
│                   ├── ic_baseline_expand_24.xml
│                   ├── ic_baseline_explore_white_24.xml
│                   ├── ic_baseline_format_list_bulleted_white_24.xml
│                   ├── ic_baseline_format_list_numbered_white_24.xml
│                   ├── ic_baseline_language_24.xml
│                   ├── ic_baseline_layers_24.xml
│                   ├── ic_baseline_library_music_white_24.xml
│                   ├── ic_baseline_list_24.xml
│                   ├── ic_baseline_location_off_24.xml
│                   ├── ic_baseline_location_on_24.xml
│                   ├── ic_baseline_location_on_white_24.xml
│                   ├── ic_baseline_markup_white_24.xml
│                   ├── ic_baseline_mic_24.xml
│                   ├── ic_baseline_mic_off_24.xml
│                   ├── ic_baseline_mic_white_24.xml
│                   ├── ic_baseline_my_location_white_24.xml
│                   ├── ic_baseline_open_in_new_white_24.xml
│                   ├── ic_baseline_photo_camera_white_24.xml
│                   ├── ic_baseline_photo_library_white_24.xml
│                   ├── ic_baseline_print_white_24.xml
│                   ├── ic_baseline_qr_code_2_add_24.xml
│                   ├── ic_baseline_remove_24.xml
│                   ├── ic_baseline_rule_24.xml
│                   ├── ic_baseline_settings_24.xml
│                   ├── ic_baseline_signature_white_24.xml
│                   ├── ic_baseline_time_filled_white_24.xml
│                   ├── ic_baseline_visibility_24.xml
│                   ├── ic_baseline_warning_24.xml
│                   ├── ic_baseline_wifi_off_24.xml
│                   ├── ic_clear_white.xml
│                   ├── ic_close.xml
│                   ├── ic_color_lens_white.xml
│                   ├── ic_delete.xml
│                   ├── ic_delete_24.xml
│                   ├── ic_edit.xml
│                   ├── ic_map_marker_big.xml
│                   ├── ic_map_marker_small.xml
│                   ├── ic_map_marker_with_hole_big.xml
│                   ├── ic_map_marker_with_hole_small.xml
│                   ├── ic_map_point.xml
│                   ├── ic_notification_small.xml
│                   ├── ic_outline_info_24.xml
│                   ├── ic_outline_polygon_white_24.xml
│                   ├── ic_outline_polyline_white_24.xml
│                   ├── ic_save.xml
│                   └── ic_save_white.xml
├── image-loader/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── imageloader/
│                               ├── GlideImageLoader.kt
│                               └── svg/
│                                   ├── SvgDecoder.kt
│                                   ├── SvgDrawableTranscoder.kt
│                                   ├── SvgModule.kt
│                                   └── SvgSoftwareLayerSetter.kt
├── lists/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── lists/
│       │   │                   ├── EmptyListView.kt
│       │   │                   ├── RecyclerViewUtils.kt
│       │   │                   └── selects/
│       │   │                       ├── MultiSelectAdapter.kt
│       │   │                       ├── MultiSelectControlsFragment.kt
│       │   │                       ├── MultiSelectListFragment.kt
│       │   │                       ├── MultiSelectViewModel.kt
│       │   │                       ├── SelectItem.kt
│       │   │                       └── SingleSelectViewModel.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── empty_list_view.xml
│       │       │   ├── multi_select_controls_layout.xml
│       │       │   └── multi_select_list.xml
│       │       └── values/
│       │           └── attrs.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── lists/
│           │                   ├── EmptyListViewTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   └── selects/
│           │                       ├── MultiSelectAdapterTest.kt
│           │                       ├── MultiSelectControlsFragmentTest.kt
│           │                       ├── MultiSelectListFragmentTest.kt
│           │                       ├── MultiSelectViewModelTest.kt
│           │                       ├── SingleSelectViewModelTest.kt
│           │                       └── support/
│           │                           └── TextAndCheckboxViewHolder.kt
│           └── resources/
│               └── robolectric.properties
├── location/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── location/
│       │                       ├── AndroidLocationClient.java
│       │                       ├── BaseLocationClient.kt
│       │                       ├── DaggerSetup.kt
│       │                       ├── GoogleFusedLocationClient.kt
│       │                       ├── Location.kt
│       │                       ├── LocationClient.java
│       │                       ├── LocationClientProvider.kt
│       │                       ├── LocationUtils.kt
│       │                       ├── satellites/
│       │                       │   ├── GpsStatusSatelliteInfoClient.kt
│       │                       │   └── SatelliteInfoClient.kt
│       │                       └── tracker/
│       │                           ├── ForegroundServiceLocationTracker.kt
│       │                           └── LocationTracker.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── location/
│           │                   ├── AndroidLocationClientTest.java
│           │                   ├── GoogleFusedLocationClientTest.kt
│           │                   ├── LocationClientProviderTest.kt
│           │                   ├── LocationUtilsTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   ├── TestClientListener.java
│           │                   ├── TestLocationListener.java
│           │                   └── tracker/
│           │                       ├── ForegroundServiceLocationTrackerTest.kt
│           │                       ├── LocationTrackerServiceTest.kt
│           │                       └── LocationTrackerTest.kt
│           └── resources/
│               └── robolectric.properties
├── mapbox/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── mapbox/
│           │                   ├── DynamicPolyLineFeature.kt
│           │                   ├── DynamicPolygonFeature.kt
│           │                   ├── LineFeature.kt
│           │                   ├── MapBoxInitializationFragment.kt
│           │                   ├── MapFeature.kt
│           │                   ├── MapUtils.kt
│           │                   ├── MapboxMapConfigurator.java
│           │                   ├── MapboxMapFragment.kt
│           │                   ├── MarkerFeature.kt
│           │                   ├── StaticPolyLineFeature.kt
│           │                   ├── StaticPolygonFeature.kt
│           │                   └── TileHttpServer.java
│           └── res/
│               └── layout/
│                   └── mapbox_fragment_layout.xml
├── maps/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── maps/
│       │   │                   ├── AnalyticsEvents.kt
│       │   │                   ├── MapConfigurator.kt
│       │   │                   ├── MapConsts.kt
│       │   │                   ├── MapFragment.kt
│       │   │                   ├── MapFragmentFactory.kt
│       │   │                   ├── MapPoint.kt
│       │   │                   ├── MapViewModel.kt
│       │   │                   ├── MapViewModelMapFragment.kt
│       │   │                   ├── ZoomObserver.kt
│       │   │                   ├── circles/
│       │   │                   │   ├── CircleDescription.kt
│       │   │                   │   └── CurrentLocationDelegate.kt
│       │   │                   ├── layers/
│       │   │                   │   ├── DirectoryReferenceLayerRepository.kt
│       │   │                   │   ├── MapFragmentReferenceLayerUtils.kt
│       │   │                   │   ├── MbtilesFile.java
│       │   │                   │   ├── OfflineMapLayersImporterAdapter.kt
│       │   │                   │   ├── OfflineMapLayersImporterDialogFragment.kt
│       │   │                   │   ├── OfflineMapLayersPickerAdapter.kt
│       │   │                   │   ├── OfflineMapLayersPickerBottomSheetDialogFragment.kt
│       │   │                   │   ├── OfflineMapLayersViewModel.kt
│       │   │                   │   ├── ReferenceLayerRepository.kt
│       │   │                   │   └── TileSource.java
│       │   │                   ├── markers/
│       │   │                   │   ├── MarkerDescription.kt
│       │   │                   │   ├── MarkerIconCreator.kt
│       │   │                   │   └── MarkerIconDescription.kt
│       │   │                   └── traces/
│       │   │                       ├── LineDescription.kt
│       │   │                       ├── PolygonDescription.kt
│       │   │                       └── TraceDescription.kt
│       │   └── res/
│       │       ├── drawable/
│       │       │   └── ic_crosshairs.xml
│       │       └── layout/
│       │           ├── offline_map_layers_importer.xml
│       │           ├── offline_map_layers_importer_item.xml
│       │           ├── offline_map_layers_picker.xml
│       │           └── offline_map_layers_picker_item.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── maps/
│           │                   ├── LineDescriptionTest.kt
│           │                   ├── MarkerIconDescriptionTest.kt
│           │                   ├── PolygonDescriptionTest.kt
│           │                   ├── RobolectricApplication.kt
│           │                   ├── TraceDescriptionTest.kt
│           │                   └── layers/
│           │                       ├── DirectoryReferenceLayerRepositoryTest.kt
│           │                       ├── InMemReferenceLayerRepository.kt
│           │                       ├── MapFragmentReferenceLayerUtilsTest.kt
│           │                       ├── OfflineMapLayersImporterDialogFragmentTest.kt
│           │                       └── OfflineMapLayersPickerBottomSheetDialogFragmentTest.kt
│           └── resources/
│               └── robolectric.properties
├── material/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── material/
│       │   │                   ├── BottomSheetBehavior.kt
│       │   │                   ├── ErrorsPill.kt
│       │   │                   ├── MaterialFullScreenDialogFragment.kt
│       │   │                   ├── MaterialPill.kt
│       │   │                   ├── MaterialProgressDialogFragment.java
│       │   │                   └── Pill.kt
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── pill.xml
│       │       │   └── progress_dialog.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── material_3_button_icon_end_style.xml
│       │           └── material_full_screen_dialog_theme.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── material/
│                               ├── ErrorsPillTest.kt
│                               └── MaterialProgressDialogFragmentTest.java
├── metadata/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── metadata/
│       │                       ├── InstallIDProvider.kt
│       │                       └── PropertyManager.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── metadata/
│                               ├── PropertyManagerTest.kt
│                               └── SettingsInstallIDProviderTest.kt
├── mobile-device-management/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── mobiledevicemanagement/
│       │   │                   ├── MDMConfigHandler.kt
│       │   │                   └── MDMConfigObserver.kt
│       │   └── res/
│       │       └── xml/
│       │           └── managed_configuration.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── mobiledevicemanagement/
│                               ├── MDMConfigHandlerTest.kt
│                               └── MDMConfigObserverTest.kt
├── nbistubs/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── AndroidManifest.xml
├── open-rosa/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── openrosa/
│       │                       ├── forms/
│       │                       │   ├── DocumentFetchResult.java
│       │                       │   ├── EntityIntegrity.kt
│       │                       │   ├── OpenRosaClient.kt
│       │                       │   └── OpenRosaXmlFetcher.java
│       │                       ├── http/
│       │                       │   ├── CaseInsensitiveEmptyHeaders.java
│       │                       │   ├── CaseInsensitiveHeaders.java
│       │                       │   ├── CollectThenSystemContentTypeMapper.java
│       │                       │   ├── HttpCredentials.java
│       │                       │   ├── HttpCredentialsInterface.java
│       │                       │   ├── HttpGetResult.java
│       │                       │   ├── HttpHeadResult.java
│       │                       │   ├── HttpPostResult.java
│       │                       │   ├── OpenRosaConstants.kt
│       │                       │   ├── OpenRosaHttpInterface.java
│       │                       │   └── okhttp/
│       │                       │       ├── OkHttpCaseInsensitiveHeaders.java
│       │                       │       ├── OkHttpConnection.java
│       │                       │       ├── OkHttpOpenRosaServerClientProvider.java
│       │                       │       ├── OpenRosaServerClient.java
│       │                       │       └── OpenRosaServerClientProvider.java
│       │                       └── parse/
│       │                           ├── Kxml2OpenRosaResponseParser.kt
│       │                           └── OpenRosaResponseParser.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── openrosa/
│                               ├── forms/
│                               │   ├── OpenRosaClientTest.kt
│                               │   └── OpenRosaXmlFetcherTest.java
│                               ├── http/
│                               │   ├── CaseInsensitiveEmptyHeadersTest.java
│                               │   ├── CollectThenSystemContentTypeMapperTest.java
│                               │   ├── OpenRosaGetRequestTest.java
│                               │   ├── OpenRosaHeadRequestTest.java
│                               │   ├── OpenRosaPostRequestTest.java
│                               │   └── okhttp/
│                               │       ├── OkHttpCaseInsensitiveHeadersTest.java
│                               │       ├── OkHttpConnectionGetRequestTest.java
│                               │       ├── OkHttpConnectionHeadRequestTest.java
│                               │       ├── OkHttpConnectionPostRequestTest.java
│                               │       ├── OkHttpOpenRosaServerClientProviderTest.java
│                               │       └── OpenRosaServerClientProviderTest.java
│                               ├── parse/
│                               │   └── Kxml2OpenRosaResponseParserTest.kt
│                               └── support/
│                                   ├── MockWebServerHelper.java
│                                   ├── MockWebServerRule.kt
│                                   └── StubWebCredentialsProvider.java
├── osmdroid/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── osmdroid/
│           │                   ├── DaggerSetup.kt
│           │                   ├── OsmDroidInitializer.kt
│           │                   ├── OsmDroidMapConfigurator.java
│           │                   ├── OsmDroidMapFragment.java
│           │                   ├── OsmMBTileModuleProvider.java
│           │                   ├── OsmMBTileProvider.java
│           │                   ├── OsmMBTileSource.java
│           │                   └── WebMapService.java
│           └── res/
│               └── layout/
│                   └── osm_map_layout.xml
├── permissions/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── permissions/
│       │   │                   ├── LocationAccessibilityChecker.kt
│       │   │                   ├── PermissionListener.kt
│       │   │                   ├── PermissionsChecker.kt
│       │   │                   ├── PermissionsDialogCreator.kt
│       │   │                   ├── PermissionsProvider.kt
│       │   │                   └── RequestPermissionsAPI.kt
│       │   └── res/
│       │       └── drawable/
│       │           ├── ic_photo_camera.xml
│       │           ├── ic_room_24dp.xml
│       │           └── ic_storage.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── permissions/
│           │                   ├── PermissionsDialogCreatorTest.kt
│           │                   └── PermissionsProviderTest.kt
│           └── resources/
│               └── robolectric.properties
├── printer/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── printer/
│                               └── HtmlPrinter.kt
├── projects/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── projects/
│       │                       ├── DaggerSetup.kt
│       │                       ├── InMemProjectsRepository.kt
│       │                       ├── Project.kt
│       │                       ├── ProjectConfigurationResult.kt
│       │                       ├── ProjectCreator.kt
│       │                       ├── ProjectDependencyFactory.kt
│       │                       ├── ProjectsRepository.kt
│       │                       ├── SettingsConnectionMatcher.kt
│       │                       └── SharedPreferencesProjectsRepository.kt
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── projects/
│           │                   ├── InMemProjectsRepositoryTest.kt
│           │                   ├── ProjectsRepositoryTest.kt
│           │                   ├── SharedPreferencesProjectsRepositoryTest.kt
│           │                   └── support/
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── qr-code/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── qrcode/
│       │   │                   ├── BarcodeFilter.kt
│       │   │                   ├── BarcodeScannerViewContainer.kt
│       │   │                   ├── DetectedState.kt
│       │   │                   ├── FlashlightToggle.kt
│       │   │                   ├── ScannerControls.kt
│       │   │                   ├── ScannerOverlay.kt
│       │   │                   ├── mlkit/
│       │   │                   │   ├── MlKitBarcodeScannerViewFactory.kt
│       │   │                   │   └── PlayServicesFallbackBarcodeScannerViewFactory.kt
│       │   │                   └── zxing/
│       │   │                       ├── QRCodeCreator.kt
│       │   │                       ├── QRCodeDecoder.kt
│       │   │                       └── ZxingBarcodeScannerViewFactory.kt
│       │   └── res/
│       │       └── layout/
│       │           ├── mlkit_barcode_scanner_layout.xml
│       │           └── zxing_barcode_scanner_layout.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── qrcode/
│           │                   ├── BarcodeFilterTest.kt
│           │                   └── QRCodeEncodeDecodeTest.kt
│           └── resources/
│               └── robolectric.properties
├── secrets.gradle
├── selfie-camera/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── selfiecamera/
│       │   │                   ├── Camera.kt
│       │   │                   ├── CameraXCamera.kt
│       │   │                   ├── CaptureSelfieActivity.kt
│       │   │                   └── DaggerSetup.kt
│       │   └── res/
│       │       └── layout/
│       │           └── activity_capture_selfie.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── selfiecamera/
│           │                   ├── CaptureSelfieActivityTest.kt
│           │                   └── support/
│           │                       └── RobolectricApplication.kt
│           └── resources/
│               └── robolectric.properties
├── service-test/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── servicetest/
│                               ├── NotificationDetails.kt
│                               └── ServiceScenario.kt
├── settings/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── consumer-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── settings/
│       │   │                   ├── InMemSettingsProvider.kt
│       │   │                   ├── ODKAppSettingsImporter.kt
│       │   │                   ├── ODKAppSettingsMigrator.java
│       │   │                   ├── SettingsProvider.kt
│       │   │                   ├── enums/
│       │   │                   │   ├── AutoSend.kt
│       │   │                   │   ├── FormUpdateMode.java
│       │   │                   │   ├── GuidanceHintMode.kt
│       │   │                   │   ├── StringIdEnum.kt
│       │   │                   │   └── StringIdEnumUtils.kt
│       │   │                   ├── importing/
│       │   │                   │   ├── ProjectDetailsCreatorImpl.kt
│       │   │                   │   └── SettingsImporter.kt
│       │   │                   ├── keys/
│       │   │                   │   ├── AppConfigurationKeys.kt
│       │   │                   │   ├── MetaKeys.kt
│       │   │                   │   ├── ProjectKeys.kt
│       │   │                   │   └── ProtectedProjectKeys.kt
│       │   │                   ├── migration/
│       │   │                   │   ├── KeyCombiner.java
│       │   │                   │   ├── KeyExtractor.java
│       │   │                   │   ├── KeyMover.java
│       │   │                   │   ├── KeyRenamer.java
│       │   │                   │   ├── KeyTranslator.java
│       │   │                   │   ├── KeyUpdater.java
│       │   │                   │   ├── KeyValuePair.java
│       │   │                   │   ├── Migration.java
│       │   │                   │   ├── MigrationUtils.java
│       │   │                   │   └── ValueTranslator.java
│       │   │                   └── validation/
│       │   │                       └── JsonSchemaSettingsValidator.kt
│       │   ├── res/
│       │   │   └── values/
│       │   │       └── strings.xml
│       │   └── resources/
│       │       └── client-settings.schema.json
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── settings/
│                               ├── ODKAppSettingsImporterTest.kt
│                               ├── ODKAppSettingsMigratorTest.java
│                               ├── importing/
│                               │   ├── ProjectDetailsCreatorImplTest.kt
│                               │   └── SettingsImporterTest.kt
│                               ├── migration/
│                               │   ├── KeyCombinerTest.java
│                               │   ├── KeyExtractorTest.java
│                               │   ├── KeyMoverTest.java
│                               │   ├── KeyRemoverTest.java
│                               │   ├── KeyRenamerTest.java
│                               │   ├── KeyTranslatorTest.java
│                               │   └── ValueTranslatorTest.java
│                               ├── support/
│                               │   └── SettingsUtils.kt
│                               └── validation/
│                                   ├── JsonSchemaSettingsValidatorTest.kt
│                                   └── OriginalJsonSchemaSettingsValidatorTest.kt
├── settings.gradle
├── shadows/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── shadows/
│       │                       └── ShadowAndroidXAlertDialog.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── shadows/
│                               └── ShadowAndroidXAlertDialogTest.kt
├── shared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── shared/
│       │                       ├── DebugLogger.kt
│       │                       ├── PathUtils.kt
│       │                       ├── Query.kt
│       │                       ├── TempFiles.kt
│       │                       ├── TimeInMs.kt
│       │                       ├── collections/
│       │                       │   └── CollectionExtensions.kt
│       │                       ├── files/
│       │                       │   └── FileExt.kt
│       │                       ├── geometry/
│       │                       │   └── Geometry.kt
│       │                       ├── injection/
│       │                       │   └── ObjectProvider.kt
│       │                       ├── locks/
│       │                       │   ├── BooleanChangeLock.kt
│       │                       │   ├── ChangeLock.kt
│       │                       │   └── ThreadSafeBooleanChangeLock.kt
│       │                       ├── result/
│       │                       │   └── Result.kt
│       │                       ├── settings/
│       │                       │   ├── InMemSettings.kt
│       │                       │   └── Settings.kt
│       │                       └── strings/
│       │                           ├── Md5.kt
│       │                           ├── RandomString.java
│       │                           ├── StringUtils.kt
│       │                           └── UUIDGenerator.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── shared/
│                               ├── Md5Test.kt
│                               ├── PathUtilsTest.kt
│                               ├── QuickCheck.kt
│                               ├── collections/
│                               │   └── CollectionExtensionsTest.kt
│                               ├── files/
│                               │   └── FileExtTest.kt
│                               ├── geometry/
│                               │   ├── GeometryTest.kt
│                               │   └── support/
│                               │       ├── GeometryTestUtils.kt
│                               │       └── GeometryTestUtilsTest.kt
│                               ├── locks/
│                               │   ├── BooleanChangeLockTest.kt
│                               │   ├── ChangeLockTest.kt
│                               │   └── ThreadSafeBooleanChangeLockTest.kt
│                               └── strings/
│                                   └── StringUtilsTest.kt
├── strings/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── odk/
│       │   │           └── collect/
│       │   │               └── strings/
│       │   │                   ├── format/
│       │   │                   │   └── LengthFormatter.kt
│       │   │                   └── localization/
│       │   │                       ├── LocalizedActivity.kt
│       │   │                       └── LocalizedApplication.kt
│       │   └── res/
│       │       ├── values/
│       │       │   ├── strings.xml
│       │       │   └── untranslated.xml
│       │       ├── values-af/
│       │       │   └── strings.xml
│       │       ├── values-am/
│       │       │   └── strings.xml
│       │       ├── values-ar/
│       │       │   └── strings.xml
│       │       ├── values-bg/
│       │       │   └── strings.xml
│       │       ├── values-bn/
│       │       │   └── strings.xml
│       │       ├── values-ca/
│       │       │   └── strings.xml
│       │       ├── values-cs/
│       │       │   └── strings.xml
│       │       ├── values-da/
│       │       │   └── strings.xml
│       │       ├── values-de/
│       │       │   └── strings.xml
│       │       ├── values-es/
│       │       │   └── strings.xml
│       │       ├── values-es-rSV/
│       │       │   └── strings.xml
│       │       ├── values-et/
│       │       │   └── strings.xml
│       │       ├── values-fa/
│       │       │   └── strings.xml
│       │       ├── values-fa-rAF/
│       │       │   └── strings.xml
│       │       ├── values-fi/
│       │       │   └── strings.xml
│       │       ├── values-fr/
│       │       │   └── strings.xml
│       │       ├── values-hi/
│       │       │   └── strings.xml
│       │       ├── values-ht/
│       │       │   └── strings.xml
│       │       ├── values-in/
│       │       │   └── strings.xml
│       │       ├── values-it/
│       │       │   └── strings.xml
│       │       ├── values-ja/
│       │       │   └── strings.xml
│       │       ├── values-ka/
│       │       │   └── strings.xml
│       │       ├── values-km/
│       │       │   └── strings.xml
│       │       ├── values-ln/
│       │       │   └── strings.xml
│       │       ├── values-lo-rLA/
│       │       │   └── strings.xml
│       │       ├── values-lt/
│       │       │   └── strings.xml
│       │       ├── values-mg/
│       │       │   └── strings.xml
│       │       ├── values-ml/
│       │       │   └── strings.xml
│       │       ├── values-mr/
│       │       │   └── strings.xml
│       │       ├── values-ms/
│       │       │   └── strings.xml
│       │       ├── values-my/
│       │       │   └── strings.xml
│       │       ├── values-ne-rNP/
│       │       │   └── strings.xml
│       │       ├── values-nl/
│       │       │   └── strings.xml
│       │       ├── values-no/
│       │       │   └── strings.xml
│       │       ├── values-pl/
│       │       │   └── strings.xml
│       │       ├── values-ps/
│       │       │   └── strings.xml
│       │       ├── values-pt/
│       │       │   └── strings.xml
│       │       ├── values-ro/
│       │       │   └── strings.xml
│       │       ├── values-ru/
│       │       │   └── strings.xml
│       │       ├── values-rw/
│       │       │   └── strings.xml
│       │       ├── values-si/
│       │       │   └── strings.xml
│       │       ├── values-sl/
│       │       │   └── strings.xml
│       │       ├── values-so/
│       │       │   └── strings.xml
│       │       ├── values-sq/
│       │       │   └── strings.xml
│       │       ├── values-sr/
│       │       │   └── strings.xml
│       │       ├── values-sv-rSE/
│       │       │   └── strings.xml
│       │       ├── values-sw/
│       │       │   └── strings.xml
│       │       ├── values-sw-rKE/
│       │       │   └── strings.xml
│       │       ├── values-te/
│       │       │   └── strings.xml
│       │       ├── values-th-rTH/
│       │       │   └── strings.xml
│       │       ├── values-ti/
│       │       │   └── strings.xml
│       │       ├── values-tl/
│       │       │   └── strings.xml
│       │       ├── values-tl-rPH/
│       │       │   └── strings.xml
│       │       ├── values-tr/
│       │       │   └── strings.xml
│       │       ├── values-uk/
│       │       │   └── strings.xml
│       │       ├── values-ur/
│       │       │   └── strings.xml
│       │       ├── values-ur-rPK/
│       │       │   └── strings.xml
│       │       ├── values-vi/
│       │       │   └── strings.xml
│       │       ├── values-zh/
│       │       │   └── strings.xml
│       │       ├── values-zh-rTW/
│       │       │   └── strings.xml
│       │       └── values-zu/
│       │           └── strings.xml
│       └── test/
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── strings/
│           │                   └── format/
│           │                       ├── DateFormatsTest.kt
│           │                       └── LengthFormatterTest.kt
│           └── resources/
│               └── robolectric.properties
├── test-forms/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── resources/
│               ├── forms/
│               │   ├── Empty First Repeat.xml
│               │   ├── RepeatGroupAndGroup.xml
│               │   ├── RepeatTitles_1648.xml
│               │   ├── TestRepeat.xml
│               │   ├── all-widgets.xml
│               │   ├── audio-question.xml
│               │   ├── basic.xml
│               │   ├── different-search-appearances.xml
│               │   ├── dynamic_and_static_choices.xml
│               │   ├── dynamic_required_question.xml
│               │   ├── emptyGroupFieldList.xml
│               │   ├── encrypted-no-instanceID.xml
│               │   ├── encrypted.xml
│               │   ├── entity-update-pulldata.xml
│               │   ├── external-audio-question.xml
│               │   ├── external-csv-search-broken.xml
│               │   ├── external-csv-search.xml
│               │   ├── external_csv_form.xml
│               │   ├── external_data_questions.xml
│               │   ├── external_select.xml
│               │   ├── external_select_10.xml
│               │   ├── external_select_csv.xml
│               │   ├── field-list-repeat.xml
│               │   ├── fieldlist-updates.xml
│               │   ├── fixed-count-repeat.xml
│               │   ├── form1.xml
│               │   ├── form2.xml
│               │   ├── form3.xml
│               │   ├── form4.xml
│               │   ├── form5.xml
│               │   ├── form6.xml
│               │   ├── form7.xml
│               │   ├── form8.xml
│               │   ├── form9.xml
│               │   ├── formHierarchy1.xml
│               │   ├── formHierarchy2.xml
│               │   ├── formHierarchy3.xml
│               │   ├── form_design_error.xml
│               │   ├── form_styling.xml
│               │   ├── form_with_images.xml
│               │   ├── g6Error.xml
│               │   ├── hints_textq.xml
│               │   ├── identify-user-audit-false.xml
│               │   ├── identify-user-audit.xml
│               │   ├── intent-group.xml
│               │   ├── internal-audio-question.xml
│               │   ├── invalid-form.xml
│               │   ├── likert_test.xml
│               │   ├── location-audit.xml
│               │   ├── manyQ.xml
│               │   ├── metadata.xml
│               │   ├── nested-intent-group.xml
│               │   ├── numberInCSV.xml
│               │   ├── one-question-audit.xml
│               │   ├── one-question-autoplay.xml
│               │   ├── one-question-autosend-disabled.xml
│               │   ├── one-question-autosend.xml
│               │   ├── one-question-background-audio-audit.xml
│               │   ├── one-question-background-audio-multiple.xml
│               │   ├── one-question-background-audio.xml
│               │   ├── one-question-editable.xml
│               │   ├── one-question-encrypted-unicode.xml
│               │   ├── one-question-entity-create-and-update.xml
│               │   ├── one-question-entity-follow-up.xml
│               │   ├── one-question-entity-registration-broken.xml
│               │   ├── one-question-entity-registration-editable.xml
│               │   ├── one-question-entity-registration-id.xml
│               │   ├── one-question-entity-registration-v2020.1.xml
│               │   ├── one-question-entity-registration-v2023.1.xml
│               │   ├── one-question-entity-registration.xml
│               │   ├── one-question-entity-update-and-create.xml
│               │   ├── one-question-entity-update-editable.xml
│               │   ├── one-question-entity-update.xml
│               │   ├── one-question-last-saved-updated.xml
│               │   ├── one-question-last-saved.xml
│               │   ├── one-question-partial.xml
│               │   ├── one-question-repeat.xml
│               │   ├── one-question-translation.xml
│               │   ├── one-question-updated.xml
│               │   ├── one-question-uuid-instance-name.xml
│               │   ├── one-question-with-constraint.xml
│               │   ├── one-question.xml
│               │   ├── pull_data.xml
│               │   ├── random.xml
│               │   ├── randomTest_broken.xml
│               │   ├── ranking_widget.xml
│               │   ├── repeat_group_form.xml
│               │   ├── repeat_group_new.xml
│               │   ├── repeat_group_wrapped_with_a_regular_group.xml
│               │   ├── repeat_groups.xml
│               │   ├── repeat_in_field_list.xml
│               │   ├── repeat_without_label.xml
│               │   ├── requiredQuestionInFieldList.xml
│               │   ├── required_question_with_audio.xml
│               │   ├── required_question_with_custom_error_message.xml
│               │   ├── search_and_select.xml
│               │   ├── selectOneExternal.xml
│               │   ├── select_one_external.xml
│               │   ├── setgeopoint-action.xml
│               │   ├── simple-search-external-csv.xml
│               │   ├── single-geopoint.xml
│               │   ├── start-geopoint.xml
│               │   ├── string_widgets_in_field_list.xml
│               │   ├── track-changes-reason-on-edit.xml
│               │   ├── two-question-audit-track-changes.xml
│               │   ├── two-question-audit.xml
│               │   ├── two-question-external.xml
│               │   ├── two-question-required.xml
│               │   ├── two-question-save-incomplete-required.xml
│               │   ├── two-question-save-incomplete.xml
│               │   ├── two-question-updated.xml
│               │   ├── two-question.xml
│               │   ├── two-questions-in-group.xml
│               │   └── validate.xml
│               └── media/
│                   ├── external-csv-search-produce.csv
│                   ├── external_csv_cities.csv
│                   ├── external_csv_countries.csv
│                   ├── external_csv_neighbourhoods.csv
│                   ├── external_data.csv
│                   ├── external_data.xml
│                   ├── external_data_10.xml
│                   ├── external_data_broken.csv
│                   ├── fruits.csv
│                   ├── itemSets.csv
│                   ├── people.csv
│                   ├── selectOneExternal-media/
│                   │   └── itemsets.csv
│                   ├── simple-search-external-csv-fruits.csv
│                   ├── test.m4a
│                   └── updated-people.csv
├── test-shared/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── testshared/
│                               ├── ActivityControllerRule.kt
│                               ├── ActivityExt.kt
│                               ├── AssertIntentsHelper.kt
│                               ├── AssertionFramework.kt
│                               ├── ComposeAssertions.kt
│                               ├── ComposeInteractions.kt
│                               ├── DummyActivity.kt
│                               ├── ErrorIntentLauncher.kt
│                               ├── EspressoAssertions.kt
│                               ├── EspressoInteractions.kt
│                               ├── FakeAudioPlayer.kt
│                               ├── FakeBarcodeScannerView.kt
│                               ├── FakeBroadcastReceiverRegister.kt
│                               ├── FakeScheduler.kt
│                               ├── FragmentResultRecorder.kt
│                               ├── LocationTestUtils.kt
│                               ├── MockFragmentFactory.kt
│                               ├── MockWebPageService.kt
│                               ├── RecyclerViewMatcher.kt
│                               ├── RobolectricHelpers.kt
│                               ├── SliderExt.kt
│                               ├── TimeZoneSetter.kt
│                               ├── ViewActions.kt
│                               ├── ViewMatchers.kt
│                               └── WaitFor.kt
├── timedgrid/
│   ├── .gitignore
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── odk/
│           │           └── collect/
│           │               └── timedgrid/
│           │                   ├── AssessmentType.kt
│           │                   ├── CommonTimedGridRenderer.kt
│           │                   ├── FinishType.kt
│           │                   ├── NavigationAwareWidget.kt
│           │                   ├── PausableCountDownTimer.kt
│           │                   ├── TimedGridRenderer.kt
│           │                   ├── TimedGridState.kt
│           │                   ├── TimedGridSummary.kt
│           │                   ├── TimedGridSummaryAnswerCreator.kt
│           │                   ├── TimedGridViewModel.kt
│           │                   ├── TimedGridWidgetConfiguration.kt
│           │                   ├── TimedGridWidgetDelegate.kt
│           │                   └── TimedGridWidgetLayout.kt
│           └── res/
│               ├── color/
│               │   └── timed_grid_button_tint_selector.xml
│               ├── drawable/
│               │   └── row_number_background.xml
│               ├── layout/
│               │   ├── timed_grid.xml
│               │   ├── timed_grid_item_button.xml
│               │   └── timed_grid_item_row.xml
│               └── values/
│                   ├── colors.xml
│                   ├── dimens.xml
│                   ├── strings.xml
│                   └── styles.xml
├── upgrade/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── org/
│       │           └── odk/
│       │               └── collect/
│       │                   └── upgrade/
│       │                       ├── AppUpgrader.kt
│       │                       ├── LaunchState.kt
│       │                       └── Upgrade.kt
│       └── test/
│           └── java/
│               └── org/
│                   └── odk/
│                       └── collect/
│                           └── upgrade/
│                               ├── AppUpgraderTest.kt
│                               └── VersionCodeLaunchStateTest.kt
└── web-page/
    ├── .gitignore
    ├── build.gradle.kts
    └── src/
        ├── main/
        │   ├── AndroidManifest.xml
        │   └── java/
        │       └── org/
        │           └── odk/
        │               └── collect/
        │                   └── webpage/
        │                       ├── CustomTabsWebPageService.kt
        │                       └── WebPageService.kt
        └── test/
            └── java/
                └── org/
                    └── odk/
                        └── collect/
                            └── webpage/
                                └── CustomTabsWebPageServiceTest.java
Download .txt
Showing preview only (520K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5828 symbols across 571 files)

FILE: androidshared/src/main/java/org/odk/collect/androidshared/livedata/LiveDataUtils.java
  class LiveDataUtils (line 16) | public class LiveDataUtils {
    method LiveDataUtils (line 18) | private LiveDataUtils() {
    method observe (line 22) | public static <T> Cancellable observe(LiveData<T> liveData, Consumer<T...
    method liveDataOf (line 36) | public static <T> LiveData<T> liveDataOf(T value) {
    method combine (line 40) | public static <T, U> LiveData<Pair<T, U>> combine(LiveData<T> one, Liv...
    method combine3 (line 47) | public static <T, U, V> LiveData<Triple<T, U, V>> combine3(LiveData<T>...
    method combine4 (line 54) | public static <T, U, V, W> LiveData<Quad<T, U, V, W>> combine4(LiveDat...
    class CombinedLiveData (line 61) | private static class CombinedLiveData<T> extends MediatorLiveData<T> {
      method CombinedLiveData (line 67) | CombinedLiveData(LiveData<?>[] sources, Function<Object[], T> map) {
      method update (line 82) | private void update() {
    class Quad (line 92) | public static class Quad<T, U, V, W> {
      method Quad (line 99) | public Quad(T first, U second, V third, W fourth) {

FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/CameraUtils.java
  class CameraUtils (line 27) | public class CameraUtils {
    method getFrontCameraId (line 28) | public static int getFrontCameraId() {
    method isFrontCameraAvailable (line 41) | public boolean isFrontCameraAvailable(Context context) {

FILE: androidshared/src/main/java/org/odk/collect/androidshared/system/PlayServicesChecker.java
  class PlayServicesChecker (line 11) | public class PlayServicesChecker {
    method isGooglePlayServicesAvailable (line 16) | public boolean isGooglePlayServicesAvailable(Context context) {
    method showGooglePlayServicesAvailabilityErrorDialog (line 23) | public void showGooglePlayServicesAvailabilityErrorDialog(Context cont...

FILE: androidshared/src/main/java/org/odk/collect/androidshared/utils/ScreenUtils.java
  class ScreenUtils (line 23) | public class ScreenUtils {
    method ScreenUtils (line 27) | public ScreenUtils(Context context) {
    method getScreenWidth (line 31) | public static int getScreenWidth(Context context) {
    method getScreenHeight (line 35) | public static int getScreenHeight(Context context) {
    method xdpi (line 39) | public static float xdpi(Context context) {
    method ydpi (line 43) | public static float ydpi(Context context) {
    method getDisplayMetrics (line 47) | private static DisplayMetrics getDisplayMetrics(Context context) {
    method getScreenSizeConfiguration (line 51) | public int getScreenSizeConfiguration() {

FILE: androidshared/src/test/java/org/odk/collect/androidshared/utils/DialogFragmentUtilsTest.java
  class DialogFragmentUtilsTest (line 20) | @RunWith(AndroidJUnit4.class)
    method showIfNotShowing_onlyEverOpensOneDialog (line 23) | @Test
    method showIfNotShowing_whenActivitySavedState_doesNotShowDialog (line 37) | @Test
    method showIfNotShowing_whenActivityDestroyed_doesNotShowDialog (line 47) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/AudioRecordingTest.java
  class AudioRecordingTest (line 25) | @RunWith(AndroidJUnit4.class)
    method providesAudioRecorder (line 31) | @Override
    method onAudioQuestion_withoutAudioQuality_canRecordAndPlayBackInApp (line 55) | @Test
    method onAudioQuestion_withQualitySpecified_canRecordAudioInApp (line 67) | @Test
    method whileRecording_pressingBack_showsWarning_andStaysOnSameScreen (line 80) | @Test
    method whileRecording_swipingToADifferentScreen_showsWarning_andStaysOnSameScreen (line 91) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/BackgroundAudioRecordingTest.java
  class BackgroundAudioRecordingTest (line 43) | @RunWith(AndroidJUnit4.class)
    method providesAudioRecorder (line 52) | @Override
    method providesPermissionsChecker (line 69) | @Override
    method providesPermissionsProvider (line 74) | @Override
    method fillingOutForm_recordsAudio (line 86) | @Test
    method fillingOutForm_withMultipleRecordActions_recordsAudioOnceForAllOfThem (line 108) | @Test
    method pressingBackWhileRecording_andClickingSave_exitsForm (line 131) | @Test
    method uncheckingRecordAudio_andConfirming_endsAndDeletesRecording (line 141) | @Test
    method whenRecordAudioPermissionNotGranted_openingForm_andDenyingPermissions_closesForm (line 161) | @Test
    method viewForm_doesNotRecordAudio (line 176) | @Test
    class RevokeableRecordAudioPermissionsChecker (line 188) | private static class RevokeableRecordAudioPermissionsChecker extends C...
      method RevokeableRecordAudioPermissionsChecker (line 192) | RevokeableRecordAudioPermissionsChecker(Context context) {
      method isPermissionGranted (line 196) | @Override
      method revoke (line 205) | public void revoke() {
    class ControllableRecordAudioPermissionsProvider (line 210) | private static class ControllableRecordAudioPermissionsProvider extend...
      method ControllableRecordAudioPermissionsProvider (line 215) | ControllableRecordAudioPermissionsProvider(PermissionsChecker permis...
      method requestRecordAudioPermission (line 219) | @Override
      method makeControllable (line 228) | public void makeControllable() {
      method additionalExplanationClosed (line 232) | public void additionalExplanationClosed() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/ContextMenuTest.java
  class ContextMenuTest (line 10) | public class ContextMenuTest {
    method whenRemoveStringAnswer_ShouldAppropriateQuestionBeCleared (line 19) | @Test
    method whenLongPressedOnEditText_ShouldNotRemoveAnswerOptionAppear (line 38) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/DeletingRepeatGroupsTest.java
  class DeletingRepeatGroupsTest (line 19) | @Ignore
    method requestingDeletionOfFirstRepeat_deletesFirstRepeat (line 29) | @Test
    method requestingDeletionOfMiddleRepeat_deletesMiddleRepeat (line 37) | @Test
    method requestingDeletionOfLastRepeat_deletesLastRepeat (line 46) | @Test
    method requestingDeletionOfFirstRepeatInHierarchy_deletesFirstRepeat (line 57) | @Test
    method requestingDeletionOfMiddleRepeatInHierarchy_deletesMiddleRepeat (line 76) | @Test
    method requestingDeletionOfLastRepeatInHierarchy_deletesLastRepeat (line 95) | @Test
    method requestingDeletionOfAllRepeatsInHierarchyStartingFromIndexThatWillBeDeleted_shouldBringAUserToTheFirstRelevantQuestionBeforeTheGroup (line 114) | @Test
    method requestingDeletionOfAllRepeatsInHierarchyStartingFromIndexThatWillNotBeDeleted_shouldBringAUserBackToTheSameIndex (line 132) | @Test
    method requestingDeletionOfAllRepeatsInHierarchyStartingFromTheEndView_shouldBringAUserToTheEndView (line 149) | @Test
    method requestingDeletionOfFirstRepeatWithFieldList_deletesFirstRepeat (line 167) | @Test
    method requestingDeletionOfMiddleRepeatWithFieldList_deletesMiddleRepeat (line 181) | @Test
    method requestingDeletionOfLastRepeatWithFieldList_deletesLastRepeat (line 195) | @Test
    method requestingDeletionOfFirstRepeatWithFieldListInHierarchy_deletesFirstRepeat (line 209) | @Test
    method requestingDeletionOfMiddleRepeatWithFieldListInHierarchy_deletesMiddleRepeat (line 229) | @Test
    method requestingDeletionOfLastRepeatWithFieldListInHierarchy_deletesLastRepeat (line 248) | @Test
    method requestingDeletionOfAllRepeatsWithFieldListInHierarchyStartingFromIndexThatWillBeDeleted_shouldBringAUserToTheFirstRelevantQuestionBeforeTheGroup (line 267) | @Test
    method requestingDeletionOfAllRepeatsWithFieldListInHierarchyStartingFromIndexThatWillNotBeDeleted_shouldBringAUserBackToTheSameIndex (line 291) | @Test
    method requestingDeletionOfAllRepeatsWithFieldListInHierarchyStartingFromTheEndView_shouldBringAUserToTheEndView (line 308) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/ExternalAudioRecordingTest.java
  class ExternalAudioRecordingTest (line 28) | @RunWith(AndroidJUnit4.class)
    method onAudioQuestion_whenAudioQualityIsExternal_usesExternalRecorder (line 54) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/ExternalSecondaryInstanceTest.java
  class ExternalSecondaryInstanceTest (line 23) | @RunWith(AndroidJUnit4.class)
    method displaysAllOptionsFromXMLSecondaryInstance (line 32) | @Test
    method displaysAllOptionsFromCSVSecondaryInstance (line 43) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/FormHierarchyTest.java
  class FormHierarchyTest (line 22) | public class FormHierarchyTest {
    method allRelevantQuestionsShouldBeVisibleInHierarchyView (line 30) | @Test
    method notRelevantRepeatGroupsShouldNotBeVisibleInHierarchy (line 47) | @Test
    method repeatGroupsShouldBeVisibleAsAppropriate (line 91) | @Test
    method deletingLastGroupShouldNotBreakHierarchy (line 121) | @Test
    method deletingLastGroupAndAddingOneShouldNotBreakHierarchy (line 156) | @Test
    method showRepeatsPickerWhenFirstRepeatIsEmpty (line 176) | @Test
    method regularGroupThatWrapsARepeatableGroupShouldBeTreatedAsARegularOne (line 190) | @Test
    method when_openHierarchyViewFromLastPage_should_mainGroupViewBeVisible (line 203) | @Test
    method hierachyView_shouldNotChangeAfterScreenRotation (line 215) | @Test
    method theListOfQuestionsShouldBeScrolledToTheLastDisplayedQuestionAfterOpeningTheHierarchy (line 228) | @Test
    method whenViewFormInHierarchyForRepeatGroup_noDeleteButtonAppears (line 241) | @Test
    method whenViewFormInHierarchy_clickingOnQuestion_doesNothing (line 257) | @Test
    method clickingBackButtonAfterNavigatingInTheHierarchyOfGroups_movesToTheQuestionDisplayedBeforeOpeningTheHierarchy (line 270) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/FormLanguageTest.java
  class FormLanguageTest (line 14) | @RunWith(AndroidJUnit4.class)
    method canSwitchLanguagesInForm (line 22) | @Test
    method languageChoiceIsPersisted (line 35) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/LikertTest.java
  class LikertTest (line 26) | public class LikertTest {
    method allText_canClick (line 35) | @Test
    method allImages_canClick (line 43) | @Test
    method insufficientText_canClick (line 51) | @Test
    method insufficientImages_canClick (line 59) | @Test
    method missingImage_canClick (line 67) | @Test
    method missingText_canClick (line 75) | @Test
    method onlyOneRemainsClicked (line 83) | @Test
    method testImagesLoad (line 94) | @Test
    method updateTest_SelectionChangeAtOneCascadeLevelWithLikert_ShouldUpdateNextLevels (line 104) | @Test
    method openWidgetList (line 141) | private void openWidgetList() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/QuickSaveTest.java
  class QuickSaveTest (line 13) | @RunWith(AndroidJUnit4.class)
    method whenFillingForm_clickingSaveIcon_savesCurrentAnswers (line 22) | @Test
    method whenFillingForm_withViolatedConstraintsOnCurrentScreen_clickingSaveIcon_savesCurrentAnswers (line 40) | @Test
    method whenEditingANonFinalizedForm_withViolatedConstraintsOnCurrentScreen_clickingSaveIcon_savesCurrentAnswers (line 55) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/QuittingFormTest.java
  class QuittingFormTest (line 15) | @RunWith(AndroidJUnit4.class)
    method whenFillingForm_pressingBack_andClickingSaveChanges_savesCurrentAnswers (line 24) | @Test
    method whenFillingForm_pressingBack_andClickingIgnoreChanges_doesNotSaveForm (line 43) | @Test
    method whenFillingForm_saving_andPressingBack_andClickingIgnoreChanges_savesAnswersBeforeSave (line 55) | @Test
    method whenFillingForm_withViolatedConstraintsOnCurrentScreen_pressingBack_andClickingSaveChanges_savesCurrentAnswers (line 72) | @Test
    method whenEditingANonFinalizedForm_withViolatedConstraintsOnCurrentScreen_pressingBack_andClickingSaveChanges_savesCurrentAnswers (line 88) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/RankingWidgetWithCSVTest.java
  class RankingWidgetWithCSVTest (line 12) | public class RankingWidgetWithCSVTest {
    method rankingWidget_shouldDisplayItemsFromSearchFunc (line 23) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/backgroundlocation/LocationTrackingAuditTest.java
  class LocationTrackingAuditTest (line 24) | public class LocationTrackingAuditTest {
    method providesFusedLocationClient (line 32) | @Override
    method locationTrackingIsLogged_andLocationIsLoggedForEachQuestion (line 39) | @Test
    method locationCollectionToggle_ShouldBeAvailable (line 72) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/backgroundlocation/SetGeopointActionTest.java
  class SetGeopointActionTest (line 10) | public class SetGeopointActionTest {
    method locationCollectionSnackbar_ShouldBeDisplayedAtFormLaunch (line 19) | @Test
    method locationCollectionToggle_ShouldBeAvailable (line 28) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formentry/dynamicpreload/DynamicPreLoadedDataSelects.java
  class DynamicPreLoadedDataSelects (line 18) | public class DynamicPreLoadedDataSelects {
    method withoutFilterAndWithFilter_displaysMatchingChoices (line 26) | @Test
    method displayErrorWhenFilesAreMissing (line 49) | @Test
    method displayWarningWhenQueryIsBad (line 58) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/DeleteBlankFormTest.java
  class DeleteBlankFormTest (line 14) | @RunWith(AndroidJUnit4.class)
    method deletingAForm_removesFormFromBlankFormList (line 24) | @Test
    method deletingAForm_whenThereFilledForms_removesFormFromBlankFormList_butAllowsEditingFilledForms (line 39) | @Test
    method afterFillingAForm_andDeletingIt_allowsFormToBeReDownloaded (line 66) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/FormsAdbTest.java
  class FormsAdbTest (line 20) | @RunWith(AndroidJUnit4.class)
    method canUpdateAFormFromDisk (line 30) | @Test
    method canUpdateFormOnDiskFromServer (line 46) | @Test
    method canDeleteFormFromDisk (line 64) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/GetBlankFormsTest.java
  class GetBlankFormsTest (line 14) | @RunWith(AndroidJUnit4.class)
    method whenThereIsAnAuthenticationErrorFetchingFormList_allowsUserToReenterCredentials (line 25) | @Test
    method whenThereIsAnErrorFetchingFormList_showsError (line 38) | @Test
    method whenThereIsAnErrorFetchingForms_showsError (line 48) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/HideOldVersionsTest.java
  class HideOldVersionsTest (line 14) | @RunWith(AndroidJUnit4.class)
    method whenHideOldVersionsEnabled_onlyTheNewestVersionOfAFormShowsInFormList (line 23) | @Test
    method whenHideOldVersionsDisabled_allVersionOfAFormShowsInFormList (line 36) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/formmanagement/ManualUpdatesTest.java
  class ManualUpdatesTest (line 17) | @RunWith(AndroidJUnit4.class)
    method whenManualUpdatesEnabled_getBlankFormsIsAvailable (line 26) | @Test
    method whenManualUpdatesEnabled_fillBlankFormRefreshButtonIsGone (line 33) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ConfigureWithQRCodeTest.java
  class ConfigureWithQRCodeTest (line 30) | @RunWith(AndroidJUnit4.class)
    method providesQRCodeGenerator (line 34) | @Override
    method teardown (line 46) | @After
    method clickConfigureQRCode_opensScanner_andThenScanning_importsSettings (line 52) | @Test
    method clickConfigureQRCode_andClickingOnView_showsQRCode (line 73) | @Test
    method whenThereIsAnAdminPassword_canRemoveFromQRCode (line 87) | @Test
    method whenThereIsAServerPassword_canRemoveFromQRCode (line 102) | @Test
    class StubQRCodeGenerator (line 125) | private static class StubQRCodeGenerator implements QRCodeGenerator {
      method generateQRCode (line 129) | @Override
      method setup (line 134) | public void setup() {
      method teardown (line 141) | public void teardown() {
      method getQRCodeFilePath (line 148) | String getQRCodeFilePath() {
      method getDrawableID (line 152) | int getDrawableID() {
      method saveBitmap (line 156) | private void saveBitmap(Bitmap bitmap) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/settings/ServerSettingsTest.java
  class ServerSettingsTest (line 16) | @RunWith(AndroidJUnit4.class)
    method whenUsingODKServer_canAddCredentialsForServer (line 28) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/smoke/BadServerTest.java
  class BadServerTest (line 17) | @RunWith(AndroidJUnit4.class)
    method whenHashNotIncludedInFormList_showError (line 27) | @Test
    method whenMediaFileHasMissingPrefix_showsAsUpdated (line 49) | @Test
    method whenMediaFileHasUnstableHash_butIsIdentical_doesNotShowAsUpdatedAfterRedownload (line 66) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/feature/smoke/GetAndSubmitFormTest.java
  class GetAndSubmitFormTest (line 15) | @RunWith(AndroidJUnit4.class)
    method canGetBlankForm_fillItIn_andSubmit (line 25) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/instrumented/forms/FormUtilsTest.java
  class FormUtilsTest (line 35) | public class FormUtilsTest {
    method create (line 39) | @Override
    method setUp (line 48) | @Before
    method sessionRootTranslatorOrderDoesNotMatter (line 57) | @Test
    method hostStringsOrderedCorrectly (line 90) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/instrumented/tasks/FormLoaderTaskTest.java
  class FormLoaderTaskTest (line 37) | public class FormLoaderTaskTest {
    method create (line 47) | @Override
    method loadSearchFromExternalCSVmultipleTimes (line 70) | @Test

FILE: collect_app/src/androidTest/java/org/odk/collect/android/instrumented/utilities/CustomSQLiteQueryExecutionTest.java
  class CustomSQLiteQueryExecutionTest (line 39) | @RunWith(AndroidJUnit4.class)
    method dropTableTest (line 60) | @Test
    method renameTableTest (line 71) | @Test
    method copyTableTest (line 88) | @Test
    method addColumnTest (line 128) | @Test
    method checkValues (line 150) | private void checkValues(String tableName) {
    method createTestTable (line 169) | private void createTestTable() {
    method insertExampleData (line 177) | private void insertExampleData(String tableName) {
    method tableExists (line 184) | private boolean tableExists(String tableName) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/instrumented/utilities/DateTimeUtilsTest.java
  class DateTimeUtilsTest (line 39) | @RunWith(AndroidJUnit4.class)
    method setUp (line 55) | @Before
    method getDateTimeLabelTest (line 71) | @Test
    method resetTimeZone (line 106) | @After

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/ActivityHelpers.java
  class ActivityHelpers (line 21) | public final class ActivityHelpers {
    method ActivityHelpers (line 23) | private ActivityHelpers() {
    method getActivity (line 26) | public static Activity getActivity() {
    method getLaunchIntent (line 55) | public static Intent getLaunchIntent() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/CountingTaskExecutorIdlingResource.java
  class CountingTaskExecutorIdlingResource (line 6) | public class CountingTaskExecutorIdlingResource extends CountingTaskExec...
    method getName (line 10) | @Override
    method isIdleNow (line 15) | @Override
    method registerIdleTransitionCallback (line 20) | @Override
    method onIdle (line 25) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/FakeLocationClient.java
  class FakeLocationClient (line 11) | public class FakeLocationClient implements LocationClient {
    method start (line 17) | public void start(LocationClientListener listener) {
    method stop (line 24) | public void stop() {
    method isLocationAvailable (line 32) | public boolean isLocationAvailable() {
    method requestLocationUpdates (line 36) | public void requestLocationUpdates(LocationListener locationListener) {
    method stopLocationUpdates (line 41) | public void stopLocationUpdates() {
    method setListener (line 45) | @Override
    method getLastLocation (line 50) | public Location getLastLocation() {
    method isMonitoringLocation (line 54) | public boolean isMonitoringLocation() {
    method setPriority (line 58) | public void setPriority(Priority priority) { }
    method setRetainMockAccuracy (line 60) | @Override
    method setUpdateInterval (line 65) | public void setUpdateInterval(long updateInterval) { }
    method setLocation (line 67) | public void setLocation(Location location) {
    method updateLocationListener (line 72) | private void updateLocationListener() {
    method getListener (line 78) | private LocationClientListener getListener() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/actions/RotateAction.java
  class RotateAction (line 16) | public class RotateAction implements ViewAction {
    method RotateAction (line 20) | public RotateAction(int screenOrientation) {
    method getConstraints (line 24) | @Override
    method getDescription (line 29) | @Override
    method perform (line 34) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/matchers/ToastMatcher.java
  class ToastMatcher (line 11) | public class ToastMatcher extends TypeSafeMatcher<Root> {
    method describeTo (line 13) | @Override
    method matchesSafely (line 18) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/AboutPage.java
  class AboutPage (line 11) | public class AboutPage extends Page<AboutPage> {
    method assertOnPage (line 13) | @Override
    method scrollToOpenSourceLibrariesLicenses (line 19) | public AboutPage scrollToOpenSourceLibrariesLicenses() {
    method clickOnOpenSourceLibrariesLicenses (line 24) | public OpenSourceLicensesPage clickOnOpenSourceLibrariesLicenses() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/BlankFormSearchPage.java
  class BlankFormSearchPage (line 8) | public class BlankFormSearchPage extends Page<BlankFormSearchPage> {
    method assertOnPage (line 10) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/CancelRecordingDialog.java
  class CancelRecordingDialog (line 3) | public class CancelRecordingDialog extends Page<CancelRecordingDialog> {
    method CancelRecordingDialog (line 7) | CancelRecordingDialog(String formName) {
    method assertOnPage (line 11) | @Override
    method clickOk (line 17) | public FormEntryPage clickOk() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ChangesReasonPromptPage.java
  class ChangesReasonPromptPage (line 16) | public class ChangesReasonPromptPage extends Page<ChangesReasonPromptPag...
    method ChangesReasonPromptPage (line 20) | public ChangesReasonPromptPage(String formName) {
    method assertOnPage (line 24) | @Override
    method enterReason (line 33) | public ChangesReasonPromptPage enterReason(String reason) {
    method clickSave (line 38) | public MainMenuPage clickSave() {
    method clickSave (line 43) | public <D extends Page<D>> D clickSave(D destination) {
    method pressClose (line 55) | public <D extends Page<D>> D pressClose(D destination) {
    method clickSaveWithValidationError (line 60) | public ChangesReasonPromptPage clickSaveWithValidationError() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/DeleteSavedFormPage.java
  class DeleteSavedFormPage (line 8) | public class DeleteSavedFormPage extends Page<DeleteSavedFormPage> {
    method assertOnPage (line 10) | @Override
    method clickBlankForms (line 16) | public DeleteSavedFormPage clickBlankForms() {
    method clickForm (line 21) | public DeleteSavedFormPage clickForm(String formName) {
    method clickDeleteSelected (line 26) | public DeleteSelectedDialog clickDeleteSelected(int numberSelected) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/DeleteSelectedDialog.java
  class DeleteSelectedDialog (line 3) | public class DeleteSelectedDialog extends Page<DeleteSelectedDialog> {
    method DeleteSelectedDialog (line 8) | public DeleteSelectedDialog(int numberSelected, DeleteSavedFormPage de...
    method assertOnPage (line 13) | @Override
    method clickDeleteForms (line 19) | public DeleteSavedFormPage clickDeleteForms() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/EditSavedFormPage.java
  class EditSavedFormPage (line 40) | public class EditSavedFormPage extends Page<EditSavedFormPage> {
    method assertOnPage (line 42) | @Override
    method checkInstanceState (line 48) | public EditSavedFormPage checkInstanceState(String instanceName, Strin...
    method clickOnFormWithDialog (line 58) | public OkDialog clickOnFormWithDialog(String instanceName) {
    method clickOnFormWithIdentityPrompt (line 63) | public IdentifyUserPromptPage clickOnFormWithIdentityPrompt(String for...
    method clickOnForm (line 68) | public FormHierarchyPage clickOnForm(String formName, String instanceN...
    method clickOnForm (line 73) | public FormHierarchyPage clickOnForm(String formName) {
    method clickOnFormWithSavepoint (line 78) | public SavepointRecoveryDialogPage clickOnFormWithSavepoint(String for...
    method clickOnFormClosingApp (line 83) | public AppClosedPage clickOnFormClosingApp(String formName) {
    method scrollToAndClickOnForm (line 88) | private void scrollToAndClickOnForm(String formName) {
    method clickMenuFilter (line 92) | public EditSavedFormPage clickMenuFilter() {
    method searchInBar (line 97) | public EditSavedFormPage searchInBar(String query) {
    method clickFinalizeAll (line 102) | public BulkFinalizationConfirmationDialogPage clickFinalizeAll(int cou...

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ExperimentalPage.java
  class ExperimentalPage (line 3) | public class ExperimentalPage extends Page<ExperimentalPage> {
    method assertOnPage (line 5) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FillBlankFormPage.java
  class FillBlankFormPage (line 24) | public class FillBlankFormPage extends Page<FillBlankFormPage> {
    method assertOnPage (line 26) | @Override
    method clickOnFormWithIdentityPrompt (line 32) | public IdentifyUserPromptPage clickOnFormWithIdentityPrompt(String for...
    method clickOnSortByButton (line 37) | public FillBlankFormPage clickOnSortByButton() {
    method clickMenuFilter (line 42) | public FillBlankFormPage clickMenuFilter() {
    method searchInBar (line 47) | public BlankFormSearchPage searchInBar(String query) {
    method checkMapIconDisplayedForForm (line 52) | public FillBlankFormPage checkMapIconDisplayedForForm(String formName) {
    method checkMapIconNotDisplayedForForm (line 59) | public FillBlankFormPage checkMapIconNotDisplayedForForm(String formNa...
    method clickOnMapIconForForm (line 66) | public FormMapPage clickOnMapIconForForm(String formName) {
    method clickOnForm (line 73) | public FormEntryPage clickOnForm(String formName) {
    method clickOnFormButton (line 78) | private void clickOnFormButton(String formName) {
    method clickOnEmptyForm (line 84) | public FormEndPage clickOnEmptyForm(String formName) {
    method clickRefresh (line 89) | public FillBlankFormPage clickRefresh() {
    method clickRefreshWithError (line 94) | public FillBlankFormPage clickRefreshWithError() {
    method clickRefreshWithAuthError (line 99) | public ServerAuthDialog clickRefreshWithAuthError() {
    method assertFormExists (line 104) | public FillBlankFormPage assertFormExists(String formName) {
    method assertFormDoesNotExist (line 115) | public FillBlankFormPage assertFormDoesNotExist(String formName) {
    method assertNoForms (line 122) | public FillBlankFormPage assertNoForms() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FormEndPage.java
  class FormEndPage (line 10) | public class FormEndPage extends Page<FormEndPage> {
    method FormEndPage (line 14) | public FormEndPage(String formName) {
    method assertOnPage (line 18) | @Override
    method clickSaveAsDraft (line 24) | public <D extends Page<D>> D clickSaveAsDraft(D destination) {
    method clickSaveAsDraft (line 28) | public MainMenuPage clickSaveAsDraft() {
    method clickSaveAsDraftWithError (line 32) | public FormEndPage clickSaveAsDraftWithError(String errorMsg) {
    method clickFinalize (line 38) | public <D extends Page<D>> D clickFinalize(D destination) {
    method clickFinalize (line 42) | public MainMenuPage clickFinalize() {
    method clickFinalizeWithError (line 47) | public FormEndPage clickFinalizeWithError(String errorMsg) {
    method clickSend (line 53) | public MainMenuPage clickSend() {
    method clickSaveAndExitBackToMap (line 57) | public FormMapPage clickSaveAndExitBackToMap() {
    method clickSaveAndExitWithError (line 61) | public FormEntryPage clickSaveAndExitWithError(String errorText) {
    method clickSaveAndExitWithChangesReasonPrompt (line 67) | public ChangesReasonPromptPage clickSaveAndExitWithChangesReasonPrompt...
    method clickGoToArrow (line 71) | public FormHierarchyPage clickGoToArrow() {
    method swipeToPreviousQuestion (line 76) | public FormEntryPage swipeToPreviousQuestion(String questionText) {
    method swipeToPreviousQuestion (line 80) | public FormEntryPage swipeToPreviousQuestion(String questionText, bool...
    method clickOptionsIcon (line 84) | public FormEndPage clickOptionsIcon() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FormEntryPage.java
  class FormEntryPage (line 43) | public class FormEntryPage extends Page<FormEntryPage> {
    method FormEntryPage (line 47) | public FormEntryPage(String formName) {
    method assertOnPage (line 51) | @Override
    method fillOut (line 71) | public FormEntryPage fillOut(QuestionAndAnswer... questionsAndAnswers) {
    method fillOutAndSave (line 87) | public <D extends Page<D>> D fillOutAndSave(D destination, QuestionAnd...
    method fillOutAndSave (line 93) | public MainMenuPage fillOutAndSave(QuestionAndAnswer... questionsAndAn...
    method fillOutAndFinalize (line 99) | public MainMenuPage fillOutAndFinalize(QuestionAndAnswer... questionsA...
    method swipeToNextQuestion (line 105) | public FormEntryPage swipeToNextQuestion(String questionText) {
    method swipeToNextQuestion (line 109) | public FormEntryPage swipeToNextQuestion(String questionText, boolean ...
    method swipeToPreviousQuestion (line 121) | public FormEntryPage swipeToPreviousQuestion(String questionText) {
    method swipeToPreviousQuestion (line 125) | public FormEntryPage swipeToPreviousQuestion(String questionText, bool...
    method swipeToNextRepeat (line 137) | public FormEntryPage swipeToNextRepeat(String repeatLabel, int repeatN...
    method swipeToEndScreen (line 144) | public FormEndPage swipeToEndScreen(String instanceName) {
    method swipeToEndScreen (line 149) | public FormEndPage swipeToEndScreen() {
    method swipeToNextQuestionWithError (line 154) | public ErrorDialog swipeToNextQuestionWithError(boolean isFatal) {
    method swipeToNextQuestionWithConstraintViolation (line 159) | public FormEntryPage swipeToNextQuestionWithConstraintViolation(int co...
    method swipeToNextQuestionWithConstraintViolation (line 166) | public FormEntryPage swipeToNextQuestionWithConstraintViolation(String...
    method assertQuestionText (line 173) | private void assertQuestionText(String text) {
    method clickOptionsIcon (line 177) | public FormEntryPage clickOptionsIcon() {
    method clickProjectSettings (line 181) | public ProjectSettingsPage clickProjectSettings() {
    method assertNavigationButtonsAreDisplayed (line 186) | public FormEntryPage assertNavigationButtonsAreDisplayed() {
    method assertNavigationButtonsAreHidden (line 192) | public FormEntryPage assertNavigationButtonsAreHidden() {
    method assertGoToIconExists (line 198) | public FormEntryPage assertGoToIconExists() {
    method assertGoToIconDoesNotExist (line 203) | public FormEntryPage assertGoToIconDoesNotExist() {
    method clickGoToArrow (line 208) | public FormHierarchyPage clickGoToArrow() {
    method clickWidgetButton (line 217) | public FormEntryPage clickWidgetButton() {
    method clickRankingButton (line 222) | public FormEntryPage clickRankingButton() {
    method deleteGroup (line 227) | public FormEntryPage deleteGroup(String questionText) {
    method clickForwardButton (line 234) | public FormEntryPage clickForwardButton() {
    method clickForwardButtonToEndScreen (line 240) | public FormEndPage clickForwardButtonToEndScreen() {
    method clickBackwardButton (line 246) | public FormEntryPage clickBackwardButton() {
    method clickSave (line 252) | public FormEntryPage clickSave() {
    method clickSaveWithError (line 257) | public FormEntryPage clickSaveWithError(String errorMsg) {
    method clickSaveWithChangesReasonPrompt (line 263) | public ChangesReasonPromptPage clickSaveWithChangesReasonPrompt() {
    method clickPlus (line 268) | public AddNewRepeatDialog clickPlus(String repeatName) {
    method longPressOnQuestion (line 273) | public FormEntryPage longPressOnQuestion(int id, int index) {
    method longPressOnQuestion (line 278) | public FormEntryPage longPressOnQuestion(String question) {
    method longPressOnQuestion (line 283) | public FormEntryPage longPressOnQuestion(String question, boolean isRe...
    method removeResponse (line 297) | public FormEntryPage removeResponse() {
    method swipeToNextQuestionWithRepeatGroup (line 302) | public AddNewRepeatDialog swipeToNextQuestionWithRepeatGroup(String re...
    method swipeToPreviousQuestionWithRepeatGroup (line 307) | public AddNewRepeatDialog swipeToPreviousQuestionWithRepeatGroup(Strin...
    method answerQuestion (line 312) | public FormEntryPage answerQuestion(String question, String answer) {
    method answerQuestion (line 317) | public FormEntryPage answerQuestion(String question, boolean isRequire...
    method answerQuestion (line 332) | @Deprecated
    method assertAnswer (line 339) | public FormEntryPage assertAnswer(String questionText, String answer) {
    method assertAnswer (line 343) | public FormEntryPage assertAnswer(String questionText, String answer, ...
    method clickOnQuestionField (line 354) | public FormEntryPage clickOnQuestionField(String questionText) {
    method assertQuestion (line 359) | public FormEntryPage assertQuestion(String text) {
    method assertQuestion (line 363) | public FormEntryPage assertQuestion(String text, boolean isRequired) {
    method assertNoQuestion (line 373) | public FormEntryPage assertNoQuestion(String text) {
    method assertNoQuestion (line 377) | public FormEntryPage assertNoQuestion(String text, boolean isRequired) {
    method flingLeft (line 387) | private void flingLeft() {
    method flingRight (line 393) | private void flingRight() {
    method openSelectMinimalDialog (line 399) | public SelectMinimalDialogPage openSelectMinimalDialog() {
    method openSelectMinimalDialog (line 403) | public SelectMinimalDialogPage openSelectMinimalDialog(int index) {
    method assertSelectMinimalDialogAnswer (line 408) | public FormEntryPage assertSelectMinimalDialogAnswer(@Nullable String ...
    method swipeToEndScreenWhileRecording (line 417) | public OkDialog swipeToEndScreenWhileRecording() {
    method clickRecordAudio (line 424) | public CancelRecordingDialog clickRecordAudio() {
    method pressBackAndDiscardChanges (line 429) | public MainMenuPage pressBackAndDiscardChanges() {
    method pressBackAndDiscardChanges (line 435) | public <D extends Page<D>> D pressBackAndDiscardChanges(D destination) {
    method pressBackAndSaveAsDraft (line 441) | public MainMenuPage pressBackAndSaveAsDraft() {
    method pressBackAndSaveAsDraft (line 447) | public <D extends Page<D>> D pressBackAndSaveAsDraft(D destination) {
    method pressBackAndDiscardForm (line 453) | public MainMenuPage pressBackAndDiscardForm() {
    method pressBackAndDiscardForm (line 459) | public <D extends Page<D>> D pressBackAndDiscardForm(D destination) {
    method assertBackgroundLocationSnackbarShown (line 465) | public FormEntryPage assertBackgroundLocationSnackbarShown() {
    method setRating (line 470) | public FormEntryPage setRating(float value) {
    method assertQuestionHasFocus (line 475) | public FormEntryPage assertQuestionHasFocus(String questionText) {
    method getQuestionFieldMatcher (line 481) | private static @NonNull Matcher<View> getQuestionFieldMatcher(String q...
    method assertImageViewShowsImage (line 488) | public FormEntryPage assertImageViewShowsImage(int resourceid, Bitmap ...
    class QuestionAndAnswer (line 493) | public static class QuestionAndAnswer {
      method QuestionAndAnswer (line 499) | public QuestionAndAnswer(String question, String answer) {
      method QuestionAndAnswer (line 503) | public QuestionAndAnswer(String question, String answer, boolean isR...

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FormManagementPage.java
  class FormManagementPage (line 15) | public class FormManagementPage extends Page<FormManagementPage> {
    method assertOnPage (line 17) | @Override
    method clickUpdateForms (line 23) | public ListPreferenceDialog<FormManagementPage> clickUpdateForms() {
    method clickAutomaticUpdateFrequency (line 28) | public ListPreferenceDialog<FormManagementPage> clickAutomaticUpdateFr...
    method clickAutoSend (line 33) | public ListPreferenceDialog<FormManagementPage> clickAutoSend() {
    method openShowGuidanceForQuestions (line 38) | public FormManagementPage openShowGuidanceForQuestions() {
    method openConstraintProcessing (line 43) | public FormManagementPage openConstraintProcessing() {
    method scrollToConstraintProcessing (line 48) | public FormManagementPage scrollToConstraintProcessing() {
    method checkIfConstraintProcessingIsDisabled (line 54) | public FormManagementPage checkIfConstraintProcessingIsDisabled() {
    method checkIfConstraintProcessingIsEnabled (line 59) | public FormManagementPage checkIfConstraintProcessingIsEnabled() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FormMapPage.java
  class FormMapPage (line 5) | public class FormMapPage extends Page<FormMapPage> {
    method FormMapPage (line 9) | public FormMapPage(String formName) {
    method assertOnPage (line 13) | @Override
    method clickFillBlankFormButton (line 20) | public FormEntryPage clickFillBlankFormButton(String formName) {
    method selectForm (line 25) | public FormMapPage selectForm(FakeClickableMapFragment mapFragment, in...
    method clickEditSavedForm (line 30) | public FormHierarchyPage clickEditSavedForm(String formName) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/FormMetadataPage.java
  class FormMetadataPage (line 7) | public class FormMetadataPage extends PreferencePage<FormMetadataPage> {
    method assertOnPage (line 9) | @Override
    method clickEmail (line 15) | public FormMetadataPage clickEmail() {
    method clickUsername (line 20) | public FormMetadataPage clickUsername() {
    method clickPhoneNumber (line 25) | public FormMetadataPage clickPhoneNumber() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/GetBlankFormPage.java
  class GetBlankFormPage (line 11) | public class GetBlankFormPage extends Page<GetBlankFormPage> {
    method assertOnPage (line 13) | @Override
    method clickGetSelected (line 19) | public FormsDownloadResultPage clickGetSelected() {
    method clickClearAll (line 24) | public GetBlankFormPage clickClearAll() {
    method clickSelectAll (line 29) | public GetBlankFormPage clickSelectAll() {
    method clickForm (line 34) | public GetBlankFormPage clickForm(String formName) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/IdentifyUserPromptPage.java
  class IdentifyUserPromptPage (line 10) | public class IdentifyUserPromptPage extends Page<IdentifyUserPromptPage> {
    method IdentifyUserPromptPage (line 14) | public IdentifyUserPromptPage(String formName) {
    method assertOnPage (line 19) | @Override
    method enterIdentity (line 26) | public IdentifyUserPromptPage enterIdentity(String identity) {
    method clickKeyboardEnter (line 31) | public <D extends Page<D>> D clickKeyboardEnter(D destination) {
    method clickKeyboardEnterWithValidationError (line 36) | public IdentifyUserPromptPage clickKeyboardEnterWithValidationError() {
    method pressClose (line 41) | public MainMenuPage pressClose() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ListPreferenceDialog.java
  class ListPreferenceDialog (line 3) | public class ListPreferenceDialog<T extends Page<T>> extends Page<ListPr...
    method ListPreferenceDialog (line 8) | ListPreferenceDialog(int title, T page) {
    method assertOnPage (line 13) | @Override
    method clickOption (line 19) | public T clickOption(int option) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MainMenuPage.java
  class MainMenuPage (line 26) | public class MainMenuPage extends Page<MainMenuPage> {
    method assertOnPage (line 28) | @Override
    method openProjectSettingsDialog (line 40) | public ProjectSettingsDialogPage openProjectSettingsDialog() {
    method startBlankForm (line 47) | public FormEntryPage startBlankForm(String formName) {
    method startBlankFormWithSavepoint (line 52) | public SavepointRecoveryDialogPage startBlankFormWithSavepoint(String ...
    method startBlankFormWithRepeatGroup (line 57) | public AddNewRepeatDialog startBlankFormWithRepeatGroup(String formNam...
    method startBlankFormWithError (line 62) | public ErrorDialog startBlankFormWithError(String formName, boolean is...
    method startBlankFormWithDialog (line 67) | public OkDialog startBlankFormWithDialog(String formName) {
    method clickFillBlankForm (line 72) | public FillBlankFormPage clickFillBlankForm() {
    method goToBlankForm (line 80) | private void goToBlankForm(String formName) {
    method clickDrafts (line 84) | public EditSavedFormPage clickDrafts() {
    method clickDrafts (line 89) | public EditSavedFormPage clickDrafts(int formCount) {
    method assertNumberOfFinalizedForms (line 94) | public MainMenuPage assertNumberOfFinalizedForms(int number) {
    method assertNumberOfEditableForms (line 103) | public MainMenuPage assertNumberOfEditableForms(int number) {
    method assertNumberOfSentForms (line 113) | private MainMenuPage assertNumberOfSentForms(int number) {
    method clickGetBlankForm (line 123) | public GetBlankFormPage clickGetBlankForm() {
    method clickGetBlankForm (line 127) | public <D extends Page<D>> D clickGetBlankForm(D destination) {
    method clickSendFinalizedForm (line 132) | public SendFinalizedFormPage clickSendFinalizedForm(int number) {
    method setServer (line 138) | public MainMenuPage setServer(String url) {
    method enableManualUpdates (line 149) | public MainMenuPage enableManualUpdates() {
    method enablePreviouslyDownloadedOnlyUpdates (line 159) | public MainMenuPage enablePreviouslyDownloadedOnlyUpdates() {
    method enablePreviouslyDownloadedOnlyUpdatesWithAutomaticDownload (line 169) | public MainMenuPage enablePreviouslyDownloadedOnlyUpdatesWithAutomatic...
    method enableMatchExactly (line 180) | public MainMenuPage enableMatchExactly() {
    method enableAutoSend (line 190) | public MainMenuPage enableAutoSend(TrackingCoroutineAndWorkManagerSche...
    method addAndSwitchToProject (line 203) | public MainMenuPage addAndSwitchToProject(String serverUrl) {
    method clickGetBlankFormWithAuthenticationError (line 211) | public ServerAuthDialog clickGetBlankFormWithAuthenticationError() {
    method clickGetBlankFormWithError (line 216) | public OkDialog clickGetBlankFormWithError() {
    method clickViewSentForm (line 221) | public ViewSentFormPage clickViewSentForm(int number) {
    method clickDeleteSavedForm (line 227) | public DeleteSavedFormPage clickDeleteSavedForm() {
    method assertProjectIcon (line 232) | public MainMenuPage assertProjectIcon(String projectIcon) {
    method copyForm (line 237) | public MainMenuPage copyForm(String formFilename) {
    method copyForm (line 241) | public MainMenuPage copyForm(String formFilename, String projectName) {
    method copyForm (line 245) | public MainMenuPage copyForm(String formFilename, List<String> mediaFi...
    method copyForm (line 249) | public MainMenuPage copyForm(String formFilename, List<String> mediaFi...
    method copyForm (line 253) | public MainMenuPage copyForm(String formFilename, List<String> mediaFi...
    method copyInstance (line 263) | public MainMenuPage copyInstance(String instanceFileName) {
    method copyInstance (line 268) | public MainMenuPage copyInstance(String instanceFileName, String proje...
    method openEntityBrowser (line 278) | public EntitiesPage openEntityBrowser() {
    method refreshForms (line 287) | public MainMenuPage refreshForms() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/MapsSettingsPage.java
  class MapsSettingsPage (line 3) | public class MapsSettingsPage extends Page<MapsSettingsPage> {
    method assertOnPage (line 5) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/OkDialog.java
  class OkDialog (line 25) | public class OkDialog extends Page<OkDialog> {
    method assertOnPage (line 27) | @Override
    method clickOK (line 33) | public <D extends Page<D>> D clickOK(D destination) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/OpenSourceLicensesPage.java
  class OpenSourceLicensesPage (line 3) | class OpenSourceLicensesPage extends Page<OpenSourceLicensesPage> {
    method assertOnPage (line 5) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/PreferencePage.java
  class PreferencePage (line 14) | abstract class PreferencePage<T extends Page<T>> extends Page<T> {
    method assertPreference (line 16) | public T assertPreference(int name, String summary) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ProjectSettingsPage.java
  class ProjectSettingsPage (line 10) | public class ProjectSettingsPage extends Page<ProjectSettingsPage> {
    method assertOnPage (line 12) | @Override
    method clickProjectDisplay (line 18) | public ProjectDisplayPage clickProjectDisplay() {
    method clickProjectManagement (line 23) | public ProjectManagementPage clickProjectManagement() {
    method clickAccessControl (line 28) | public AccessControlPage clickAccessControl() {
    method clickOnUserInterface (line 33) | public UserInterfacePage clickOnUserInterface() {
    method openFormManagement (line 38) | public FormManagementPage openFormManagement() {
    method clickServerSettings (line 43) | public ServerSettingsPage clickServerSettings() {
    method clickMaps (line 48) | public MapsSettingsPage clickMaps() {
    method clickUserAndDeviceIdentity (line 54) | public UserAndDeviceIdentitySettingsPage clickUserAndDeviceIdentity() {
    method checkIfServerOptionIsDisplayed (line 59) | public ProjectSettingsPage checkIfServerOptionIsDisplayed() {
    method checkIfFormManagementOptionIsDisplayed (line 64) | public ProjectSettingsPage checkIfFormManagementOptionIsDisplayed() {
    method checkIfServerOptionIsNotDisplayed (line 69) | public ProjectSettingsPage checkIfServerOptionIsNotDisplayed() {
    method clickFormManagement (line 74) | public FormManagementPage clickFormManagement() {
    method clickExperimental (line 79) | public ExperimentalPage clickExperimental() {
    method setAdminPassword (line 84) | public ProjectSettingsPage setAdminPassword(String password) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/QRCodePage.java
  class QRCodePage (line 19) | public class QRCodePage extends Page<QRCodePage> {
    method assertOnPage (line 20) | @Override
    method clickScanFragment (line 26) | public QRCodePage clickScanFragment() {
    method clickView (line 31) | public QRCodePage clickView() {
    method assertImageViewShowsImage (line 42) | public QRCodePage assertImageViewShowsImage(int resourceid, Bitmap ima...
    method clickOnMenu (line 47) | public QRCodePage clickOnMenu() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ResetApplicationDialog.java
  class ResetApplicationDialog (line 9) | public class ResetApplicationDialog extends Page<ResetApplicationDialog> {
    method assertOnPage (line 11) | @Override

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ServerAuthDialog.java
  class ServerAuthDialog (line 3) | public class ServerAuthDialog extends Page<ServerAuthDialog> {
    method assertOnPage (line 5) | @Override
    method fillUsername (line 11) | public ServerAuthDialog fillUsername(String username) {
    method fillPassword (line 16) | public ServerAuthDialog fillPassword(String password) {
    method clickOK (line 21) | public <D extends Page<D>> D clickOK(D destination) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ServerSettingsPage.java
  class ServerSettingsPage (line 7) | public class ServerSettingsPage extends Page<ServerSettingsPage> {
    method assertOnPage (line 9) | @Override
    method clickServerUsername (line 15) | public ServerSettingsPage clickServerUsername() {
    method clickOnURL (line 20) | public ServerSettingsPage clickOnURL() {
    method clickServerPassword (line 25) | public ServerSettingsPage clickServerPassword() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ShortcutsPage.java
  class ShortcutsPage (line 9) | public class ShortcutsPage extends Page<ShortcutsPage> {
    method ShortcutsPage (line 13) | public ShortcutsPage(ActivityScenario<AndroidShortcutsActivity> scenar...
    method assertOnPage (line 17) | @Override
    method selectForm (line 23) | public Intent selectForm(String formName) {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/UserAndDeviceIdentitySettingsPage.java
  class UserAndDeviceIdentitySettingsPage (line 3) | public class UserAndDeviceIdentitySettingsPage extends Page<UserAndDevic...
    method assertOnPage (line 5) | @Override
    method clickFormMetadata (line 11) | public FormMetadataPage clickFormMetadata() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/UserInterfacePage.java
  class UserInterfacePage (line 9) | public class UserInterfacePage extends Page<UserInterfacePage> {
    method assertOnPage (line 11) | @Override
    method clickOnLanguage (line 17) | public UserInterfacePage clickOnLanguage() {
    method clickOnSelectedLanguage (line 22) | public MainMenuPage clickOnSelectedLanguage(String language) {
    method clickNavigation (line 27) | public UserInterfacePage clickNavigation() {
    method clickUseSwipesAndButtons (line 32) | public UserInterfacePage clickUseSwipesAndButtons() {
    method clickOnTheme (line 37) | public UserInterfacePage clickOnTheme() {
    method clickUseNavigationButtons (line 42) | public UserInterfacePage clickUseNavigationButtons() {
    method clickSwipes (line 47) | public UserInterfacePage clickSwipes() {

FILE: collect_app/src/androidTest/java/org/odk/collect/android/support/pages/ViewSentFormPage.java
  class ViewSentFormPage (line 9) | public class ViewSentFormPage extends Page<ViewSentFormPage> {
    method assertOnPage (line 11) | @Override
    method clickOnForm (line 17) | public ViewFormPage clickOnForm(String formName) {

FILE: collect_app/src/main/assets/svg_map_helper.js
  function selectArea (line 25) | function selectArea(areaId) {
  function unselectArea (line 29) | function unselectArea(areaId) {
  function notifyChanges (line 33) | function notifyChanges() {
  function clearAreas (line 37) | function clearAreas() {
  function addSelectedArea (line 47) | function addSelectedArea(selectedAreaId) {
  function addArea (line 55) | function addArea(areaId) {
  function setSelectMode (line 59) | function setSelectMode(isSingleSelect) {
  function clickOnArea (line 63) | function clickOnArea(areaId) {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/ActivityUtils.java
  class ActivityUtils (line 6) | public final class ActivityUtils {
    method ActivityUtils (line 8) | private ActivityUtils() {
    method startActivityAndCloseAllOthers (line 12) | public static <A extends Activity> void startActivityAndCloseAllOthers...

FILE: collect_app/src/main/java/org/odk/collect/android/activities/AppListActivity.java
  class AppListActivity (line 53) | public abstract class AppListActivity extends LocalizedActivity {
    method onCreate (line 76) | @Override
    method toggleChecked (line 90) | public static boolean toggleChecked(ListView lv) {
    method setAllToCheckedState (line 101) | public static void setAllToCheckedState(ListView lv, boolean check) {
    method toggleButtonLabel (line 113) | public static void toggleButtonLabel(Button toggleButton, ListView lv) {
    method setContentView (line 121) | @Override
    method setContentView (line 127) | @Override
    method init (line 133) | private void init() {
    method onResume (line 150) | @Override
    method onSaveInstanceState (line 156) | @Override
    method onRestoreInstanceState (line 169) | @Override
    method onCreateOptionsMenu (line 177) | @Override
    method onOptionsItemSelected (line 223) | @Override
    method checkPreviouslyCheckedItems (line 245) | protected void checkPreviouslyCheckedItems() {
    method updateAdapter (line 265) | protected abstract void updateAdapter();
    method getSortingOrderKey (line 267) | protected abstract String getSortingOrderKey();
    method areCheckedItems (line 269) | protected boolean areCheckedItems() {
    method getCheckedCount (line 273) | protected int getCheckedCount() {
    method saveSelectedSortingOrder (line 277) | private void saveSelectedSortingOrder(int selectedStringOrder) {
    method restoreSelectedSortingOrder (line 282) | protected void restoreSelectedSortingOrder() {
    method getSelectedSortingOrder (line 286) | protected int getSelectedSortingOrder() {
    method getFilterText (line 293) | protected CharSequence getFilterText() {
    method clearSearchView (line 297) | protected void clearSearchView() {
    method hideProgressBarAndAllow (line 301) | protected void hideProgressBarAndAllow() {
    method hideProgressBar (line 305) | private void hideProgressBar() {
    method showProgressBar (line 309) | protected void showProgressBar() {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/BearingActivity.java
  class BearingActivity (line 31) | public class BearingActivity extends LocalizedActivity implements Sensor...
    method onCreate (line 43) | @Override
    method onPause (line 55) | @Override
    method onResume (line 67) | @Override
    method setupBearingDialog (line 79) | private void setupBearingDialog() {
    method returnBearing (line 111) | private void returnBearing() {
    method onAccuracyChanged (line 119) | @Override
    method onSensorChanged (line 125) | @Override
    method formatDegrees (line 179) | public static String formatDegrees(double degrees) {
    method normalizeDegrees (line 183) | public static double normalizeDegrees(double value) {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/FormDownloadListActivity.java
  class FormDownloadListActivity (line 94) | public class FormDownloadListActivity extends FormListActivity implement...
    method onCreate (line 134) | @SuppressWarnings("unchecked")
    method init (line 149) | private void init(Bundle savedInstanceState) {
    method clearChoices (line 252) | private void clearChoices() {
    method onItemClick (line 257) | @Override
    method downloadFormList (line 272) | private void downloadFormList() {
    method onRestoreInstanceState (line 307) | @Override
    method onSaveInstanceState (line 313) | @Override
    method getSortingOrderKey (line 319) | @Override
    method updateAdapter (line 324) | @Override
    method checkPreviouslyCheckedItems (line 350) | @Override
    method sortList (line 362) | private void sortList() {
    method getFilesToDownload (line 372) | private ArrayList<ServerFormDetails> getFilesToDownload() {
    method startFormsDownload (line 389) | @SuppressWarnings("unchecked")
    method onRetainCustomNonConfigurationInstance (line 413) | @Override
    method onDestroy (line 422) | @Override
    method onResume (line 433) | @Override
    method onPause (line 450) | @Override
    method isLocalFormSuperseded (line 458) | public boolean isLocalFormSuperseded(String formId) {
    method selectSupersededForms (line 473) | private void selectSupersededForms() {
    method formListDownloadingComplete (line 484) | @Override
    method performDownloadModeDownload (line 551) | private void performDownloadModeDownload() {
    method createAlertDialog (line 582) | private void createAlertDialog(String title, String message, final boo...
    method createAuthDialog (line 611) | private void createAuthDialog() {
    method createCancelDialog (line 622) | private void createCancelDialog() {
    method progressUpdate (line 632) | @Override
    method formsDownloadingComplete (line 642) | @Override
    method formsDownloadingCancelled (line 670) | @Override
    method updatedCredentials (line 690) | @Override
    method cancelledUpdatingCredentials (line 706) | @Override
    method setReturnResult (line 711) | private void setReturnResult(boolean successful, @Nullable String mess...
    method cleanUpWebCredentials (line 724) | private void cleanUpWebCredentials() {
    method onCancelFormLoading (line 735) | @Override
    method onCloseDownloadingResult (line 758) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/activities/FormFillingActivity.java
  class FormFillingActivity (line 226) | public class FormFillingActivity extends LocalizedActivity implements Co...
    method allowSwiping (line 293) | @Override
    method handleOnBackPressed (line 396) | @Override
    method onCreate (line 416) | @Override
    method setupViewModels (line 556) | private void setupViewModels(FormEntryViewModelFactory formEntryViewMo...
    method handleValidationResult (line 649) | private void handleValidationResult(ODKView view, ValidationResult val...
    method formControllerAvailable (line 667) | private void formControllerAvailable(@NonNull FormController formContr...
    method setupFields (line 673) | private void setupFields(Bundle savedInstanceState) {
    method loadForm (line 699) | private void loadForm() {
    method loadFromIntent (line 736) | private void loadFromIntent(Intent intent) {
    method initToolbar (line 751) | private void initToolbar() {
    method nonblockingCreateSavePointData (line 763) | private void nonblockingCreateSavePointData() {
    method getFormController (line 794) | @Nullable
    method onSaveInstanceState (line 799) | @Override
    method onActivityResult (line 837) | @Override
    method loadMedia (line 930) | private void loadMedia(Uri uri) {
    method getWidgetWaitingForBinaryData (line 940) | public QuestionWidget getWidgetWaitingForBinaryData() {
    method setWidgetData (line 955) | public void setWidgetData(Object data) {
    method clearAnswer (line 986) | private void clearAnswer(QuestionWidget qw) {
    method onCreateContextMenu (line 994) | @Override
    method onContextItemSelected (line 1009) | @Override
    method deleteGroup (line 1028) | public void deleteGroup() {
    method onRetainCustomNonConfigurationInstance (line 1041) | @Override
    method createView (line 1060) | private SwipeHandler.View createView(int event, boolean advancingPage) {
    method createODKView (line 1128) | @NotNull
    method releaseOdkView (line 1140) | private void releaseOdkView() {
    method createViewForFormEnd (line 1155) | private SwipeHandler.View createViewForFormEnd(FormController formCont...
    method dispatchTouchEvent (line 1195) | @Override
    method onSwipeForward (line 1205) | @Override
    method onSwipeBackward (line 1210) | @Override
    method moveScreen (line 1215) | private void moveScreen(Direction direction) {
    method onScreenChange (line 1265) | @Override
    method onScreenRefresh (line 1289) | @Override
    method animateToNextView (line 1299) | private void animateToNextView(int event) {
    method animateToPreviousView (line 1322) | private void animateToPreviousView(int event) {
    method showView (line 1332) | public void showView(SwipeHandler.View next, FormAnimationType from) {
    method createRepeatDialog (line 1425) | private void createRepeatDialog() {
    method createErrorDialog (line 1483) | private void createErrorDialog(FormError error) {
    method saveForm (line 1518) | public boolean saveForm(boolean exit, boolean complete, String updated...
    method handleSaveResult (line 1533) | private void handleSaveResult(FormSaveViewModel.SaveResult result) {
    method getAbsoluteInstancePath (line 1613) | @Nullable
    method createClearDialog (line 1622) | private void createClearDialog(final QuestionWidget qw) {
    method createLanguageDialog (line 1660) | public void createLanguageDialog() {
    method updateNavigationButtonVisibility (line 1694) | private void updateNavigationButtonVisibility() {
    method onStart (line 1704) | @Override
    method onPause (line 1722) | @Override
    method onResume (line 1729) | @Override
    method onResumeFragments (line 1772) | @Override
    method onKeyDown (line 1788) | @Override
    method onDestroy (line 1809) | @Override
    method afterAllAnimations (line 1838) | private void afterAllAnimations() {
    method onAnimationEnd (line 1855) | @Override
    method onAnimationRepeat (line 1870) | @Override
    method onAnimationStart (line 1874) | @Override
    method loadingComplete (line 1894) | @Override
    method loadingError (line 2037) | @Override
    method showFormLoadErrorAndExit (line 2042) | private void showFormLoadErrorAndExit(String errorMsg) {
    method onProgressStep (line 2052) | public void onProgressStep(String stepMessage) {
    method next (line 2061) | public void next() {
    method finishAndReturnInstance (line 2072) | private void finishAndReturnInstance() {
    method exit (line 2094) | private void exit() {
    method advance (line 2100) | @Override
    method onSavePointError (line 2105) | @Override
    method onSaveFormIndexError (line 2112) | @Override
    method onDateChanged (line 2119) | @Override
    method onTimeChanged (line 2124) | @Override
    method onRankingChanged (line 2129) | @Override
    method updateSelectedItems (line 2138) | @Override
    method onCancelFormLoading (line 2148) | @Override
    method onDataChanged (line 2160) | private void onDataChanged(Object data) {
    method getCurrentViewIfODKView (line 2173) | @Nullable
    class EmptyView (line 2184) | static class EmptyView extends SwipeHandler.View {
      method EmptyView (line 2185) | EmptyView(Context context) {
      method shouldSuppressFlingGesture (line 2189) | @Override
      method verticalScrollView (line 2194) | @Nullable
    class LocationProvidersReceiver (line 2201) | private class LocationProvidersReceiver extends BroadcastReceiver {
      method onReceive (line 2202) | @Override
    method activityDisplayed (line 2211) | private void activityDisplayed() {
    method displayUIFor (line 2232) | private void displayUIFor(@Nullable BackgroundLocationManager.Backgrou...
    method widgetValueChanged (line 2259) | @Override
    method updateFieldListQuestions (line 2299) | private void updateFieldListQuestions(FormIndex lastChangedIndex) thro...
    method getAnswers (line 2309) | private HashMap<FormIndex, IAnswerData> getAnswers() {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/FormListActivity.java
  class FormListActivity (line 10) | public abstract class FormListActivity extends AppListActivity {
    method getSortingOrder (line 19) | protected String getSortingOrder() {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/InstanceChooserList.java
  class InstanceChooserList (line 74) | @Deprecated
    method onCreate (line 107) | @Override
    method init (line 174) | private void init() {
    method onItemClick (line 182) | @Override
    method setupAdapter (line 218) | private void setupAdapter() {
    method getSortingOrderKey (line 231) | @Override
    method updateAdapter (line 236) | @Override
    method onCreateLoader (line 241) | @NonNull
    method onLoadFinished (line 252) | @Override
    method onLoaderReset (line 258) | @Override
    method getSortingOrder (line 263) | protected String getSortingOrder() {

FILE: collect_app/src/main/java/org/odk/collect/android/activities/viewmodels/FormDownloadListViewModel.java
  class FormDownloadListViewModel (line 30) | public class FormDownloadListViewModel extends ViewModel {
    method getFormDetailsByFormId (line 59) | public HashMap<String, ServerFormDetails> getFormDetailsByFormId() {
    method setFormDetailsByFormId (line 63) | public void setFormDetailsByFormId(HashMap<String, ServerFormDetails> ...
    method clearFormDetailsByFormId (line 67) | public void clearFormDetailsByFormId() {
    method getAlertTitle (line 71) | public String getAlertTitle() {
    method setAlertTitle (line 75) | public void setAlertTitle(String alertTitle) {
    method getAlertDialogMsg (line 79) | public String getAlertDialogMsg() {
    method setAlertDialogMsg (line 83) | public void setAlertDialogMsg(String alertDialogMsg) {
    method isAlertShowing (line 87) | public boolean isAlertShowing() {
    method setAlertShowing (line 91) | public void setAlertShowing(boolean alertShowing) {
    method shouldExit (line 95) | public boolean shouldExit() {
    method setShouldExit (line 99) | public void setShouldExit(boolean shouldExit) {
    method getFormList (line 103) | public ArrayList<HashMap<String, String>> getFormList() {
    method clearFormList (line 107) | public void clearFormList() {
    method addForm (line 111) | public void addForm(HashMap<String, String> item) {
    method addForm (line 115) | public void addForm(int index, HashMap<String, String> item) {
    method getSelectedFormIds (line 119) | public LinkedHashSet<String> getSelectedFormIds() {
    method addSelectedFormId (line 123) | public void addSelectedFormId(String selectedFormId) {
    method removeSelectedFormId (line 127) | public void removeSelectedFormId(String selectedFormId) {
    method clearSelectedFormIds (line 131) | public void clearSelectedFormIds() {
    method isDownloadOnlyMode (line 135) | public boolean isDownloadOnlyMode() {
    method setDownloadOnlyMode (line 139) | public void setDownloadOnlyMode(boolean downloadOnlyMode) {
    method getFormResults (line 143) | public HashMap<String, Boolean> getFormResults() {
    method putFormResult (line 147) | public void putFormResult(String formId, boolean result) {
    method getPassword (line 151) | public String getPassword() {
    method setPassword (line 155) | public void setPassword(String password) {
    method getUsername (line 159) | public String getUsername() {
    method setUsername (line 163) | public void setUsername(String username) {
    method getUrl (line 167) | public String getUrl() {
    method setUrl (line 171) | public void setUrl(String url) {
    method getFormIdsToDownload (line 175) | public String[] getFormIdsToDownload() {
    method setFormIdsToDownload (line 179) | public void setFormIdsToDownload(String[] formIdsToDownload) {
    method isCancelDialogShowing (line 183) | public boolean isCancelDialogShowing() {
    method setCancelDialogShowing (line 187) | public void setCancelDialogShowing(boolean cancelDialogShowing) {
    method wasLoadingCanceled (line 191) | public boolean wasLoadingCanceled() {
    method setLoadingCanceled (line 195) | public void setLoadingCanceled(boolean loadingCanceled) {
    class Factory (line 199) | public static class Factory implements ViewModelProvider.Factory {
      method create (line 201) | @SuppressWarnings("unchecked")

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/AbstractSelectListAdapter.java
  class AbstractSelectListAdapter (line 62) | public abstract class AbstractSelectListAdapter extends RecyclerView.Ada...
    method AbstractSelectListAdapter (line 76) | AbstractSelectListAdapter(Context context, List<SelectChoice> items, F...
    method onBindViewHolder (line 91) | @Override
    method getItemCount (line 96) | @Override
    method getFilter (line 101) | @Override
    method createButton (line 133) | abstract CompoundButton createButton(int index, ViewGroup parent);
    method setUpButton (line 135) | void setUpButton(TextView button, int index) {
    method isItemSelected (line 141) | boolean isItemSelected(List<Selection> selectedItems, @NonNull Selecti...
    method onItemClick (line 150) | abstract void onItemClick(Selection selection, View view);
    method getSelectedItems (line 152) | public abstract List<Selection> getSelectedItems();
    method getFilteredItems (line 154) | public List<SelectChoice> getFilteredItems() {
    method getAudioPlayer (line 158) | public AudioPlayer getAudioPlayer() {
    method setContext (line 162) | public void setContext(Context context) {
    method setAudioPlayer (line 166) | public void setAudioPlayer(AudioPlayer audioPlayer) {
    class ViewHolder (line 170) | abstract class ViewHolder extends RecyclerView.ViewHolder {
      method ViewHolder (line 174) | ViewHolder(View itemView) {
      method bind (line 178) | void bind(final int index) {
      method getImageFile (line 190) | private File getImageFile(int index) {
      method getChoiceText (line 204) | private String getChoiceText(int index) {
      method getErrorMsg (line 209) | private String getErrorMsg(File imageFile) {
      method enableLongClickToAllowRemovingAnswers (line 213) | private void enableLongClickToAllowRemovingAnswers(View view) {
      method addMediaFromChoice (line 227) | public void addMediaFromChoice(AudioVideoImageTextLabel audioVideoIm...
      method getImageURI (line 258) | private String getImageURI(int index, List<SelectChoice> items) {
      method adjustAudioVideoImageTextLabelForFlexAppearance (line 269) | void adjustAudioVideoImageTextLabelForFlexAppearance() {
    method playAudio (line 282) | public void playAudio(SelectChoice selectChoice) {
    method getNumColumns (line 290) | public int getNumColumns() {
    method clearAnswer (line 294) | public abstract void clearAnswer();
    method hasAnswerChanged (line 296) | public abstract boolean hasAnswerChanged();

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/FormDownloadListAdapter.java
  class FormDownloadListAdapter (line 37) | public class FormDownloadListAdapter extends ArrayAdapter {
    method FormDownloadListAdapter (line 42) | public FormDownloadListAdapter(Context context, ArrayList<HashMap<Stri...
    method setFromIdsToDetails (line 49) | public void setFromIdsToDetails(HashMap<String, ServerFormDetails> for...
    class ViewHolder (line 53) | private static class ViewHolder {
    method getView (line 59) | public View getView(int position, View convertView, @NonNull ViewGroup...

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/InstanceListCursorAdapter.java
  class InstanceListCursorAdapter (line 31) | public class InstanceListCursorAdapter extends SimpleCursorAdapter {
    method InstanceListCursorAdapter (line 35) | public InstanceListCursorAdapter(Context context, int layout, Cursor c...
    method setOnItemClickListener (line 40) | public void setOnItemClickListener(OnItemClickListener onItemClickList...
    method getView (line 44) | @Override
    type OnItemClickListener (line 64) | public interface OnItemClickListener {
      method onItemClick (line 65) | void onItemClick(View view, int position);

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/InstanceUploaderAdapter.java
  class InstanceUploaderAdapter (line 19) | public class InstanceUploaderAdapter extends CursorAdapter {
    method InstanceUploaderAdapter (line 23) | public InstanceUploaderAdapter(Context context, Cursor cursor, Consume...
    method newView (line 28) | @Override
    method bindView (line 35) | @Override
    method setSelected (line 49) | public void setSelected(Set<Long> ids) {

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/RankingListAdapter.java
  class RankingListAdapter (line 41) | public class RankingListAdapter extends Adapter<ItemViewHolder> {
    method RankingListAdapter (line 46) | public RankingListAdapter(List<SelectChoice> items, FormEntryPrompt fo...
    method onCreateViewHolder (line 51) | @NonNull
    method onBindViewHolder (line 57) | @Override
    method onItemMove (line 63) | public void onItemMove(int fromPosition, int toPosition) {
    method getItemCount (line 68) | @Override
    method getItems (line 73) | public List<SelectChoice> getItems() {
    class ItemViewHolder (line 77) | public static class ItemViewHolder extends ViewHolder {
      method ItemViewHolder (line 83) | ItemViewHolder(View itemView) {
      method onItemSelected (line 91) | public void onItemSelected() {
      method onItemClear (line 98) | public void onItemClear() {

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/SelectMultipleListAdapter.java
  class SelectMultipleListAdapter (line 44) | public class SelectMultipleListAdapter extends AbstractSelectListAdapter {
    method SelectMultipleListAdapter (line 50) | public SelectMultipleListAdapter(List<Selection> selectedItems, Select...
    method onCreateViewHolder (line 60) | @Override
    class ViewHolder (line 67) | class ViewHolder extends AbstractSelectListAdapter.ViewHolder {
      method ViewHolder (line 68) | ViewHolder(View v) {
      method bind (line 79) | void bind(final int index) {
    method createButton (line 95) | @Override
    method checkCheckBoxIfNeeded (line 115) | private void checkCheckBoxIfNeeded(CheckBox checkBox, int index) {
    method onItemClick (line 125) | @Override
    method addItem (line 146) | public void addItem(Selection item) {
    method removeItem (line 152) | public void removeItem(Selection item) {
    method clearAnswer (line 161) | @Override
    method getSelectedItems (line 167) | @Override
    method hasAnswerChanged (line 172) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/adapters/SelectOneListAdapter.java
  class SelectOneListAdapter (line 46) | public class SelectOneListAdapter extends AbstractSelectListAdapter impl...
    method SelectOneListAdapter (line 53) | public SelectOneListAdapter(String selectedValue, SelectItemClickListe...
    method onCreateViewHolder (line 62) | @Override
    method onCheckedChanged (line 69) | @Override
    method setSelectItemClickListener (line 80) | public void setSelectItemClickListener(SelectItemClickListener listene...
    class ViewHolder (line 84) | class ViewHolder extends AbstractSelectListAdapter.ViewHolder {
      method ViewHolder (line 85) | ViewHolder(View v) {
      method bind (line 96) | void bind(final int index) {
    method createButton (line 111) | @Override
    method onItemClick (line 125) | @Override
    method getSelectedItems (line 139) | @Override
    method clearAnswer (line 146) | @Override
    method getSelectedItem (line 158) | public Selection getSelectedItem() {
    method hasAnswerChanged (line 169) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/application/Collect.java
  class Collect (line 94) | public class Collect extends Application implements
    method getInstance (line 131) | @Deprecated
    method getExternalDataManager (line 136) | public ExternalDataManager getExternalDataManager() {
    method setExternalDataManager (line 140) | public void setExternalDataManager(ExternalDataManager externalDataMan...
    method onCreate (line 144) | @Override
    method setupDagger (line 163) | private void setupDagger() {
    method getAudioRecorderDependencyComponent (line 202) | @NotNull
    method getProjectsDependencyComponent (line 208) | @NotNull
    method onConfigurationChanged (line 214) | @Override
    method getComponent (line 222) | @Nullable
    method setComponent (line 227) | public void setComponent(AppDependencyComponent applicationComponent) {
    method getFormIdentifierHash (line 239) | public static String getFormIdentifierHash(String formId, String formV...
    method fixGoogleBug154855417 (line 249) | private void fixGoogleBug154855417() {
    method getLocale (line 266) | @NotNull
    method getState (line 276) | @NotNull
    method getGeoDependencyComponent (line 282) | @NonNull
    method getOsmDroidDependencyComponent (line 295) | @NonNull
    method getObjectProvider (line 307) | @NonNull
    method getEntitiesDependencyComponent (line 313) | @NonNull
    method getSelfieCameraDependencyComponent (line 325) | @NonNull
    method getGoogleMapsDependencyComponent (line 331) | @NonNull
    method getDrawDependencyComponent (line 343) | @NonNull
    method getLocationDependencyComponent (line 349) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AMRAppender.java
  class AMRAppender (line 8) | public class AMRAppender implements AudioFileAppender {
    method append (line 10) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AudioButton.java
  class AudioButton (line 28) | public class AudioButton extends MultiClickSafeMaterialButton implements...
    method AudioButton (line 34) | public AudioButton(Context context) {
    method AudioButton (line 39) | public AudioButton(Context context, AttributeSet attrs) {
    method isPlaying (line 44) | public Boolean isPlaying() {
    method setPlaying (line 48) | public void setPlaying(Boolean isPlaying) {
    method setListener (line 53) | public void setListener(Listener listener) {
    method onClick (line 57) | @Override
    method initView (line 66) | private void initView() {
    method render (line 71) | private void render() {
    type Listener (line 79) | public interface Listener {
      method onPlayClicked (line 81) | void onPlayClicked();
      method onStopClicked (line 83) | void onStopClicked();

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AudioControllerView.java
  class AudioControllerView (line 34) | public class AudioControllerView extends FrameLayout {
    method AudioControllerView (line 50) | public AudioControllerView(Context context) {
    method AudioControllerView (line 54) | public AudioControllerView(Context context, AttributeSet attrs) {
    method playClicked (line 74) | private void playClicked() {
    method onPositionChanged (line 86) | private void onPositionChanged(Integer newPosition) {
    method setPlaying (line 95) | public void setPlaying(Boolean playing) {
    method setListener (line 105) | public void setListener(Listener listener) {
    method setPosition (line 109) | public void setPosition(Integer position) {
    method setDuration (line 115) | public void setDuration(Integer duration) {
    method renderPosition (line 123) | private void renderPosition(Integer position) {
    type SwipableParent (line 131) | public interface SwipableParent {
      method allowSwiping (line 132) | void allowSwiping(boolean allowSwiping);
    type Listener (line 135) | public interface Listener {
      method onPlayClicked (line 137) | void onPlayClicked();
      method onPauseClicked (line 139) | void onPauseClicked();
      method onPositionChanged (line 141) | void onPositionChanged(Integer newPosition);
      method onRemoveClicked (line 143) | void onRemoveClicked();
    class SwipeListener (line 146) | private class SwipeListener implements SeekBar.OnSeekBarChangeListener {
      method onStartTrackingTouch (line 151) | @Override
      method onProgressChanged (line 162) | @Override
      method onStopTrackingTouch (line 169) | @Override
      method isSwiping (line 182) | Boolean isSwiping() {

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AudioFileAppender.java
  type AudioFileAppender (line 6) | public interface AudioFileAppender {
    method append (line 8) | void append(File one, File two) throws IOException;

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AudioRecordingControllerFragment.java
  class AudioRecordingControllerFragment (line 33) | public class AudioRecordingControllerFragment extends Fragment {
    method AudioRecordingControllerFragment (line 44) | public AudioRecordingControllerFragment(ViewModelProvider.Factory view...
    method onAttach (line 48) | @Override
    method onCreateView (line 58) | @Nullable
    method onViewCreated (line 66) | @Override
    method update (line 90) | private void update(boolean hasBackgroundRecording, boolean isBackgrou...
    method renderRecordingProblem (line 115) | private void renderRecordingProblem(String string) {
    method renderRecordingInProgress (line 123) | private void renderRecordingInProgress(RecordingSession session, boole...
    method renderControls (line 135) | private void renderControls(RecordingSession session) {

FILE: collect_app/src/main/java/org/odk/collect/android/audio/AudioRecordingErrorDialogFragment.java
  class AudioRecordingErrorDialogFragment (line 21) | public class AudioRecordingErrorDialogFragment extends DialogFragment {
    method onAttach (line 29) | @Override
    method onCreateDialog (line 36) | @NonNull
    method onDismiss (line 51) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/audio/BackgroundAudioHelpDialogFragment.java
  class BackgroundAudioHelpDialogFragment (line 16) | public class BackgroundAudioHelpDialogFragment extends DialogFragment {
    method onCreateDialog (line 18) | @NonNull

FILE: collect_app/src/main/java/org/odk/collect/android/audio/M4AAppender.java
  class M4AAppender (line 15) | public class M4AAppender implements AudioFileAppender {
    method append (line 17) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/audio/VolumeBar.java
  class VolumeBar (line 19) | public class VolumeBar extends LinearLayout {
    method VolumeBar (line 39) | public VolumeBar(@NonNull Context context) {
    method VolumeBar (line 44) | public VolumeBar(@NonNull Context context, @Nullable AttributeSet attr...
    method VolumeBar (line 49) | public VolumeBar(@NonNull Context context, @Nullable AttributeSet attr...
    method init (line 54) | private void init(Context context) {
    method onLayout (line 63) | @Override
    method addAmplitude (line 82) | public void addAmplitude(int amplitude) {
    method getLatestAmplitude (line 100) | @Nullable
    method getBestPipSize (line 105) | private int getBestPipSize(int availableWidth) {
    method createPipView (line 113) | @NotNull

FILE: collect_app/src/main/java/org/odk/collect/android/audio/Waveform.java
  class Waveform (line 19) | public class Waveform extends FrameLayout {
    method Waveform (line 28) | public Waveform(@NotNull Context context) {
    method Waveform (line 33) | public Waveform(@NotNull Context context, @NotNull AttributeSet attrs) {
    method Waveform (line 38) | public Waveform(@NotNull Context context, @NotNull AttributeSet attrs,...
    method init (line 43) | private void init(Context context, @Nullable AttributeSet attrs) {
    method onLayout (line 52) | @Override
    method addAmplitude (line 58) | public void addAmplitude(int amplitude) {
    method getLatestAmplitude (line 72) | @Nullable
    method clear (line 77) | public void clear() {

FILE: collect_app/src/main/java/org/odk/collect/android/backgroundwork/BackgroundWorkUtils.java
  class BackgroundWorkUtils (line 5) | public final class BackgroundWorkUtils {
    method BackgroundWorkUtils (line 12) | private BackgroundWorkUtils() {
    method getPeriodInMilliseconds (line 16) | public static long getPeriodInMilliseconds(String period, Context cont...

FILE: collect_app/src/main/java/org/odk/collect/android/backgroundwork/FormUpdateAndInstanceSubmitScheduler.java
  class FormUpdateAndInstanceSubmitScheduler (line 18) | public class FormUpdateAndInstanceSubmitScheduler implements FormUpdateS...
    method FormUpdateAndInstanceSubmitScheduler (line 24) | public FormUpdateAndInstanceSubmitScheduler(Scheduler scheduler, Setti...
    method scheduleUpdates (line 30) | @Override
    method scheduleAutoUpdate (line 52) | private void scheduleAutoUpdate(long periodInMilliseconds, String proj...
    method scheduleMatchExactly (line 58) | private void scheduleMatchExactly(long periodInMilliseconds, String pr...
    method cancelUpdates (line 64) | @Override
    method scheduleAutoSend (line 70) | @Override
    method scheduleFormAutoSend (line 90) | @Override
    method cancelSubmit (line 98) | @Override
    method getAutoSendTag (line 103) | @NotNull
    method getAutoSendFormTag (line 108) | public String getAutoSendFormTag(String projectId) {
    method getMatchExactlyTag (line 112) | @NotNull
    method getAutoUpdateTag (line 117) | @NotNull

FILE: collect_app/src/main/java/org/odk/collect/android/backgroundwork/FormUpdateScheduler.java
  type FormUpdateScheduler (line 3) | public interface FormUpdateScheduler {
    method scheduleUpdates (line 5) | void scheduleUpdates(String projectId);
    method cancelUpdates (line 7) | void cancelUpdates(String projectId);

FILE: collect_app/src/main/java/org/odk/collect/android/backgroundwork/InstanceSubmitScheduler.java
  type InstanceSubmitScheduler (line 3) | public interface InstanceSubmitScheduler {
    method scheduleAutoSend (line 5) | void scheduleAutoSend(String projectId);
    method scheduleFormAutoSend (line 7) | void scheduleFormAutoSend(String projectId);
    method cancelSubmit (line 9) | void cancelSubmit(String projectId);

FILE: collect_app/src/main/java/org/odk/collect/android/dao/CursorLoaderFactory.java
  class CursorLoaderFactory (line 13) | @Deprecated
    method CursorLoaderFactory (line 19) | public CursorLoaderFactory(ProjectsDataService projectsDataService) {
    method createSentInstancesCursorLoader (line 23) | public CursorLoader createSentInstancesCursorLoader(CharSequence charS...
    method createEditableInstancesCursorLoader (line 46) | public CursorLoader createEditableInstancesCursorLoader(CharSequence c...
    method createFinalizedInstancesCursorLoader (line 67) | public CursorLoader createFinalizedInstancesCursorLoader(CharSequence ...
    method createCompletedUndeletedInstancesCursorLoader (line 90) | public CursorLoader createCompletedUndeletedInstancesCursorLoader(Char...
    method getInstancesCursorLoader (line 121) | private CursorLoader getInstancesCursorLoader(String selection, String...
    method getUriWithAnalyticsParam (line 133) | private Uri getUriWithAnalyticsParam(Uri uri) {

FILE: collect_app/src/main/java/org/odk/collect/android/dao/helpers/InstancesDaoHelper.java
  class InstancesDaoHelper (line 30) | @Deprecated
    method InstancesDaoHelper (line 33) | private InstancesDaoHelper() {
    method isInstanceComplete (line 47) | public static boolean isInstanceComplete(FormController formController) {

FILE: collect_app/src/main/java/org/odk/collect/android/database/DatabaseConstants.java
  class DatabaseConstants (line 3) | public final class DatabaseConstants {
    method DatabaseConstants (line 20) | private DatabaseConstants() {

FILE: collect_app/src/main/java/org/odk/collect/android/database/forms/DatabaseFormsRepository.java
  class DatabaseFormsRepository (line 59) | public class DatabaseFormsRepository implements FormsRepository {
    method DatabaseFormsRepository (line 67) | public DatabaseFormsRepository(Context context, String dbPath, String ...
    method get (line 81) | @Nullable
    method getLatestByFormIdAndVersion (line 87) | @Nullable
    method getOneByPath (line 98) | @Nullable
    method getOneByMd5Hash (line 106) | @Nullable
    method getAll (line 118) | @Override
    method getAllByFormIdAndVersion (line 124) | @Override
    method getAllByFormId (line 133) | @Override
    method getAllNotDeletedByFormId (line 139) | @Override
    method getAllNotDeletedByFormIdAndVersion (line 146) | @Override
    method save (line 157) | @Override
    method delete (line 192) | @Override
    method softDelete (line 200) | @Override
    method deleteByMd5Hash (line 208) | @Override
    method deleteAll (line 216) | @Override
    method restore (line 221) | @Override
    method rawQuery (line 228) | public Cursor rawQuery(Map<String, String> projectionMap, String[] pro...
    method queryForForm (line 232) | @Nullable
    method queryForForms (line 239) | private List<Form> queryForForms(String selection, String[] selectionA...
    method queryAndReturnCursor (line 245) | private Cursor queryAndReturnCursor(Map<String, String> projectionMap,...
    method insertForm (line 288) | private Long insertForm(ContentValues values) {
    method updateForm (line 293) | private void updateForm(Long id, ContentValues values) {
    method deleteForms (line 298) | private void deleteForms(String selection, String[] selectionArgs) {
    method getFormsFromCursor (line 310) | @NotNull
    method deleteFilesForForm (line 337) | private void deleteFilesForForm(Form form) {

FILE: collect_app/src/main/java/org/odk/collect/android/database/forms/FormDatabaseMigrator.java
  class FormDatabaseMigrator (line 35) | public class FormDatabaseMigrator implements DatabaseMigrator {
    method onCreate (line 46) | public void onCreate(SQLiteDatabase db) {
    method onUpgrade (line 50) | @SuppressWarnings({"checkstyle:FallThrough"})
    method upgradeToVersion2 (line 85) | private void upgradeToVersion2(SQLiteDatabase db) {
    method upgradeToVersion4 (line 90) | private void upgradeToVersion4(SQLiteDatabase db, int oldVersion) {
    method upgradeToVersion5 (line 210) | private void upgradeToVersion5(SQLiteDatabase db) {
    method upgradeToVersion6 (line 215) | private void upgradeToVersion6(SQLiteDatabase db) {
    method upgradeToVersion7 (line 219) | private void upgradeToVersion7(SQLiteDatabase db) {
    method upgradeToVersion8 (line 227) | private void upgradeToVersion8(SQLiteDatabase db) {
    method upgradeToVersion9 (line 231) | private void upgradeToVersion9(SQLiteDatabase db) {
    method upgradeToVersion10 (line 242) | private void upgradeToVersion10(SQLiteDatabase db) {
    method upgradeToVersion11 (line 253) | private void upgradeToVersion11(SQLiteDatabase db) {
    method upgradeToVersion12 (line 264) | private void upgradeToVersion12(SQLiteDatabase db) {
    method upgradeToVersion13 (line 268) | private void upgradeToVersion13(SQLiteDatabase db) {
    method upgradeToVersion14 (line 279) | private void upgradeToVersion14(SQLiteDatabase db) {
    method createFormsTableV4 (line 283) | private void createFormsTableV4(SQLiteDatabase db, String tableName) {
    method createFormsTableV7 (line 304) | public void createFormsTableV7(SQLiteDatabase db) {
    method createFormsTableV8 (line 324) | public void createFormsTableV8(SQLiteDatabase database) {
    method createFormsTableV9 (line 345) | public void createFormsTableV9(SQLiteDatabase db) {
    method createFormsTableV10 (line 366) | public void createFormsTableV10(SQLiteDatabase db) {
    method createFormsTableV11 (line 387) | public void createFormsTableV11(SQLiteDatabase db) {
    method createFormsTableV12 (line 408) | public void createFormsTableV12(SQLiteDatabase db) {
    method createFormsTableV13 (line 430) | public void createFormsTableV13(SQLiteDatabase db) {
    method createFormsTableV14 (line 452) | private void createFormsTableV14(SQLiteDatabase db) {

FILE: collect_app/src/main/java/org/odk/collect/android/database/instances/DatabaseInstancesRepository.java
  class DatabaseInstancesRepository (line 46) | public final class DatabaseInstancesRepository implements InstancesRepos...
    method DatabaseInstancesRepository (line 52) | public DatabaseInstancesRepository(Context context, String dbPath, Str...
    method get (line 65) | @Override
    method getOneByPath (line 76) | @Override
    method getAll (line 90) | @Override
    method getAllNotDeleted (line 99) | @Override
    method getAllByStatus (line 108) | @Override
    method getCountByStatus (line 115) | @Override
    method getAllByFormId (line 123) | @Override
    method getAllNotDeletedByFormIdAndVersion (line 132) | @Override
    method delete (line 147) | @Override
    method deleteAll (line 164) | @Override
    method save (line 183) | @Override
    method deleteWithLogging (line 220) | @Override
    method rawQuery (line 232) | public Cursor rawQuery(String[] projection, String selection, String[]...
    method getCursorForAllByStatus (line 236) | private Cursor getCursorForAllByStatus(String[] status) {
    method query (line 245) | private Cursor query(String[] projection, String selection, String[] s...
    method insert (line 281) | private long insert(ContentValues values) throws IntegrityException {
    method update (line 293) | private void update(Long instanceId, ContentValues values) {
    method deleteInstanceFiles (line 302) | private void deleteInstanceFiles(Instance instance) {
    method getInstancesFromCursor (line 306) | private static List<Instance> getInstancesFromCursor(Cursor cursor, St...

FILE: collect_app/src/main/java/org/odk/collect/android/database/instances/InstanceDatabaseMigrator.java
  class InstanceDatabaseMigrator (line 35) | public class InstanceDatabaseMigrator implements DatabaseMigrator {
    method onCreate (line 43) | public void onCreate(SQLiteDatabase db) {
    method onUpgrade (line 47) | @SuppressWarnings({"checkstyle:FallThrough"})
    method upgradeToVersion2 (line 75) | private void upgradeToVersion2(SQLiteDatabase db) {
    method upgradeToVersion3 (line 87) | private void upgradeToVersion3(SQLiteDatabase db) {
    method upgradeToVersion4 (line 91) | private void upgradeToVersion4(SQLiteDatabase db) {
    method upgradeToVersion5 (line 101) | private void upgradeToVersion5(SQLiteDatabase db) {
    method dropObsoleteColumns (line 126) | private void dropObsoleteColumns(SQLiteDatabase db, String[] relevantC...
    method upgradeToVersion6 (line 136) | private void upgradeToVersion6(SQLiteDatabase db, String name) {
    method upgradeToVersion7 (line 141) | private void upgradeToVersion7(SQLiteDatabase db) {
    method upgradeToVersion8 (line 149) | private void upgradeToVersion8(SQLiteDatabase db) {
    method upgradeToVersion9 (line 154) | private void upgradeToVersion9(SQLiteDatabase db) {
    method upgradeToVersion10 (line 159) | private void upgradeToVersion10(SQLiteDatabase db) {
    method createInstancesTableV5 (line 167) | private void createInstancesTableV5(SQLiteDatabase db, String name) {
    method createInstancesTableV6 (line 181) | public void createInstancesTableV6(SQLiteDatabase db) {
    method createInstancesTableV7 (line 197) | public void createInstancesTableV7(SQLiteDatabase db) {
    method createInstancesTableV8 (line 213) | public void createInstancesTableV8(SQLiteDatabase db) {
    method createInstancesTableV9 (line 230) | public void createInstancesTableV9(SQLiteDatabase db) {
    method createInstancesTableV10 (line 251) | public void createInstancesTableV10(SQLiteDatabase db) {

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalAnswerResolver.java
  class ExternalAnswerResolver (line 46) | public class ExternalAnswerResolver extends DefaultAnswerResolver {
    method resolveAnswer (line 48) | @Override
    method createBugRuntimeException (line 171) | private RuntimeException createBugRuntimeException(TreeElement treeEle...
    method createCustomSelectChoices (line 177) | protected List<SelectChoice> createCustomSelectChoices(String complete...

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalAppsUtils.java
  class ExternalAppsUtils (line 55) | public final class ExternalAppsUtils {
    method ExternalAppsUtils (line 60) | private ExternalAppsUtils() {
    method extractIntentName (line 63) | public static String extractIntentName(String exString) {
    method extractParameters (line 73) | public static Map<String, String> extractParameters(String exString) {
    method getParamPairs (line 96) | private static List<String> getParamPairs(String paramsStr) {
    method populateParameters (line 116) | public static void populateParameters(Intent intent, Map<String, Strin...
    method getValueRepresentedBy (line 135) | public static Object getValueRepresentedBy(String text, TreeReference ...
    method asStringData (line 167) | public static StringData asStringData(Object value) {
    method asIntegerData (line 171) | public static IntegerData asIntegerData(Object value) {
    method asDecimalData (line 185) | public static DecimalData asDecimalData(Object value) {

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataHandler.java
  type ExternalDataHandler (line 28) | public interface ExternalDataHandler extends IFunctionHandler {
    method setExternalDataManager (line 30) | void setExternalDataManager(ExternalDataManager externalDataManager);

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataManager.java
  type ExternalDataManager (line 28) | public interface ExternalDataManager {
    method getDatabase (line 40) | ExternalSQLiteOpenHelper getDatabase(String dataSetName, boolean requi...
    method close (line 42) | void close();

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataManagerImpl.java
  class ExternalDataManagerImpl (line 37) | public class ExternalDataManagerImpl implements ExternalDataManager {
    method ExternalDataManagerImpl (line 43) | public ExternalDataManagerImpl(File mediaFolder) {
    method getDatabase (line 47) | @Override
    method close (line 67) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataReader.java
  type ExternalDataReader (line 29) | public interface ExternalDataReader {
    method doImport (line 31) | void doImport(Map<String, File> externalDataMap);

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataReaderImpl.java
  class ExternalDataReaderImpl (line 40) | public class ExternalDataReaderImpl implements ExternalDataReader {
    method ExternalDataReaderImpl (line 45) | public ExternalDataReaderImpl(Supplier<Boolean> isCancelled, Consumer<...
    method doImport (line 50) | @Override
    method doImportDataSetAndContinue (line 64) | private boolean doImportDataSetAndContinue(String dataSetName, File da...

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalDataUtil.java
  class ExternalDataUtil (line 60) | public final class ExternalDataUtil {
    method ExternalDataUtil (line 73) | private ExternalDataUtil() {
    method toSafeColumnName (line 77) | public static String toSafeColumnName(String columnName, Map<String, S...
    method toSafeColumnName (line 88) | public static String toSafeColumnName(String columnName) {
    method findMatchingColumnsAfterSafeningNames (line 95) | public static List<String> findMatchingColumnsAfterSafeningNames(Strin...
    method getSearchXPathExpression (line 111) | public static XPathFuncExpr getSearchXPathExpression(String appearance) {
    method populateExternalChoices (line 166) | public static ArrayList<SelectChoice> populateExternalChoices(FormEntr...
    method createMapWithDisplayingColumns (line 239) | public static LinkedHashMap<String, String> createMapWithDisplayingCol...
    method createListOfColumns (line 261) | public static List<String> createListOfColumns(String columnString) {
    method splitTrimmed (line 274) | private static List<String> splitTrimmed(String displayColumns, String...
    method splitTrimmed (line 285) | private static List<String> splitTrimmed(String text, String separator) {
    method containsAnyData (line 297) | public static boolean containsAnyData(String[] row) {
    method fillUpNullValues (line 309) | public static String[] fillUpNullValues(String[] row, String[] headerR...
    method nullSafe (line 327) | public static String nullSafe(String value) {
    method isAnInteger (line 331) | public static boolean isAnInteger(String value) {
    method containsConfigurationChoice (line 351) | private static boolean containsConfigurationChoice(List<SelectChoice> ...
    method getFilePath (line 360) | private static String getFilePath(XPathFuncExpr xpathfuncexpr, FormCon...

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalSQLiteOpenHelper.java
  class ExternalSQLiteOpenHelper (line 59) | public class ExternalSQLiteOpenHelper extends SQLiteOpenHelper {
    method ExternalSQLiteOpenHelper (line 71) | ExternalSQLiteOpenHelper(File dbFile) {
    method importFromCSV (line 75) | void importFromCSV(File dataSetFile, ExternalDataReader externalDataRe...
    method onCreate (line 92) | @Override
    method onCreateNamed (line 114) | private void onCreateNamed(SQLiteDatabase db, String tableName) throws...
    method isCancelled (line 279) | protected boolean isCancelled() {
    method createAndPopulateMetadataTable (line 285) | static void createAndPopulateMetadataTable(SQLiteDatabase db, String m...
    method getLastMd5Hash (line 301) | static String getLastMd5Hash(SQLiteDatabase db, String metadataTableNa...
    method shouldUpdateDBforDataSet (line 319) | static boolean shouldUpdateDBforDataSet(File dbFile, File dataSetFile) {
    method shouldUpdateDBforDataSet (line 324) | static boolean shouldUpdateDBforDataSet(SQLiteDatabase db, String data...
    method onUpgrade (line 337) | @Override
    method onProgress (line 341) | private void onProgress(String message) {
    method removeByteOrderMark (line 351) | private String removeByteOrderMark(String bomCheckString) {

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/ExternalSelectChoice.java
  class ExternalSelectChoice (line 28) | public class ExternalSelectChoice extends SelectChoice {
    method ExternalSelectChoice (line 32) | public ExternalSelectChoice(String labelOrID, String value, boolean is...
    method getImage (line 36) | public String getImage() {
    method setImage (line 40) | public void setImage(String image) {

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/handler/ExternalDataHandlerBase.java
  class ExternalDataHandlerBase (line 31) | public abstract class ExternalDataHandlerBase implements ExternalDataHan...
    method getExternalDataManager (line 35) | public ExternalDataManager getExternalDataManager() {
    method setExternalDataManager (line 39) | public void setExternalDataManager(ExternalDataManager externalDataMan...
    method ExternalDataHandlerBase (line 43) | protected ExternalDataHandlerBase(ExternalDataManager externalDataMana...
    method normalize (line 53) | protected String normalize(String dataSetName) {

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/handler/ExternalDataHandlerPull.java
  class ExternalDataHandlerPull (line 42) | public class ExternalDataHandlerPull extends ExternalDataHandlerBase {
    method ExternalDataHandlerPull (line 46) | public ExternalDataHandlerPull(ExternalDataManager externalDataManager) {
    method getName (line 50) | @Override
    method getPrototypes (line 55) | @Override
    method rawArgs (line 60) | @Override
    method realTime (line 65) | @Override
    method eval (line 70) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/handler/ExternalDataHandlerSearch.java
  class ExternalDataHandlerSearch (line 51) | public class ExternalDataHandlerSearch extends ExternalDataHandlerBase {
    method ExternalDataHandlerSearch (line 59) | public ExternalDataHandlerSearch(ExternalDataManager externalDataManag...
    method getDisplayColumns (line 67) | public String getDisplayColumns() {
    method getValueColumn (line 71) | public String getValueColumn() {
    method getImageColumn (line 75) | public String getImageColumn() {
    method getName (line 79) | @Override
    method getPrototypes (line 84) | @Override
    method rawArgs (line 89) | @Override
    method realTime (line 94) | @Override
    method eval (line 99) | @Override
    method createDynamicSelectChoices (line 200) | protected ArrayList<SelectChoice> createDynamicSelectChoices(Cursor c,
    method createLikeExpression (line 245) | protected String createLikeExpression(List<String> queriedColumns) {
    method buildLabel (line 263) | protected String buildLabel(Cursor c, LinkedHashMap<String, String> se...

FILE: collect_app/src/main/java/org/odk/collect/android/dynamicpreload/handler/ExternalDataSearchType.java
  type ExternalDataSearchType (line 26) | enum ExternalDataSearchType {
    method getSingleLikeArgument (line 29) | @Override
    method getSingleLikeArgument (line 36) | @Override
    method getSingleLikeArgument (line 43) | @Override
    method getSingleLikeArgument (line 50) | @Override
    method ExternalDataSearchType (line 58) | ExternalDataSearchType(String keyword) {
    method getKeyword (line 62) | public String getKeyword() {
    method getByKeyword (line 66) | public static ExternalDataSearchType getByKeyword(String keyword,
    method constructLikeArguments (line 80) | public String[] constructLikeArguments(String queriedValue, int times) {
    method getSingleLikeArgument (line 88) | protected abstract String getSingleLikeArgument(String queriedValue);

FILE: collect_app/src/main/java/org/odk/collect/android/exception/EncryptionException.java
  class EncryptionException (line 26) | public class EncryptionException extends Exception {
    method EncryptionException (line 28) | public EncryptionException(String detailMessage, Throwable throwable) {

FILE: collect_app/src/main/java/org/odk/collect/android/exception/ExternalDataException.java
  class ExternalDataException (line 26) | public class ExternalDataException extends RuntimeException {
    method ExternalDataException (line 28) | public ExternalDataException(String detailMessage) {
    method ExternalDataException (line 32) | public ExternalDataException(String detailMessage, Throwable throwable) {

FILE: collect_app/src/main/java/org/odk/collect/android/exception/ExternalParamsException.java
  class ExternalParamsException (line 26) | public class ExternalParamsException extends Exception {
    method ExternalParamsException (line 28) | public ExternalParamsException(String detailMessage, Throwable throwab...

FILE: collect_app/src/main/java/org/odk/collect/android/exception/JavaRosaException.java
  class JavaRosaException (line 28) | public class JavaRosaException extends Exception {
    method JavaRosaException (line 30) | public JavaRosaException(Throwable throwable) {

FILE: collect_app/src/main/java/org/odk/collect/android/external/FormsContract.java
  class FormsContract (line 30) | public final class FormsContract {
    method getUri (line 39) | public static Uri getUri(String projectId, Long formDbId) {
    method getUri (line 43) | public static Uri getUri(String projectId) {
    method getContentNewestFormsByFormIdUri (line 55) | @Deprecated
    method FormsContract (line 60) | private FormsContract() {

FILE: collect_app/src/main/java/org/odk/collect/android/external/FormsProvider.java
  class FormsProvider (line 67) | public class FormsProvider extends ContentProvider {
    method deferDaggerInit (line 95) | private void deferDaggerInit() {
    method onCreate (line 99) | @Override
    method query (line 104) | @Override
    method getType (line 170) | @Override
    method insert (line 185) | @Override
    method delete (line 195) | @Override
    method update (line 231) | @Override
    method getFormsRepository (line 236) | @NotNull
    method getProjectId (line 241) | private String getProjectId(@NonNull Uri uri) {
    method databaseQuery (line 251) | private Cursor databaseQuery(String projectId, String[] projection, St...
    method logServerEvent (line 255) | private void logServerEvent(String projectId, String event) {

FILE: collect_app/src/main/java/org/odk/collect/android/external/InstanceProvider.java
  class InstanceProvider (line 48) | public class InstanceProvider extends ContentProvider {
    method onCreate (line 69) | @Override
    method query (line 74) | @Override
    method dbQuery (line 106) | private Cursor dbQuery(String projectId, String[] projection, String s...
    method getType (line 110) | @Override
    method insert (line 124) | @Override
    method delete (line 149) | @Override
    method update (line 199) | @Override
    method getProjectId (line 204) | private String getProjectId(@NonNull Uri uri) {
    method logServerEvent (line 214) | private void logServerEvent(String projectId, String event) {

FILE: collect_app/src/main/java/org/odk/collect/android/external/InstancesContract.java
  class InstancesContract (line 21) | public final class InstancesContract {
    method getUri (line 27) | public static Uri getUri(String projectId) {
    method getUri (line 31) | public static Uri getUri(String projectId, Long instanceDbId) {
    method InstancesContract (line 36) | private InstancesContract() {

FILE: collect_app/src/main/java/org/odk/collect/android/fastexternalitemset/ItemsetDao.java
  class ItemsetDao (line 39) | public class ItemsetDao {
    method ItemsetDao (line 44) | public ItemsetDao(ItemsetDbAdapter adapter) {
    method getItemLabel (line 48) | public String getItemLabel(String itemName, String mediaFolderPath, St...
    method getItems (line 88) | public List<SelectChoice> getItems(FormEntryPrompt formEntryPrompt, XP...
    method getNodesetString (line 98) | private String getNodesetString(FormEntryPrompt formEntryPrompt) {
    method getQueryString (line 105) | private String getQueryString(String nodesetStr) {
    method getSelectionStringAndPopulateArguments (line 110) | private String getSelectionStringAndPopulateArguments(String queryStri...
    method getSelectionArgs (line 175) | @SuppressWarnings("PMD.AvoidThrowingNewInstanceOfSameException")
    method getItemsFromDatabase (line 220) | private List<SelectChoice> getItemsFromDatabase(String selection, Stri...
    method getItemsetFile (line 275) | public File getItemsetFile(String mediaFolderPath) {

FILE: collect_app/src/main/java/org/odk/collect/android/fastexternalitemset/ItemsetDbAdapter.java
  class ItemsetDbAdapter (line 24) | public class ItemsetDbAdapter implements Closeable {
    class DatabaseHelper (line 46) | private static class DatabaseHelper extends SQLiteOpenHelper {
      method DatabaseHelper (line 47) | DatabaseHelper() {
      method onCreate (line 51) | @Override
      method onUpgrade (line 58) | @Override
    method open (line 87) | public ItemsetDbAdapter open() throws SQLException {
    method close (line 93) | @Override
    method createTable (line 98) | public boolean createTable(String formHash, String pathHash, String[] ...
    method addRow (line 133) | public boolean addRow(String tableName, String[] columns, String[] new...
    method beginTransaction (line 147) | public void beginTransaction() {
    method commit (line 151) | public void commit() {
    method query (line 155) | public Cursor query(String hash, String selection, String[] selectionA...
    method dropTable (line 160) | public void dropTable(String pathHash, String path) {
    method getItemsets (line 172) | public Cursor getItemsets(String path) {
    method getItemsets (line 180) | public Cursor getItemsets() {
    method update (line 184) | public void update(ContentValues values, String where, String[] whereA...
    method delete (line 188) | public void delete(String path) {
    method getMd5FromString (line 207) | public static String getMd5FromString(String toEncode) {

FILE: collect_app/src/main/java/org/odk/collect/android/fastexternalitemset/XPathParseTool.java
  class XPathParseTool (line 11) | public class XPathParseTool {
    method parseXPath (line 12) | public XPathExpression parseXPath(String xpath) throws XPathSyntaxExce...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/BackgroundAudioPermissionDialogFragment.java
  class BackgroundAudioPermissionDialogFragment (line 24) | public class BackgroundAudioPermissionDialogFragment extends DialogFragm...
    method BackgroundAudioPermissionDialogFragment (line 33) | public BackgroundAudioPermissionDialogFragment(ViewModelProvider.Facto...
    method onAttach (line 37) | @Override
    method onCreateDialog (line 44) | @NonNull
    method onOKClicked (line 58) | private void onOKClicked(FragmentActivity activity) {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/BackgroundAudioViewModel.java
  class BackgroundAudioViewModel (line 31) | public class BackgroundAudioViewModel extends ViewModel {
    method BackgroundAudioViewModel (line 50) | public BackgroundAudioViewModel(AudioRecorder audioRecorder, Settings ...
    method onCleared (line 66) | @Override
    method isPermissionRequired (line 72) | public LiveData<Boolean> isPermissionRequired() {
    method isBackgroundRecordingEnabled (line 76) | public NonNullLiveData<Boolean> isBackgroundRecordingEnabled() {
    method setBackgroundRecordingEnabled (line 80) | public void setBackgroundRecordingEnabled(boolean enabled) {
    method isBackgroundRecording (line 97) | public boolean isBackgroundRecording() {
    method grantAudioPermission (line 101) | public void grantAudioPermission() {
    method handleRecordAction (line 113) | private void handleRecordAction(TreeReference treeReference, String qu...
    method startBackgroundRecording (line 137) | private void startBackgroundRecording(String quality, HashSet<TreeRefe...
    type RecordAudioActionRegistry (line 148) | public interface RecordAudioActionRegistry {
      method register (line 150) | void register(BiConsumer<TreeReference, String> listener);
      method unregister (line 152) | void unregister();

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/FormEntryViewModel.java
  class FormEntryViewModel (line 57) | public class FormEntryViewModel extends ViewModel implements SelectChoic...
    method FormEntryViewModel (line 85) | @SuppressWarnings("WeakerAccess")
    method getSessionId (line 104) | public String getSessionId() {
    method getFormController (line 111) | @Deprecated
    method getCurrentIndex (line 116) | public LiveData<CurrentFormIndex> getCurrentIndex() {
    method getError (line 120) | public LiveData<FormError> getError() {
    method isLoading (line 124) | public NonNullLiveData<Boolean> isLoading() {
    method promptForNewRepeat (line 128) | @SuppressWarnings("WeakerAccess")
    method jumpToNewRepeat (line 139) | public void jumpToNewRepeat() {
    method addRepeat (line 143) | public void addRepeat() {
    method cancelRepeatPrompt (line 167) | public void cancelRepeatPrompt() {
    method errorDisplayed (line 189) | public void errorDisplayed() {
    method canAddRepeat (line 193) | public boolean canAddRepeat() {
    method moveForward (line 203) | public void moveForward(HashMap<FormIndex, IAnswerData> answers) {
    method moveForward (line 207) | public void moveForward(HashMap<FormIndex, IAnswerData> answers, Boole...
    method moveBackward (line 226) | public void moveBackward(HashMap<FormIndex, IAnswerData> answers) {
    method updateAnswersForScreen (line 245) | public boolean updateAnswersForScreen(HashMap<FormIndex, IAnswerData> ...
    method saveScreenAnswersToFormController (line 252) | public boolean saveScreenAnswersToFormController(HashMap<FormIndex, IA...
    method openHierarchy (line 271) | public void openHierarchy() {
    method hasBackgroundRecording (line 275) | public NonNullLiveData<Boolean> hasBackgroundRecording() {
    method getQuestionPrompt (line 279) | public FormEntryPrompt getQuestionPrompt(FormIndex formIndex) {
    method answerQuestion (line 283) | public void answerQuestion(FormIndex index, IAnswerData answer) {
    method loadSelectChoices (line 306) | @NonNull
    method onCleared (line 319) | @Override
    method refreshSync (line 327) | @Deprecated
    method refresh (line 332) | public void refresh() {
    method updateIndex (line 339) | private void updateIndex(boolean isAsync, @Nullable ValidationResult v...
    method updateIndex (line 343) | private void updateIndex(boolean isAsync, @Nullable ValidationResult v...
    method exit (line 380) | public void exit() {
    method validateForm (line 386) | public void validateForm() {
    method preloadSelectChoices (line 402) | private void preloadSelectChoices() throws RepeatsInFieldListException...
    method changeLanguage (line 418) | public void changeLanguage(String newLanguage) {
    method isFormEditableAfterFinalization (line 429) | public boolean isFormEditableAfterFinalization() {
    method shouldShowNewEditMessage (line 438) | public boolean shouldShowNewEditMessage() {
    method saveFieldList (line 449) | public FormEntryPrompt[] saveFieldList(HashMap<FormIndex, IAnswerData>...
    method isQuestionRecalculated (line 473) | private boolean isQuestionRecalculated(FormEntryPrompt mutableQuestion...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/FormLoadingDialogFragment.java
  class FormLoadingDialogFragment (line 24) | public class FormLoadingDialogFragment extends MaterialProgressDialogFra...
    type FormLoadingDialogFragmentListener (line 26) | public interface FormLoadingDialogFragmentListener {
      method onCancelFormLoading (line 27) | void onCancelFormLoading();
    method onAttach (line 38) | @Override
    method getCancelButtonText (line 51) | @Override
    method getOnCancelCallback (line 56) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java
  class ODKView (line 115) | @SuppressLint("ViewConstructor")
    method ODKView (line 152) | public ODKView(
    method setupAudioErrors (line 219) | private void setupAudioErrors() {
    method autoplayIfNeeded (line 232) | private void autoplayIfNeeded(boolean advancingPage) {
    method autoplayAudio (line 246) | private Boolean autoplayAudio(FormEntryPrompt firstPrompt) {
    method autoplayVideo (line 255) | private void autoplayVideo(FormEntryPrompt prompt) {
    method configureIntentGroup (line 273) | private void configureIntentGroup(ComponentActivity context, FormEntry...
    method addWidgetForQuestion (line 300) | private void addWidgetForQuestion(FormEntryPrompt question) {
    method addWidgetForQuestion (line 317) | private void addWidgetForQuestion(FormEntryPrompt question, int index) {
    method isInIntentGroup (line 361) | private boolean isInIntentGroup(FormEntryPrompt question) {
    method configureWidgetForQuestion (line 376) | private QuestionWidget configureWidgetForQuestion(FormEntryPrompt ques...
    method getDividerView (line 390) | private View getDividerView() {
    method getAnswers (line 409) | public HashMap<FormIndex, IAnswerData> getAnswers() {
    method setGroupText (line 426) | private void setGroupText(FormEntryCaption[] groups) {
    method getGroupsPath (line 443) | @NonNull
    method getGroupsPath (line 455) | @NonNull
    method addIntentLaunchButton (line 485) | private void addIntentLaunchButton(Context context, FormEntryPrompt[] ...
    method setFocus (line 556) | public void setFocus(Context context) {
    method isDisplayed (line 565) | public boolean isDisplayed(QuestionWidget qw) {
    method focusToTopOf (line 571) | public void focusToTopOf(FormIndex index) {
    method focusToTopOf (line 580) | public void focusToTopOf(@Nullable QuestionWidget qw) {
    method setDataForFields (line 590) | public void setDataForFields(Bundle bundle) throws JavaRosaException {
    method shouldSuppressFlingGesture (line 651) | @Override
    method verticalScrollView (line 661) | @Nullable
    method clearAnswer (line 670) | public boolean clearAnswer() {
    method getWidgets (line 681) | public ArrayList<QuestionWidget> getWidgets() {
    method setOnFocusChangeListener (line 685) | @Override
    method onLongClick (line 693) | @Override
    method cancelLongPress (line 698) | @Override
    method setErrorForQuestionWithIndex (line 706) | public void setErrorForQuestionWithIndex(FormIndex formIndex, String e...
    method removeWidgetAt (line 720) | private void removeWidgetAt(int index) {
    method setWidgetValueChangedListener (line 753) | public void setWidgetValueChangedListener(WidgetValueChangedListener l...
    method widgetValueChanged (line 757) | public void widgetValueChanged(QuestionWidget changedWidget) {
    method onUpdated (line 763) | public void onUpdated(FormIndex lastChangedIndex, FormEntryPrompt[] qu...
    method updateQuestions (line 807) | private void updateQuestions(FormEntryPrompt[] prompts) {
    method isNavigationBlocked (line 814) | @Nullable

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/RecordingHandler.java
  class RecordingHandler (line 21) | public class RecordingHandler {
    method RecordingHandler (line 29) | public RecordingHandler(QuestionMediaManager questionMediaManager, Lif...
    method handle (line 37) | public void handle(FormController formController, RecordingSession ses...
    method handleBackgroundRecording (line 55) | private void handleBackgroundRecording(FormController formController, ...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/RecordingWarningDialogFragment.java
  class RecordingWarningDialogFragment (line 12) | public class RecordingWarningDialogFragment extends DialogFragment {
    method onCreateDialog (line 14) | @NonNull

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/RefreshFormListDialogFragment.java
  class RefreshFormListDialogFragment (line 9) | public class RefreshFormListDialogFragment extends MaterialProgressDialo...
    method onAttach (line 13) | @Override
    method getCancelButtonText (line 25) | @Override
    method getOnCancelCallback (line 30) | @Override
    type RefreshFormListDialogFragmentListener (line 39) | public interface RefreshFormListDialogFragmentListener {
      method onCancelFormLoading (line 40) | void onCancelFormLoading();

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AsyncTaskAuditEventWriter.java
  class AsyncTaskAuditEventWriter (line 10) | public class AsyncTaskAuditEventWriter implements AuditEventLogger.Audit...
    method AsyncTaskAuditEventWriter (line 19) | public AsyncTaskAuditEventWriter(@NonNull File file, boolean isLocatio...
    method writeEvents (line 27) | @Override
    method isWriting (line 33) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AuditConfig.java
  class AuditConfig (line 30) | public class AuditConfig {
    method AuditConfig (line 57) | public AuditConfig(String mode, String locationMinInterval, String loc...
    method getMode (line 66) | private LocationClient.Priority getMode(@NonNull String mode) {
    method getLocationPriority (line 81) | @Nullable
    method getLocationMinInterval (line 86) | @Nullable
    method getLocationMaxAge (line 95) | @Nullable
    method isLocationEnabled (line 100) | public boolean isLocationEnabled() {
    method isTrackingChangesEnabled (line 104) | public boolean isTrackingChangesEnabled() {
    method isIdentifyUserEnabled (line 108) | public boolean isIdentifyUserEnabled() {
    method isTrackChangesReasonEnabled (line 112) | public boolean isTrackChangesReasonEnabled() {
    class Builder (line 116) | public static class Builder {
      method setMode (line 124) | public Builder setMode(String mode) {
      method setLocationMinInterval (line 129) | public Builder setLocationMinInterval(String locationMinInterval) {
      method setLocationMaxAge (line 134) | public Builder setLocationMaxAge(String locationMaxAge) {
      method setIsTrackingChangesEnabled (line 139) | public Builder setIsTrackingChangesEnabled(boolean isTrackingChanges...
      method setIsIdentifyUserEnabled (line 144) | public Builder setIsIdentifyUserEnabled(boolean isIdentifyUserEnable...
      method setIsTrackChangesReasonEnabled (line 149) | public Builder setIsTrackChangesReasonEnabled(boolean isTrackChanges...
      method createAuditConfig (line 154) | public AuditConfig createAuditConfig() {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AuditEvent.java
  class AuditEvent (line 24) | public class AuditEvent {
    type AuditEventType (line 26) | public enum AuditEventType {
      method AuditEventType (line 88) | AuditEventType(String value, boolean isLogged, boolean isInterval, b...
      method AuditEventType (line 96) | AuditEventType(String value, boolean isInterval) {
      method AuditEventType (line 100) | AuditEventType(String value) {
      method getValue (line 104) | public String getValue() {
      method isLogged (line 108) | public boolean isLogged() {
      method isInterval (line 115) | public boolean isInterval() {
      method isLocationRelated (line 119) | public boolean isLocationRelated() {
    method AuditEvent (line 142) | public AuditEvent(long start, AuditEventType auditEventType) {
    method AuditEvent (line 146) | public AuditEvent(long start, AuditEventType auditEventType,
    method isIntervalAuditEventType (line 159) | public boolean isIntervalAuditEventType() {
    method setEnd (line 166) | public void setEnd(long endTime) {
    method isEndTimeSet (line 171) | public boolean isEndTimeSet() {
    method getAuditEventType (line 175) | public AuditEventType getAuditEventType() {
    method getFormIndex (line 179) | public FormIndex getFormIndex() {
    method hasNewAnswer (line 183) | public boolean hasNewAnswer() {
    method isLocationAlreadySet (line 187) | public boolean isLocationAlreadySet() {
    method setLocationCoordinates (line 193) | public void setLocationCoordinates(String latitude, String longitude, ...
    method setUser (line 199) | public void setUser(String user) {
    method recordValueChange (line 203) | public boolean recordValueChange(String newValue) {
    method getChangeReason (line 216) | public String getChangeReason() {
    method getLatitude (line 220) | public String getLatitude() {
    method getLongitude (line 224) | public String getLongitude() {
    method getAccuracy (line 228) | public String getAccuracy() {
    method getUser (line 232) | public String getUser() {
    method getStart (line 236) | public long getStart() {
    method getOldValue (line 240) | @NonNull
    method getNewValue (line 245) | @NonNull
    method getEnd (line 250) | public long getEnd() {
    method getAuditEventTypeFromFecType (line 255) | public static AuditEventType getAuditEventTypeFromFecType(int fcEvent) {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AuditEventCSVLine.java
  class AuditEventCSVLine (line 14) | public final class AuditEventCSVLine {
    method AuditEventCSVLine (line 16) | private AuditEventCSVLine() {
    method toCSVLine (line 20) | public static String toCSVLine(AuditEvent auditEvent, boolean isTracki...
    method getXPathPath (line 72) | private static String getXPathPath(FormIndex formIndex) {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AuditEventLogger.java
  class AuditEventLogger (line 31) | public class AuditEventLogger {
    method AuditEventLogger (line 44) | public AuditEventLogger(AuditConfig auditConfig, AuditEventWriter writ...
    method logEvent (line 50) | public void logEvent(AuditEvent.AuditEventType eventType, boolean writ...
    method logEvent (line 58) | public void logEvent(AuditEvent.AuditEventType eventType, FormIndex fo...
    method internalLog (line 63) | private synchronized void internalLog(AuditEvent.AuditEventType eventT...
    method flush (line 108) | public synchronized void flush() {
    method addLocationCoordinatesToAuditEvent (line 115) | private void addLocationCoordinatesToAuditEvent(AuditEvent auditEvent,...
    method addNewValueToQuestionAuditEvent (line 123) | private void addNewValueToQuestionAuditEvent(AuditEvent aev, FormContr...
    method isDuplicateOfLastLocationEvent (line 130) | boolean isDuplicateOfLastLocationEvent(AuditEvent.AuditEventType event...
    method isDuplicatedIntervalEvent (line 140) | private boolean isDuplicatedIntervalEvent(AuditEvent newAuditEvent) {
    method finalizeEvents (line 154) | private void finalizeEvents() {
    method setIntervalEventFinalParameters (line 171) | private void setIntervalEventFinalParameters(AuditEvent aev, long end,...
    method shouldBeIgnored (line 194) | private boolean shouldBeIgnored(AuditEvent.AuditEventType eventType) {
    method shouldEventBeLogged (line 204) | private boolean shouldEventBeLogged(AuditEvent aev) {
    method writeEvents (line 212) | private void writeEvents() {
    method getEventTime (line 224) | private long getEventTime() {
    method addLocation (line 232) | public void addLocation(Location location) {
    method getMostAccurateLocation (line 236) | @Nullable
    method removeExpiredLocations (line 251) | private void removeExpiredLocations(long currentTime) {
    method isAuditEnabled (line 267) | boolean isAuditEnabled() {
    method getLocations (line 271) | List<Location> getLocations() {
    method isUserRequired (line 275) | public boolean isUserRequired() {
    method setUser (line 279) | public void setUser(String user) {
    method getUser (line 283) | public String getUser() {
    method isChangeReasonRequired (line 287) | public boolean isChangeReasonRequired() {
    type AuditEventWriter (line 291) | public interface AuditEventWriter {
      method writeEvents (line 293) | void writeEvents(List<AuditEvent> auditEvents);
      method isWriting (line 295) | boolean isWriting();

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/AuditEventSaveTask.java
  class AuditEventSaveTask (line 21) | public class AuditEventSaveTask extends AsyncTask<AuditEvent, Void, Void> {
    method AuditEventSaveTask (line 35) | public AuditEventSaveTask(@NonNull File file, boolean isLocationEnable...
    method doInBackground (line 43) | @Override
    method updateHeaderIfNeeded (line 76) | private boolean updateHeaderIfNeeded() {
    method shouldHeaderBeUpdated (line 110) | private boolean shouldHeaderBeUpdated(String header) {
    method getHeader (line 117) | private String getHeader() {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/ChangesReasonPromptDialogFragment.java
  class ChangesReasonPromptDialogFragment (line 21) | public class ChangesReasonPromptDialogFragment extends MaterialFullScree...
    method onCreateView (line 25) | @Nullable
    method onViewCreated (line 31) | @Override
    method onAttach (line 68) | @Override
    method onBackPressed (line 74) | @Override
    method getToolbar (line 79) | @Override
    method onCloseClicked (line 84) | @Override
    method shouldShowSoftKeyboard (line 89) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/IdentifyUserPromptDialogFragment.java
  class IdentifyUserPromptDialogFragment (line 19) | public class IdentifyUserPromptDialogFragment extends MaterialFullScreen...
    method onCreateView (line 23) | @Override
    method onViewCreated (line 28) | @Override
    method onAttach (line 65) | @Override
    method onCloseClicked (line 77) | @Override
    method onBackPressed (line 83) | @Override
    method getToolbar (line 89) | @Override
    method shouldShowSoftKeyboard (line 94) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/audit/IdentityPromptViewModel.java
  class IdentityPromptViewModel (line 13) | public class IdentityPromptViewModel extends ViewModel {
    method IdentityPromptViewModel (line 24) | public IdentityPromptViewModel() {
    method formLoaded (line 28) | public void formLoaded(@NonNull FormController formController) {
    method requiresIdentityToContinue (line 34) | public LiveData<Boolean> requiresIdentityToContinue() {
    method isFormEntryCancelled (line 38) | public LiveData<Boolean> isFormEntryCancelled() {
    method getUser (line 42) | public String getUser() {
    method setIdentity (line 46) | public void setIdentity(String identity) {
    method done (line 50) | public void done() {
    method promptDismissed (line 58) | public void promptDismissed() {
    method updateRequiresIdentity (line 62) | private void updateRequiresIdentity() {
    method userIsValid (line 68) | private static boolean userIsValid(String user) {
    method getFormTitle (line 72) | public String getFormTitle() {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/backgroundlocation/BackgroundLocationHelper.java
  class BackgroundLocationHelper (line 30) | public class BackgroundLocationHelper {
    method BackgroundLocationHelper (line 37) | public BackgroundLocationHelper(
    method isAndroidLocationPermissionGranted (line 49) | boolean isAndroidLocationPermissionGranted() {
    method isBackgroundLocationPreferenceEnabled (line 53) | boolean isBackgroundLocationPreferenceEnabled() {
    method arePlayServicesAvailable (line 57) | boolean arePlayServicesAvailable() {
    method isCurrentFormSet (line 64) | boolean isCurrentFormSet() {
    method currentFormCollectsBackgroundLocation (line 73) | boolean currentFormCollectsBackgroundLocation() {
    method currentFormAuditsLocation (line 83) | boolean currentFormAuditsLocation() {
    method getCurrentFormAuditConfig (line 92) | AuditConfig getCurrentFormAuditConfig() {
    method logAuditEvent (line 101) | void logAuditEvent(AuditEvent.AuditEventType eventType) {
    method provideLocationToAuditLogger (line 110) | void provideLocationToAuditLogger(Location location) {
    method getFormController (line 114) | @Nullable

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/backgroundlocation/BackgroundLocationManager.java
  class BackgroundLocationManager (line 27) | public class BackgroundLocationManager implements LocationClient.Locatio...
    method BackgroundLocationManager (line 40) | public BackgroundLocationManager(LocationClient locationClient, Backgr...
    method formFinishedLoading (line 49) | public void formFinishedLoading() {
    method activityDisplayed (line 58) | public BackgroundLocationMessage activityDisplayed() {
    method activityHidden (line 111) | public void activityHidden() {
    method isPendingPermissionCheck (line 119) | public boolean isPendingPermissionCheck() {
    method locationPermissionGranted (line 123) | public BackgroundLocationMessage locationPermissionGranted() {
    method locationPermissionDenied (line 161) | public void locationPermissionDenied() {
    method backgroundLocationPreferenceToggled (line 174) | public void backgroundLocationPreferenceToggled() {
    method locationPermissionChanged (line 192) | public void locationPermissionChanged() {
    method locationProvidersChanged (line 204) | public void locationProvidersChanged() {
    method startLocationRequests (line 217) | private void startLocationRequests() {
    method stopLocationRequests (line 232) | private void stopLocationRequests() {
    method onLocationChanged (line 238) | @Override
    method onClientStart (line 246) | @Override
    method onClientStartFailure (line 251) | @Override
    method onClientStop (line 256) | @Override
    type BackgroundLocationState (line 261) | private enum BackgroundLocationState {
    type BackgroundLocationMessage (line 287) | public enum BackgroundLocationMessage {
      method BackgroundLocationMessage (line 298) | BackgroundLocationMessage(int messageTextResourceId, boolean isMenuC...
      method getMessageTextResourceId (line 303) | public int getMessageTextResourceId() {
      method isMenuCharacterNeeded (line 307) | public boolean isMenuCharacterNeeded() {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/backgroundlocation/BackgroundLocationViewModel.java
  class BackgroundLocationViewModel (line 19) | public class BackgroundLocationViewModel extends ViewModel {
    method BackgroundLocationViewModel (line 23) | public BackgroundLocationViewModel(BackgroundLocationManager locationM...
    method formFinishedLoading (line 27) | public void formFinishedLoading() {
    method activityDisplayed (line 31) | public BackgroundLocationManager.BackgroundLocationMessage activityDis...
    method activityHidden (line 35) | public void activityHidden() {
    method isBackgroundLocationPermissionsCheckNeeded (line 39) | public boolean isBackgroundLocationPermissionsCheckNeeded() {
    method locationPermissionsGranted (line 43) | public BackgroundLocationManager.BackgroundLocationMessage locationPer...
    method locationPermissionsDenied (line 47) | public void locationPermissionsDenied() {
    method locationPermissionChanged (line 51) | public void locationPermissionChanged() {
    method locationProvidersChanged (line 55) | public void locationProvidersChanged() {
    method backgroundLocationPreferenceToggled (line 59) | public void backgroundLocationPreferenceToggled(Settings generalSettin...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/media/FormMediaUtils.java
  class FormMediaUtils (line 17) | public final class FormMediaUtils {
    method FormMediaUtils (line 19) | private FormMediaUtils() {
    method getClip (line 23) | @Nullable
    method getClipID (line 34) | public static String getClipID(FormEntryPrompt prompt) {
    method getClipID (line 38) | public static String getClipID(FormEntryPrompt prompt, SelectChoice se...
    method getPlayableAudioURI (line 42) | @Nullable
    method getPlayableAudioURI (line 47) | @Nullable
    method deriveReference (line 57) | @Nullable
    method getPlayColor (line 71) | public static int getPlayColor(FormEntryPrompt prompt, ThemeUtils them...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/media/PromptAutoplayer.java
  class PromptAutoplayer (line 20) | public class PromptAutoplayer {
    method PromptAutoplayer (line 28) | public PromptAutoplayer(AudioPlayer audioPlayer, ReferenceManager refe...
    method autoplayIfNeeded (line 33) | public Boolean autoplayIfNeeded(FormEntryPrompt prompt) {
    method hasAudioAutoplay (line 60) | private boolean hasAudioAutoplay(String autoplayOption) {
    method getSelectClips (line 64) | private List<Clip> getSelectClips(FormEntryPrompt prompt) {
    method appearanceDoesNotShowControls (line 89) | private boolean appearanceDoesNotShowControls(String appearance) {
    method getPromptClip (line 95) | private Clip getPromptClip(FormEntryPrompt prompt) {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/questions/AnswersProvider.java
  type AnswersProvider (line 8) | public interface AnswersProvider {
    method getAnswers (line 9) | HashMap<FormIndex, IAnswerData> getAnswers();

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/questions/AudioVideoImageTextLabel.java
  class AudioVideoImageTextLabel (line 49) | public class AudioVideoImageTextLabel extends RelativeLayout implements ...
    method AudioVideoImageTextLabel (line 60) | public AudioVideoImageTextLabel(Context context) {
    method AudioVideoImageTextLabel (line 66) | public AudioVideoImageTextLabel(Context context, AttributeSet attrs) {
    method setTextView (line 72) | public void setTextView(TextView questionText) {
    method setText (line 85) | public void setText(String questionText, boolean isRequiredQuestion, f...
    method setAudio (line 98) | public void setAudio(String audioURI, AudioPlayer audioPlayer) {
    method setImage (line 128) | public void setImage(@NonNull File imageFile, ImageLoader imageLoader) {
    method setBigImage (line 141) | public void setBigImage(@NonNull File bigImageFile) {
    method setVideo (line 145) | public void setVideo(@NonNull File videoFile) {
    method setPlayTextColor (line 153) | public void setPlayTextColor(int textColor) {
    method setMediaUtils (line 157) | public void setMediaUtils(MediaUtils mediaUtils) {
    method playVideo (line 161) | public void playVideo() {
    method getLabelTextView (line 165) | public TextView getLabelTextView() {
    method getImageView (line 169) | public ImageView getImageView() {
    method getMissingImage (line 173) | public TextView getMissingImage() {
    method getVideoButton (line 177) | public Button getVideoButton() {
    method getAudioButton (line 181) | public Button getAudioButton() {
    method onClick (line 185) | @Override
    method setEnabled (line 194) | @Override
    method isEnabled (line 200) | @Override
    method onImageClick (line 205) | private void onImageClick() {
    method selectItem (line 213) | private void selectItem() {
    method setItemClickListener (line 225) | public void setItemClickListener(SelectItemClickListener listener) {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/questions/NoButtonsItem.java
  class NoButtonsItem (line 16) | public class NoButtonsItem extends FrameLayout {
    method NoButtonsItem (line 20) | public NoButtonsItem(Context context, boolean enabled, ImageLoader ima...
    method setUpNoButtonsItem (line 29) | public void setUpNoButtonsItem(File imageFile, String choiceText, Stri...

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/questions/QuestionDetails.java
  class QuestionDetails (line 10) | public class QuestionDetails {
    method QuestionDetails (line 15) | public QuestionDetails(FormEntryPrompt prompt) {
    method QuestionDetails (line 19) | public QuestionDetails(FormEntryPrompt prompt, boolean readOnlyOverrid...
    method getPrompt (line 24) | public FormEntryPrompt getPrompt() {
    method isReadOnly (line 28) | public boolean isReadOnly() {

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/repeats/DeleteRepeatDialogFragment.java
  class DeleteRepeatDialogFragment (line 24) | public class DeleteRepeatDialogFragment extends DialogFragment {
    method DeleteRepeatDialogFragment (line 31) | public DeleteRepeatDialogFragment(ViewModelProvider.Factory viewModelF...
    method onAttach (line 35) | @Override
    method onCreateDialog (line 43) | @NonNull

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/DiskFormSaver.java
  class DiskFormSaver (line 15) | public class DiskFormSaver implements FormSaver {
    method save (line 17) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/FormSaveViewModel.java
  class FormSaveViewModel (line 60) | public class FormSaveViewModel extends ViewModel implements MaterialProg...
    method FormSaveViewModel (line 98) | public FormSaveViewModel(SavedStateHandle stateHandle, Supplier<Long> ...
    method onCleared (line 132) | @Override
    method saveForm (line 137) | public void saveForm(Uri instanceContentURI, boolean shouldFinalize, S...
    method ignoreChanges (line 157) | public void ignoreChanges() {
    method resumeSave (line 198) | public void resumeSave() {
    method getAbsoluteInstancePath (line 217) | @Nullable
    method isSaving (line 222) | public boolean isSaving() {
    method cancel (line 226) | @Override
    method setReason (line 235) | public void setReason(@NonNull String reason) {
    method getReason (line 239) | public String getReason() {
    method saveReason (line 243) | private boolean saveReason() {
    method saveToDisk (line 252) | private void saveToDisk(SaveRequest saveRequest) {
    method handleTaskResult (line 267) | private void handleTaskResult(SaveToDiskResult taskResult, SaveRequest...
    method getSaveResult (line 321) | public LiveData<SaveResult> getSaveResult() {
    method resumeFormEntry (line 325) | public void resumeFormEntry() {
    method requiresReasonToSave (line 329) | private boolean requiresReasonToSave() {
    method getFormName (line 335) | public String getFormName() {
    method deleteAnswerFile (line 342) | @Override
    method replaceAnswerFile (line 356) | @Override
    method createAnswerFile (line 369) | @Override
    method getAnswerFile (line 412) | @Override
    method isSavingAnswerFile (line 422) | public LiveData<Boolean> isSavingAnswerFile() {
    method clearMediaFiles (line 426) | private void clearMediaFiles() {
    method getAnswerFileError (line 431) | public LiveData<String> getAnswerFileError() {
    method answerFileErrorDisplayed (line 435) | public void answerFileErrorDisplayed() {
    method canBeFullyDiscarded (line 439) | public boolean canBeFullyDiscarded() {
    method getLastSavedTime (line 443) | public Long getLastSavedTime() {
    method getInstance (line 447) | @Nullable
    method removeSavepoint (line 452) | private void removeSavepoint(long formDbId, @Nullable Long instanceDbI...
    class SaveResult (line 460) | public static class SaveResult {
      method SaveResult (line 465) | SaveResult(State state, SaveRequest request) {
      method SaveResult (line 469) | SaveResult(State state, SaveRequest request, String message) {
      method getState (line 475) | public State getState() {
      method getMessage (line 479) | public String getMessage() {
      type State (line 483) | public enum State {
      method getRequest (line 493) | public SaveRequest getRequest() {
    class SaveRequest (line 498) | public static class SaveRequest {
      method SaveRequest (line 505) | SaveRequest(Uri instanceContentURI, boolean viewExiting, String upda...
      method shouldFinalize (line 512) | public boolean shouldFinalize() {
      method viewExiting (line 516) | public boolean viewExiting() {
    class SaveTask (line 521) | private static class SaveTask extends AsyncTask<Void, String, SaveToDi...
      method SaveTask (line 535) | SaveTask(SaveRequest saveRequest, FormSaver formSaver, FormControlle...
      method doInBackground (line 549) | @Override
      method onProgressUpdate (line 558) | @Override
      method onPostExecute (line 563) | @Override
      type Listener (line 568) | interface Listener {
        method onProgressPublished (line 569) | void onProgressPublished(String progress);
        method onComplete (line 571) | void onComplete(SaveToDiskResult saveToDiskResult);

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/FormSaver.java
  type FormSaver (line 14) | public interface FormSaver {
    method save (line 15) | SaveToDiskResult save(Uri instanceContentURI, FormController formContr...
    type ProgressListener (line 18) | interface ProgressListener {
      method onProgressUpdate (line 19) | void onProgressUpdate(String message);

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/SaveAnswerFileErrorDialogFragment.java
  class SaveAnswerFileErrorDialogFragment (line 15) | public class SaveAnswerFileErrorDialogFragment extends DialogFragment {
    method SaveAnswerFileErrorDialogFragment (line 20) | public SaveAnswerFileErrorDialogFragment(ViewModelProvider.Factory vie...
    method onAttach (line 24) | @Override
    method onCreateDialog (line 32) | @NonNull
    method onDismiss (line 42) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/SaveAnswerFileProgressDialogFragment.java
  class SaveAnswerFileProgressDialogFragment (line 9) | public class SaveAnswerFileProgressDialogFragment extends MaterialProgre...
    method onAttach (line 11) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formentry/saving/SaveFormProgressDialogFragment.java
  class SaveFormProgressDialogFragment (line 12) | public class SaveFormProgressDialogFragment extends MaterialProgressDial...
    method SaveFormProgressDialogFragment (line 17) | public SaveFormProgressDialogFragment(ViewModelProvider.Factory viewMo...
    method onAttach (line 21) | @Override
    method getOnCancelCallback (line 39) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formhierarchy/FormHierarchyFragment.java
  class FormHierarchyFragment (line 72) | public class FormHierarchyFragment extends Fragment {
    method FormHierarchyFragment (line 89) | public FormHierarchyFragment(
    method onAttach (line 106) | @Override
    method handleInstanceEditResult (line 180) | private void handleInstanceEditResult(InstanceEditResult result) {
    method openEditedInstance (line 194) | private void openEditedInstance(long dbId) {
    method showOpenDraftEditDialog (line 200) | private void showOpenDraftEditDialog(Instance instance) {
    method showOpenFinalizedEditDialog (line 219) | private void showOpenFinalizedEditDialog(Instance instance) {
    method onViewCreated (line 240) | @Override
    method refreshView (line 314) | public void refreshView() {
    method refreshView (line 321) | private void refreshView(boolean isGoingUp) {
    method calculateElementsToDisplay (line 362) | private void calculateElementsToDisplay(FormController formController,...
    method jumpToHierarchyStartIndex (line 550) | private void jumpToHierarchyStartIndex() {
    method isScreenEvent (line 600) | private boolean isScreenEvent(FormController formController, FormIndex...
    method goUpLevel (line 612) | protected void goUpLevel() {
    method getCurrentPath (line 638) | private CharSequence getCurrentPath() {
    method onElementClick (line 662) | private void onElementClick(HierarchyItem item) {
    method onQuestionClicked (line 683) | void onQuestionClicked(FormIndex index) {
    method createErrorDialog (line 705) | protected void createErrorDialog(String errorMsg) {
    method isDisplayingSingleGroup (line 730) | private boolean isDisplayingSingleGroup() {
    method configureButtons (line 735) | private void configureButtons(FormHierarchyLayoutBinding binding, Form...
    method didDeleteLastRepeatItem (line 769) | private boolean didDeleteLastRepeatItem() {
    method didDeleteFirstRepeatItem (line 780) | private boolean didDeleteFirstRepeatItem() {
    method onRepeatDeleted (line 787) | private void onRepeatDeleted() {
    method goToPreviousEvent (line 809) | private void goToPreviousEvent() {
    method navigateToTheLastRelevantIndex (line 822) | private void navigateToTheLastRelevantIndex(FormController formControl...
    class FormHiearchyMenuProvider (line 845) | private static class FormHiearchyMenuProvider implements MenuProvider {
      method FormHiearchyMenuProvider (line 853) | FormHiearchyMenuProvider(FormEntryViewModel formEntryViewModel, Form...
      method onCreateMenu (line 861) | @Override
      method onPrepareMenu (line 866) | @Override
      method onMenuItemSelected (line 881) | @Override
      method isGroupSizeLocked (line 904) | private boolean isGroupSizeLocked(FormIndex index) {
      type OnClickListener (line 910) | interface OnClickListener {
        method onEditClicked (line 911) | void onEditClicked();
        method onGoUpClicked (line 913) | void onGoUpClicked();
        method onAddRepeatClicked (line 915) | void onAddRepeatClicked();
        method onDeleteRepeatClicked (line 917) | void onDeleteRepeatClicked();

FILE: collect_app/src/main/java/org/odk/collect/android/formmanagement/download/ServerFormDownloader.java
  class ServerFormDownloader (line 36) | public class ServerFormDownloader implements FormDownloader {
    method ServerFormDownloader (line 47) | public ServerFormDownloader(FormSource formSource, FormsRepository for...
    method downloadForm (line 58) | @Override
    method processOneForm (line 92) | private void processOneForm(ServerFormDetails fd, OngoingWorkListener ...
    method isSubmissionOk (line 154) | private boolean isSubmissionOk(FormMetadata formMetadata) {
    method installEverything (line 159) | private void installEverything(String tempMediaPath, FileResult fileRe...
    method cleanUp (line 214) | private void cleanUp(FileResult fileResult, String tempMediaPath) {
    method findOrCreateForm (line 230) | private FormResult findOrCreateForm(File formFile, FormMetadata formMe...
    method saveNewForm (line 244) | private Form saveNewForm(FormMetadata formMetadata, File formFile, Str...
    method downloadXform (line 266) | private FileResult downloadXform(String formName, String url, OngoingW...
    method getFormFileName (line 287) | @NotNull
    method validateHash (line 299) | private static String validateHash(String hash) {
    method moveMediaFiles (line 303) | private static void moveMediaFiles(String tempMediaPath, File formMedi...
    class FormResult (line 320) | private static class FormResult {
      method FormResult (line 325) | private FormResult(Form form, boolean isNew) {
      method isNew (line 330) | private boolean isNew() {
      method getForm (line 334) | public Form getForm() {
    class FileResult (line 339) | private static class FileResult {
      method FileResult (line 344) | FileResult(File file, boolean isNew) {
      method getFile (line 349) | private File getFile() {
      method isNew (line 353) | private boolean isNew() {
    class ProgressReporterAndSupplierStateListener (line 358) | private static class ProgressReporterAndSupplierStateListener implemen...
      method ProgressReporterAndSupplierStateListener (line 362) | ProgressReporterAndSupplierStateListener(ProgressReporter progressRe...
      method progressUpdate (line 367) | @Override
      method isCancelled (line 374) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/formmanagement/matchexactly/ServerFormsSynchronizer.java
  class ServerFormsSynchronizer (line 15) | public class ServerFormsSynchronizer {
    method ServerFormsSynchronizer (line 23) | public ServerFormsSynchronizer(ServerFormsDetailsFetcher serverFormsDe...
    method synchronize (line 31) | public void synchronize() throws FormSourceException {
    type ServerFormsDetailsFetcher (line 59) | public interface ServerFormsDetailsFetcher {
      method fetchFormDetails (line 60) | List<ServerFormDetails> fetchFormDetails(FormsRepository formsReposi...

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/MediaLoadingFragment.java
  class MediaLoadingFragment (line 15) | public class MediaLoadingFragment extends Fragment {
    method beginMediaLoadingTask (line 19) | public void beginMediaLoadingTask(Uri uri, FormController formControll...
    method onCreate (line 24) | @Override
    method onAttach (line 30) | @Override
    method isMediaLoadingTaskRunning (line 38) | public boolean isMediaLoadingTaskRunning() {

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/LocationProvidersDisabledDialog.java
  class LocationProvidersDisabledDialog (line 30) | public class LocationProvidersDisabledDialog extends DialogFragment {
    method newInstance (line 34) | public static LocationProvidersDisabledDialog newInstance() {
    method show (line 43) | @Override
    method onCreateDialog (line 55) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/MovingBackwardsDialog.java
  class MovingBackwardsDialog (line 27) | public class MovingBackwardsDialog extends DialogFragment {
    type MovingBackwardsDialogListener (line 31) | public interface MovingBackwardsDialogListener {
      method preventOtherWaysOfEditingForm (line 32) | void preventOtherWaysOfEditingForm();
    method onAttach (line 37) | @Override
    method onCreateDialog (line 45) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/RankingWidgetDialog.java
  class RankingWidgetDialog (line 53) | public class RankingWidgetDialog extends DialogFragment {
    type RankingListener (line 60) | public interface RankingListener {
      method onRankingChanged (line 61) | void onRankingChanged(List<SelectChoice> items);
    method RankingWidgetDialog (line 64) | public RankingWidgetDialog() {
    method RankingWidgetDialog (line 67) | public RankingWidgetDialog(List<SelectChoice> items, FormEntryPrompt f...
    method onAttach (line 72) | @Override
    method onCreateDialog (line 84) | @Override
    method setUpRankingLayout (line 96) | private NestedScrollView setUpRankingLayout() {
    method setUpPositionsLayout (line 113) | private LinearLayout setUpPositionsLayout() {
    method setUpRecyclerView (line 132) | private RecyclerView setUpRecyclerView() {

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/ResetSettingsResultDialog.java
  class ResetSettingsResultDialog (line 27) | public class ResetSettingsResultDialog extends DialogFragment {
    type ResetSettingsResultDialogListener (line 32) | public interface ResetSettingsResultDialogListener {
      method onDialogClosed (line 33) | void onDialogClosed();
    method newInstance (line 38) | public static ResetSettingsResultDialog newInstance(String dialogMessa...
    method onAttach (line 47) | @Override
    method onCreateDialog (line 55) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/SelectMinimalDialog.java
  class SelectMinimalDialog (line 30) | public abstract class SelectMinimalDialog extends MaterialFullScreenDial...
    type SelectMinimalDialogListener (line 44) | public interface SelectMinimalDialogListener {
      method updateSelectedItems (line 45) | void updateSelectedItems(List<Selection> items);
    method SelectMinimalDialog (line 48) | public SelectMinimalDialog() {
    method SelectMinimalDialog (line 51) | public SelectMinimalDialog(boolean isFlex, boolean isAutoComplete) {
    method onAttach (line 56) | @Override
    method onCreateView (line 69) | @Override
    method onViewCreated (line 75) | @Override
    method onDestroyView (line 82) | @Override
    method onCloseClicked (line 89) | @Override
    method onBackPressed (line 94) | @Override
    method closeDialogAndSaveAnswers (line 99) | protected void closeDialogAndSaveAnswers() {
    method getToolbar (line 107) | @Nullable
    method initToolbar (line 113) | private void initToolbar() {
    method initSearchBar (line 121) | private void initSearchBar() {
    method initRecyclerView (line 143) | private void initRecyclerView() {
    method setListener (line 150) | public void setListener(SelectMinimalDialogListener listener) {

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/SelectMultiMinimalDialog.java
  class SelectMultiMinimalDialog (line 14) | public class SelectMultiMinimalDialog extends SelectMinimalDialog {
    method SelectMultiMinimalDialog (line 15) | public SelectMultiMinimalDialog() {
    method SelectMultiMinimalDialog (line 18) | public SelectMultiMinimalDialog(List<Selection> selectedItems, boolean...

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/SelectOneMinimalDialog.java
  class SelectOneMinimalDialog (line 17) | public class SelectOneMinimalDialog extends SelectMinimalDialog implemen...
    method SelectOneMinimalDialog (line 18) | public SelectOneMinimalDialog() {
    method SelectOneMinimalDialog (line 21) | public SelectOneMinimalDialog(String selectedItem, boolean isFlex, boo...
    method onViewCreated (line 29) | @Override
    method onItemClicked (line 36) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/dialogs/SimpleDialog.java
  class SimpleDialog (line 33) | public class SimpleDialog extends DialogFragment {
    method newInstance (line 43) | public static SimpleDialog newInstance(String dialogTitle, int iconId,...
    method show (line 61) | @Override
    method onCreateDialog (line 73) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/viewmodels/RankingViewModel.java
  class RankingViewModel (line 12) | public class RankingViewModel extends ViewModel {
    method RankingViewModel (line 17) | private RankingViewModel(List<SelectChoice> items, FormEntryPrompt for...
    method getItems (line 22) | public List<SelectChoice> getItems() {
    method getFormEntryPrompt (line 26) | public FormEntryPrompt getFormEntryPrompt() {
    class Factory (line 30) | public static class Factory implements ViewModelProvider.Factory {
      method Factory (line 34) | public Factory(List<SelectChoice> items, FormEntryPrompt formEntryPr...
      method create (line 39) | @NonNull

FILE: collect_app/src/main/java/org/odk/collect/android/fragments/viewmodels/SelectMinimalViewModel.java
  class SelectMinimalViewModel (line 9) | public class SelectMinimalViewModel extends ViewModel {
    method SelectMinimalViewModel (line 14) | private SelectMinimalViewModel(AbstractSelectListAdapter selectListAda...
    method getSelectListAdapter (line 20) | public AbstractSelectListAdapter getSelectListAdapter() {
    method isFlex (line 24) | public boolean isFlex() {
    method isAutoComplete (line 28) | public boolean isAutoComplete() {
    class Factory (line 32) | public static class Factory implements ViewModelProvider.Factory {
      method Factory (line 37) | public Factory(AbstractSelectListAdapter selectListAdapter, boolean ...
      method create (line 43) | @NonNull

FILE: collect_app/src/main/java/org/odk/collect/android/geo/MapConfiguratorProvider.java
  class MapConfiguratorProvider (line 32) | public class MapConfiguratorProvider {
    method MapConfiguratorProvider (line 42) | private MapConfiguratorProvider() {
    method initOptions (line 51) | public static void initOptions(Context context) {
    method getConfigurator (line 121) | public static @NonNull
    method getConfigurator (line 130) | public static @NonNull MapConfigurator getConfigurator(String id) {
    method getIds (line 135) | public static String[] getIds() {
    method getLabelIds (line 144) | public static int[] getLabelIds() {
    method isMapboxSupported (line 152) | private static boolean isMapboxSupported() {
    method getOption (line 160) | private static @NonNull SourceOption getOption(String id) {
    method getApplication (line 173) | private static Collect getApplication() {
    class SourceOption (line 177) | private static class SourceOption {
      method SourceOption (line 182) | private SourceOption(String id, int labelId, MapConfigurator cftor) {

FILE: collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyModule.java
  class AppDependencyModule (line 164) | @Module
    method context (line 167) | @Provides
    method provideMimeTypeMap (line 172) | @Provides
    method providesUserAgent (line 177) | @Provides
    method provideHttpInterface (line 183) | @Provides
    method provideWebCredentials (line 194) | @Provides
    method providesAnalytics (line 199) | @Provides
    method providesPermissionsProvider (line 210) | @Provides
    method providesReferenceManager (line 215) | @Provides
    method providesSettingsProvider (line 220) | @Provides
    method providesInstallIDProvider (line 227) | @Provides
    method providesStoragePathProvider (line 232) | @Provides
    method providesAdminPasswordProvider (line 243) | @Provides
    method providesFormUpdateManger (line 248) | @Provides
    method providesFormSubmitManager (line 253) | @Provides
    method providesNetworkStateProvider (line 258) | @Provides
    method providesQRCodeGenerator (line 263) | @Provides
    method providesVersionInformation (line 268) | @Provides
    method providesFileProvider (line 273) | @Provides
    method providesWorkManager (line 278) | @Provides
    method providesScheduler (line 283) | @Provides
    method providesPreferenceMigrator (line 292) | @Provides
    method providesPropertyManager (line 297) | @Provides
    method providesSettingsChangeHandler (line 303) | @Provides
    method providesODKAppSettingsImporter (line 308) | @Provides
    method providesQRCodeDecoder (line 333) | @Provides
    method providesNotifier (line 338) | @Provides
    method providesChangeLockProvider (line 343) | @Provides
    method providesScreenUtils (line 349) | @Provides
    method providesAudioRecorder (line 354) | @Provides
    method provideEntitiesRepositoryProvider (line 359) | @Provides
    method provideSoftKeyboardController (line 364) | @Provides
    method providesJsonPreferencesGenerator (line 369) | @Provides
    method providesPermissionsChecker (line 374) | @Provides
    method providesExternalAppIntentProvider (line 380) | @Provides
    method providesFormSessionStore (line 386) | @Provides
    method providesWebPageService (line 391) | @Provides
    method providesProjectsRepository (line 396) | @Provides
    method providesProjectCreator (line 402) | @Provides
    method providesGson (line 408) | @Provides
    method providesUUIDGenerator (line 413) | @Provides
    method providesInstancesDataService (line 419) | @Provides
    method providesItemsetsRepository (line 433) | @Provides
    method providesCurrentProjectProvider (line 438) | @Provides
    method providesFormsRepositoryProvider (line 443) | @Provides
    method providesInstancesRepositoryProvider (line 448) | @Provides
    method providesSavepointsRepositoryProvider (line 453) | @Provides
    method providesProjectPreferencesViewModel (line 458) | @Provides
    method providesReadyToSendViewModel (line 463) | @Provides
    method providesMainMenuViewModelFactory (line 468) | @Provides
    method providesAnalyticsInitializer (line 478) | @Provides
    method providesFormSourceProvider (line 483) | @Provides
    method providesFormsUpdater (line 488) | @Provides
    method providesAutoSendSettingsProvider (line 493) | @Provides
    method providesExistingProjectMigrator (line 498) | @Provides
    method providesFormUpdatesUpgrader (line 503) | @Provides
    method providesExistingSettingsMigrator (line 508) | @Provides
    method providesGoogleDriveProjectsDeleter (line 513) | @Provides
    method providesUpgradeInitializer (line 518) | @Provides
    method providesApplicationInitializer (line 532) | @Provides
    method providesProjectDeleter (line 537) | @Provides
    method providesProjectResetter (line 542) | @Provides
    method providesDisabledPreferencesRemover (line 547) | @Provides
    method providesReferenceLayerRepository (line 552) | @Provides
    method providesIntentLauncher (line 563) | @Provides
    method providesLocationClient (line 568) | @Provides
    method providesFusedLocationClient (line 573) | @Provides
    method providesMediaUtils (line 579) | @Provides
    method providesMapFragmentFactory (line 584) | @Provides
    method providesImageLoader (line 589) | @Provides
    method providesBlankFormListViewModel (line 594) | @Provides
    method providesImageCompressorManager (line 599) | @Provides
    method formEntryControllerFactory (line 605) | @Provides
    method providesBroadcastReceiverRegister (line 612) | @Provides
    method providesRestrictionsManager (line 617) | @Provides
    method providesMDMConfigObserver (line 622) | @Provides
    method providesBarcodeScannerViewFactory (line 653) | @Provides
    method providesAudioPlayerFactory (line 658) | @Provides
    method providesUniqueIdGenerator (line 663) | @Provides

FILE: collect_app/src/main/java/org/odk/collect/android/instancemanagement/InstanceDiskSynchronizer.java
  class InstanceDiskSynchronizer (line 53) | public class InstanceDiskSynchronizer {
    method getStatusMessage (line 63) | public String getStatusMessage() {
    method InstanceDiskSynchronizer (line 67) | public InstanceDiskSynchronizer(SettingsProvider settingsProvider) {
    method doInBackground (line 74) | public String doInBackground() {
    method getFormIdFromInstance (line 157) | private String getFormIdFromInstance(final String instancePath) {
    method getInstanceIdFromInstance (line 171) | private String getInstanceIdFromInstance(final String instancePath) {
    method encryptInstanceIfNeeded (line 185) | private void encryptInstanceIfNeeded(Form form, Instance instance) thr...
    method encryptInstance (line 193) | private void encryptInstance(Instance instance) throws EncryptionExcep...
    method shouldInstanceBeEncrypted (line 222) | private boolean shouldInstanceBeEncrypted(Form form) {

FILE: collect_app/src/main/java/org/odk/collect/android/instancemanagement/send/InstanceUploaderActivity.java
  class InstanceUploaderActivity (line 57) | public class InstanceUploaderActivity extends LocalizedActivity implemen...
    method onCreate (line 96) | @Override
    method init (line 106) | private void init(Bundle savedInstanceState) {
    method onResume (line 203) | @Override
    method onPostResume (line 214) | @Override
    method onSaveInstanceState (line 220) | @Override
    method onRetainCustomNonConfigurationInstance (line 238) | @Override
    method onDestroy (line 243) | @Override
    method uploadingComplete (line 251) | @Override
    method progressUpdate (line 271) | @Override
    method onCreateDialog (line 277) | @Override
    method authRequest (line 323) | @Override
    method createUploadInstancesResultDialog (line 359) | private void createUploadInstancesResultDialog(String message) {
    method updatedCredentials (line 367) | @Override
    method cancelledUpdatingCredentials (line 385) | @Override
    method getReferrerUri (line 390) | private String getReferrerUri() {

FILE: collect_app/src/main/java/org/odk/collect/android/instancemanagement/send/InstanceUploaderListActivity.java
  class InstanceUploaderListActivity (line 93) | public class InstanceUploaderListActivity extends LocalizedActivity impl...
    method onCreate (line 141) | @Override
    method onUploadButtonsClicked (line 186) | public void onUploadButtonsClicked() {
    method init (line 209) | void init() {
    method updateAutoSendStatus (line 254) | private void updateAutoSendStatus() {
    method onResume (line 272) | @Override
    method uploadSelectedFiles (line 279) | private void uploadSelectedFiles(long[] instanceIds) {
    method onCreateOptionsMenu (line 285) | @Override
    method onOptionsItemSelected (line 336) | @Override
    method createPreferencesMenu (line 366) | private void createPreferencesMenu() {
    method onItemClick (line 371) | @Override
    method onSaveInstanceState (line 385) | @Override
    method onActivityResult (line 399) | @Override
    method setupAdapter (line 420) | private void setupAdapter() {
    method getSortingOrderKey (line 428) | private String getSortingOrderKey() {
    method updateAdapter (line 432) | private void updateAdapter() {
    method onCreateLoader (line 436) | @NonNull
    method onLoadFinished (line 447) | @Override
    method onLoaderReset (line 461) | @Override
    method onLongClick (line 466) | @Override
    method showSentAndUnsentChoices (line 475) | private boolean showSentAndUnsentChoices() {
    method getSortingOrder (line 504) | private String getSortingOrder() {
    method getSelectedSortingOrder (line 523) | private int getSelectedSortingOrder() {
    method restoreSelectedSortingOrder (line 530) | private void restoreSelectedSortingOrder() {
    method showProgressBar (line 534) | private void showProgressBar() {
    method hideProgressBarAndAllow (line 538) | private void hideProgressBarAndAllow() {
    method hideProgressBar (line 542) | private void hideProgressBar() {
    method getFilterText (line 546) | private CharSequence getFilterText() {
    method saveSelectedSortingOrder (line 550) | private void saveSelectedSortingOrder(int selectedStringOrder) {

FILE: collect_app/src/main/java/org/odk/collect/android/javarosawrapper/FormIndexUtils.java
  class FormIndexUtils (line 10) | public final class FormIndexUtils {
    method FormIndexUtils (line 12) | private FormIndexUtils() {
    method getPreviousLevel (line 21) | @Nullable
    method getRepeatGroupIndex (line 30) | @Nullable

FILE: collect_app/src/main/java/org/odk/collect/android/javarosawrapper/InstanceMetadata.java
  class InstanceMetadata (line 14) | public class InstanceMetadata {
    method InstanceMetadata (line 19) | public InstanceMetadata(String instanceId, String instanceName, AuditC...

FILE: collect_app/src/main/java/org/odk/collect/android/javarosawrapper/JavaRosaFormController.java
  class JavaRosaFormController (line 75) | public class JavaRosaFormController implements FormController {
    method JavaRosaFormController (line 104) | public JavaRosaFormController(File mediaFolder, FormEntryController fe...
    method isEditing (line 111) | @Override
    method getFormDef (line 116) | public FormDef getFormDef() {
    method getMediaFolder (line 120) | public File getMediaFolder() {
    method getInstanceFile (line 124) | @Nullable
    method setInstanceFile (line 129) | public void setInstanceFile(File instanceFile) {
    method getAbsoluteInstancePath (line 133) | @Nullable
    method getLastSavedPath (line 138) | @Nullable
    method setIndexWaitingForData (line 143) | public void setIndexWaitingForData(FormIndex index) {
    method getIndexWaitingForData (line 147) | public FormIndex getIndexWaitingForData() {
    method getAuditEventLogger (line 151) | public AuditEventLogger getAuditEventLogger() {
    method getXPath (line 165) | public String getXPath(FormIndex index) {
    method getIndexFromXPath (line 196) | @Nullable
    method getEvent (line 229) | public int getEvent() {
    method getEvent (line 233) | public int getEvent(FormIndex index) {
    method getFormIndex (line 237) | public FormIndex getFormIndex() {
    method getLanguages (line 241) | public String[] getLanguages() {
    method getFormTitle (line 245) | public String getFormTitle() {
    method getLanguage (line 249) | public String getLanguage() {
    method getBindAttribute (line 253) | private String getBindAttribute(FormIndex idx, String attributeNamespa...
    method getCaptionHierarchy (line 263) | private FormEntryCaption[] getCaptionHierarchy() {
    method getCaptionHierarchy (line 272) | private FormEntryCaption[] getCaptionHierarchy(FormIndex index) {
    method getCaptionPrompt (line 276) | public FormEntryCaption getCaptionPrompt(FormIndex index) {
    method getCaptionPrompt (line 280) | public FormEntryCaption getCaptionPrompt() {
    method finalizeForm (line 284) | public void finalizeForm() {
    method getInstance (line 291) | private FormInstance getInstance() {
    method groupIsFieldList (line 301) | private boolean groupIsFieldList(FormIndex index) {
    method repeatIsFieldList (line 311) | private boolean repeatIsFieldList(FormIndex index) {
    method getAppearanceAttr (line 318) | private String getAppearanceAttr(@NonNull FormIndex index) {
    method usesDatabaseExternalDataFeature (line 328) | public boolean usesDatabaseExternalDataFeature(@NonNull FormIndex inde...
    method indexIsInFieldList (line 336) | public boolean indexIsInFieldList(FormIndex index) {
    method indexIsInFieldList (line 364) | public boolean indexIsInFieldList() {
    method currentPromptIsQuestion (line 368) | public boolean currentPromptIsQuestion() {
    method isCurrentQuestionFirstInForm (line 375) | public boolean isCurrentQuestionFirstInForm() {
    method answerQuestion (line 388) | public int answerQuestion(FormIndex index, IAnswerData data) throws Ja...
    method validateAnswerConstraint (line 396) | public ValidationResult validateAnswerConstraint(FormIndex index, IAns...
    method validateAnswers (line 405) | public ValidationResult validateAnswers(boolean moveToInvalidIndex) th...
    method getFailedValidationResult (line 423) | private ValidationResult getFailedValidationResult(FormIndex index, in...
    method saveAnswer (line 443) | public boolean saveAnswer(FormIndex index, IAnswerData data) throws Ja...
    method stepToNextEvent (line 456) | public int stepToNextEvent(boolean stepIntoGroup) {
    method stepOverGroup (line 466) | public int stepOverGroup() {
    method stepToPreviousScreenEvent (line 477) | public int stepToPreviousScreenEvent() throws JavaRosaException {
    method stepToNextScreenEvent (line 513) | public int stepToNextScreenEvent() throws JavaRosaException {
    method stepToNextEventType (line 556) | private int stepToNextEventType(int eventType) {
    method stepToOuterScreenEvent (line 568) | public int stepToOuterScreenEvent() {
    method isDisplayableGroup (line 610) | public boolean isDisplayableGroup(FormIndex index) {
    method isPresentationGroup (line 622) | private boolean isPresentationGroup(FormIndex groupIndex) {
    method isLogicalGroup (line 633) | private boolean isLogicalGroup(FormIndex groupIndex) {
    method saveAllScreenAnswers (line 642) | public ValidationResult saveAllScreenAnswers(HashMap<FormIndex, IAnswe...
    method saveOneScreenAnswer (line 659) | public ValidationResult saveOneScreenAnswer(FormIndex index, IAnswerDa...
    method stepToPreviousEvent (line 676) | public int stepToPreviousEvent() {
    method jumpToIndex (line 730) | public int jumpToIndex(FormIndex index) {
    method jumpToNewRepeatPrompt (line 734) | public void jumpToNewRepeatPrompt() {
    method newRepeat (line 745) | public void newRepeat() {
    method deleteRepeat (line 749) | public void deleteRepeat() {
    method setLanguage (line 754) | public void setLanguage(String language) {
    method getQuestionPrompts (line 758) | @NonNull
    method isGroupEmpty (line 792) | private boolean isGroupEmpty() {
    method getIndicesForGroup (line 800) | private List<FormIndex> getIndicesForGroup(GroupDef gd) {
    method getIndicesForGroup (line 805) | private List<FormIndex> getIndicesForGroup(GroupDef gd, FormIndex curr...
    method isGroupRelevant (line 825) | public boolean isGroupRelevant() {
    method getQuestionPrompt (line 836) | public FormEntryPrompt getQuestionPrompt(FormIndex index) {
    method getQuestionPrompt (line 840) | public FormEntryPrompt getQuestionPrompt() {
    method getQuestionPromptConstraintText (line 844) | public String getQuestionPromptConstraintText(FormIndex index) {
    method currentCaptionPromptIsQuestion (line 848) | public boolean currentCaptionPromptIsQuestion() {
    method getQuestionPromptRequiredText (line 852) | public String getQuestionPromptRequiredText(FormIndex index) {
    method getGroupsForIndex (line 889) | public FormEntryCaption[] getGroupsForIndex(FormIndex index) {
    method indexContainsRepeatableGroup (line 915) | public boolean indexContainsRepeatableGroup() {
    method indexContainsRepeatableGroup (line 919) | public boolean indexContainsRepeatableGroup(FormIndex formIndex) {
    method getLastRepeatedGroupRepeatCount (line 932) | public int getLastRepeatedGroupRepeatCount() {
    method getLastRepeatedGroupName (line 945) | public String getLastRepeatedGroupName() {
    method getLastGroup (line 963) | private FormEntryCaption getLastGroup() {
    method getLastGroupText (line 972) | public String getLastGroupText() {
    method getSubmissionDataReference (line 982) | private IDataReference getSubmissionDataReference() {
    method isSubmissionEntireForm (line 993) | public boolean isSubmissionEntireForm() {
    method getFilledInFormXml (line 998) | public ByteArrayPayload getFilledInFormXml() throws IOException {
    method getSubmissionXml (line 1006) | public ByteArrayPayload getSubmissionXml() throws IOException {
    method findDepthFirst (line 1016) | private TreeElement findDepthFirst(TreeElement parent, String name) {
    method getSubmissionMetadata (line 1032) | public InstanceMetadata getSubmissionMetadata() {
    method currentFormAuditsLocation (line 1109) | public boolean currentFormAuditsLocation() {
    method currentFormCollectsBackgroundLocation (line 1115) | public boolean currentFormCollectsBackgroundLocation() {
    method getAnswer (line 1119) | public IAnswerData getAnswer(TreeReference treeReference) {
    method getEntities (line 1123) | public EntitiesExtra getEntities() {

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/AdvanceToNextListener.java
  type AdvanceToNextListener (line 17) | public interface AdvanceToNextListener {
    method advance (line 19) | void advance();

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/DeleteInstancesListener.java
  type DeleteInstancesListener (line 23) | public interface DeleteInstancesListener {
    method deleteComplete (line 24) | void deleteComplete(int deletedInstances);
    method progressUpdate (line 26) | void progressUpdate(int progress, int total);

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/DownloadFormsTaskListener.java
  type DownloadFormsTaskListener (line 25) | public interface DownloadFormsTaskListener {
    method formsDownloadingComplete (line 26) | void formsDownloadingComplete(Map<ServerFormDetails, FormDownloadExcep...
    method progressUpdate (line 28) | void progressUpdate(String currentFile, int progress, int total);
    method formsDownloadingCancelled (line 30) | void formsDownloadingCancelled();

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/FormListDownloaderListener.java
  type FormListDownloaderListener (line 25) | public interface FormListDownloaderListener {
    method formListDownloadingComplete (line 26) | void formListDownloadingComplete(HashMap<String, ServerFormDetails> fo...

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/FormLoaderListener.java
  type FormLoaderListener (line 24) | public interface FormLoaderListener extends ProgressNotifier {
    method loadingComplete (line 25) | void loadingComplete(FormLoaderTask task, FormDef fd, String warningMsg);
    method loadingError (line 27) | void loadingError(String errorMsg);

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/InstanceUploaderListener.java
  type InstanceUploaderListener (line 24) | public interface InstanceUploaderListener {
    method uploadingComplete (line 25) | void uploadingComplete(HashMap<String, String> result);
    method progressUpdate (line 27) | void progressUpdate(int progress, int total);
    method authRequest (line 29) | void authRequest(Uri url, HashMap<String, String> doneSoFar);

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/Result.java
  type Result (line 8) | public interface Result<T> {
    method onComplete (line 9) | void onComplete(T result);

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/SelectItemClickListener.java
  type SelectItemClickListener (line 3) | public interface SelectItemClickListener {
    method onItemClicked (line 4) | void onItemClicked();

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/ThousandsSeparatorTextWatcher.java
  class ThousandsSeparatorTextWatcher (line 18) | public class ThousandsSeparatorTextWatcher implements TextWatcher {
    method ThousandsSeparatorTextWatcher (line 23) | public ThousandsSeparatorTextWatcher(EditText editText) {
    method beforeTextChanged (line 35) | @Override
    method onTextChanged (line 40) | @Override
    method afterTextChanged (line 43) | @Override
    method getDecimalFormattedString (line 67) | private static String getDecimalFormattedString(String value) {
    method getOriginalString (line 101) | public static String getOriginalString(String string) {

FILE: collect_app/src/main/java/org/odk/collect/android/listeners/WidgetValueChangedListener.java
  type WidgetValueChangedListener (line 5) | public interface WidgetValueChangedListener {
    method widgetValueChanged (line 6) | void widgetValueChanged(QuestionWidget changedWidget);

FILE: collect_app/src/main/java/org/odk/collect/android/location/client/MaxAccuracyWithinTimeoutLocationClientWrapper.java
  class MaxAccuracyWithinTimeoutLocationClientWrapper (line 21) | public class MaxAccuracyWithinTimeoutLocationClientWrapper implements Lo...
    method MaxAccuracyWithinTimeoutLocationClientWrapper (line 34) | public MaxAccuracyWithinTimeoutLocationClientWrapper(LocationClient lo...
    method requestLocationUpdates (line 45) | public void requestLocationUpdates(long timeoutSeconds) {
    method onClientStart (line 61) | @Override
    method onClientStartFailure (line 73) | @Override
    method onClientStop (line 78) | @Override
    method onLocationChanged (line 94) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/logic/FileReference.java
  class FileReference (line 19) | public class FileReference implements Reference {
    method FileReference (line 23) | public FileReference(String localPart, String referencePart) {
    method getInternalURI (line 28) | private String getInternalURI() {
    method doesBinaryExist (line 32) | @Override
    method getStream (line 37) | @Override
    method getURI (line 42) | @Override
    method isReadOnly (line 47) | @Override
    method getOutputStream (line 52) | @Override
    method remove (line 57) | @Override
    method getLocalURI (line 63) | @Override
    method probeAlternativeReferences (line 68) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/logic/FileReferenceFactory.java
  class FileReferenceFactory (line 13) | public class FileReferenceFactory extends PrefixedRootFactory {
    method FileReferenceFactory (line 17) | public FileReferenceFactory(String localRoot) {
    method factory (line 24) | @Override
    method toString (line 29) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/logic/ImmutableDisplayableQuestion.java
  class ImmutableDisplayableQuestion (line 34) | public class ImmutableDisplayableQuestion {
    method ImmutableDisplayableQuestion (line 79) | public ImmutableDisplayableQuestion(FormEntryPrompt question) {
    method getFormIndex (line 95) | public FormIndex getFormIndex() {
    method getAnswerText (line 99) | public Object getAnswerText() {
    method sameAs (line 107) | public boolean sameAs(FormEntryPrompt question) {
    method selectChoiceListsEqual (line 119) | private static boolean selectChoiceListsEqual(List<SelectChoice> selec...
    method getGuidanceHintText (line 140) | private static String getGuidanceHintText(FormEntryPrompt question) {
    method selectChoicesEqual (line 152) | private static boolean selectChoicesEqual(SelectChoice selectChoice1, ...

FILE: collect_app/src/main/java/org/odk/collect/android/logic/actions/setgeopoint/CollectSetGeopointAction.java
  class CollectSetGeopointAction (line 52) | public class CollectSetGeopointAction extends SetGeopointAction implemen...
    method CollectSetGeopointAction (line 57) | public CollectSetGeopointAction() {
    method CollectSetGeopointAction (line 62) | CollectSetGeopointAction(TreeReference targetReference) {
    method requestLocationUpdates (line 66) | @Override
    method onLocationChanged (line 89) | @Override
    method isBackgroundLocationEnabled (line 101) | private boolean isBackgroundLocationEnabled() {

FILE: collect_app/src/main/java/org/odk/collect/android/logic/actions/setgeopoint/CollectSetGeopointActionHandler.java
  class CollectSetGeopointActionHandler (line 25) | public class CollectSetGeopointActionHandler extends SetGeopointActionHa...
    method getSetGeopointAction (line 26) | public SetGeopointAction getSetGeopointAction() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/ServerPreferencesAdder.java
  class ServerPreferencesAdder (line 28) | public class ServerPreferencesAdder {
    method ServerPreferencesAdder (line 32) | public ServerPreferencesAdder(PreferenceFragmentCompat fragment) {
    method add (line 36) | public boolean add() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/dialogs/ResetDialogPreference.java
  class ResetDialogPreference (line 26) | public class ResetDialogPreference extends DialogPreference {
    method ResetDialogPreference (line 28) | public ResetDialogPreference(Context context, AttributeSet attrs) {
    method getDialogLayoutResource (line 32) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/dialogs/ResetDialogPreferenceFragmentCompat.java
  class ResetDialogPreferenceFragmentCompat (line 34) | public class ResetDialogPreferenceFragmentCompat extends PreferenceDialo...
    method newInstance (line 47) | public static ResetDialogPreferenceFragmentCompat newInstance(String k...
    method onAttach (line 55) | @Override
    method onBindDialogView (line 63) | @Override
    method onStart (line 78) | @Override
    method onDetach (line 84) | @Override
    method onClick (line 94) | @Override
    method onDialogClosed (line 101) | @Override
    method resetSelected (line 105) | private void resetSelected() {
    method handleResult (line 147) | private void handleResult(final List<Integer> resetActions, List<Integ...
    method onCheckedChanged (line 217) | @Override
    method adjustResetButtonAccessibility (line 222) | public void adjustResetButtonAccessibility() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/dialogs/ServerAuthDialogFragment.java
  class ServerAuthDialogFragment (line 22) | public class ServerAuthDialogFragment extends DialogFragment {
    method onAttach (line 29) | @Override
    method onCreateDialog (line 35) | @NonNull
    method getDialogView (line 56) | public View getDialogView() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/filters/ControlCharacterFilter.java
  class ControlCharacterFilter (line 9) | public class ControlCharacterFilter implements InputFilter {
    method filter (line 10) | public CharSequence filter(CharSequence source, int start, int end,

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/BaseAdminPreferencesFragment.java
  class BaseAdminPreferencesFragment (line 12) | public abstract class BaseAdminPreferencesFragment extends BasePreferenc...
    method onAttach (line 17) | @Override
    method onCreatePreferences (line 24) | @Override
    method onResume (line 29) | @Override
    method onPause (line 35) | @Override
    method onSettingChanged (line 41) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/BaseProjectPreferencesFragment.java
  class BaseProjectPreferencesFragment (line 21) | public abstract class BaseProjectPreferencesFragment extends BasePrefere...
    method onAttach (line 36) | @Override
    method onCreatePreferences (line 46) | @Override
    method onViewCreated (line 51) | @Override
    method onResume (line 57) | @Override
    method onPause (line 63) | @Override
    method onSettingChanged (line 69) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/ExperimentalPreferencesFragment.java
  class ExperimentalPreferencesFragment (line 15) | public class ExperimentalPreferencesFragment extends BaseProjectPreferen...
    method onCreatePreferences (line 17) | @Override
    method onViewCreated (line 34) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/FormManagementPreferencesFragment.java
  class FormManagementPreferencesFragment (line 48) | public class FormManagementPreferencesFragment extends BaseProjectPrefer...
    method onAttach (line 56) | @Override
    method onCreatePreferences (line 62) | @Override
    method onSettingChanged (line 77) | @Override
    method updateDisabledPrefs (line 90) | private void updateDisabledPrefs() {
    method initListPref (line 126) | private void initListPref(String key) {
    method initPref (line 143) | private void initPref(String key) {
    method initGuidancePrefs (line 156) | private void initGuidancePrefs() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/FormMetadataPreferencesFragment.java
  class FormMetadataPreferencesFragment (line 27) | public class FormMetadataPreferencesFragment extends BaseProjectPreferen...
    method onAttach (line 35) | @Override
    method onCreatePreferences (line 41) | @Override
    method onActivityCreated (line 51) | @Override
    method setupPrefs (line 58) | private void setupPrefs() {
    class PropertyManagerPropertySummaryProvider (line 78) | private class PropertyManagerPropertySummaryProvider implements Prefer...
      method PropertyManagerPropertySummaryProvider (line 83) | PropertyManagerPropertySummaryProvider(PropertyManager propertyManag...
      method provideSummary (line 88) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/ServerPreferencesFragment.java
  class ServerPreferencesFragment (line 38) | public class ServerPreferencesFragment extends BaseProjectPreferencesFra...
    method onAttach (line 44) | @Override
    method onCreatePreferences (line 50) | @Override
    method addServerPreferences (line 57) | public void addServerPreferences() {
    method createChangeListener (line 83) | private Preference.OnPreferenceChangeListener createChangeListener() {
    method maskPasswordSummary (line 125) | private void maskPasswordSummary(String password) {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/UserInterfacePreferencesFragment.java
  class UserInterfacePreferencesFragment (line 38) | public class UserInterfacePreferencesFragment extends BaseProjectPrefere...
    method onAttach (line 47) | @Override
    method onCreatePreferences (line 58) | @Override
    method initNavigationPrefs (line 68) | private void initNavigationPrefs() {
    method initFontSizePref (line 82) | private void initFontSizePref() {
    method initLanguagePrefs (line 96) | private void initLanguagePrefs() {

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/screens/UserSettingsAccessPreferencesFragment.java
  class UserSettingsAccessPreferencesFragment (line 7) | public class UserSettingsAccessPreferencesFragment extends BaseAdminPref...
    method onCreatePreferences (line 9) | @Override

FILE: collect_app/src/main/java/org/odk/collect/android/preferences/utilities/PreferencesUtils.java
  class PreferencesUtils (line 6) | public final class PreferencesUtils {
    method PreferencesUtils (line 8) | private PreferencesUtils() {
    method displayDisabled (line 12) | public static void displayDisabled(CheckBoxPreference preference, bool...
    method displayDisabled (line 19) | public static void displayDisabled(Preference preference, String displ...

FILE: collect_app/src/main/java/org/odk/collect/android/storage/StorageSubdirectory.java
  type StorageSubdirectory (line 3) | public enum StorageSubdirectory {
    method StorageSubdirectory (line 15) | StorageSubdirectory(String directoryName) {
    method getDirectoryName (line 19) | public String getDirectoryName() {

FILE: collect_app/src/main/java/org/odk/collect/android/tasks/DownloadFormListTask.java
  class DownloadFormListTask (line 52) | @Deprecated
    method DownloadFormListTask (line 74) | public DownloadFormListTask() {
    method doInBackground (line 83) | @Override
    method onPostExecute (line 107) | @Override
    method setDownloaderListener (line 125) | public void setDownloaderListener(FormListDownloaderListener sl) {
    method setAlternateCredentials (line 131) | public void setAlternateCredentials(WebCredentialsUtils webCredentials...
    method setTemporaryCredentials (line 145) | private void setTemporaryCredentials() {
    method clearTemporaryCredentials (line 159) | private void clearTemporaryCredentials() {

FILE: collect_app/src/main/java/org/odk/collect/android/tasks/DownloadFormsTask.java
  class DownloadFormsTask (line 40) | public class DownloadFormsTask extends
    method DownloadFormsTask (line 47) | public DownloadFormsTask(String projectId, FormsDataService formsDataS...
    method doInBackground (line 52) | @Override
    method onCancelled (line 67) | @Override
    method onPostExecute (line 76) | @Override
    method onProgressUpdate (line 85) | @Override
    method setDownloaderListener (line 98) | public void setDownloaderListener(DownloadFormsTaskListener sl) {

FILE: collect_app/src/main/java/org/odk/collect/android/tasks/FormLoaderTask.java
  class FormLoaderTask (line 83) | public class FormLoaderTask extends SchedulerAsyncTaskMimic<Void, String...
    method onPreExecute (line 106) | @Override
    method getInstancePath (line 111) | public String getInstancePath() {
    method getForm (line 115) | public Form getForm() {
    method getInstance (line 119) | public Instance getInstance() {
    class FECWrapper (line 123) | public static class FECWrapper {
      method FECWrapper (line 127) | protected FECWrapper(FormController controller, boolean usedSavepoin...
      method getController (line 132) | public FormController getController() {
      method hasUsedSavepoint (line 136) | protected boolean hasUsedSavepoint() {
      method free (line 140) | protected void free() {
    method FormLoaderTask (line 147) | public FormLoaderTask(Uri uri, String uriMimeType, String xpath, Strin...
    method doInBackground (line 163) | @Override
    method logFormDetails (line 285) | private void logFormDetails(File formFile, File formMediaDir) {
    method unzipMediaFiles (line 314) | private static void unzipMediaFiles(File formMediaDir) {
    method createFormDefFromCacheOrXml (line 333) | private FormDef createFormDefFromCacheOrXml(String formPath, File form...
    method processItemSets (line 366) | private void processItemSets(File formMediaDir) {
    method initializeForm (line 405) | private boolean initializeForm(FormDef formDef, FormEntryController fe...
    method onProgressUpdate (line 449) | @Override
    method importData (line 461) | public static void importData(File instanceFile, FormEntryController f...
    method onCancelled (line 504) | @Override
    method onPostExecute (line 511) | @Override
    method setFormLoaderListener (line 528) | public void setFormLoaderListener(FormLoaderListener sl) {
    method getFormController (line 534) | public FormController getFormController() {
    method hasUsedSavepoint (line 538) | public boolean hasUsedSavepoint() {
    method destroy (line 542) | public void destroy() {
    method hasPendingActivityResult (line 549) | public boolean hasPendingActivityResult() {
    method getRequestCode (line 553) | public int getRequestCode() {
    method getResultCode (line 557) | public int getResultCode() {
    method getIntent (line 561) | public Intent getIntent() {
    method setActivityResult (line 565) | public void setActivityResult(int requestCode, int resultCode, Intent ...
    method readCSV (line 572) | private void readCSV(File csv, String formHash, String pathHash) {
    method getFormDef (line 615) | public FormDef getFormDef() {
    type FormEntryControllerFactory (line 619) | public interface FormEntryControllerFactory {
      method create (line 620) | FormEntryController create(@NonNull FormDef formDef, @NonNull File f...

FILE: collect_app/src/main/java/org/odk/collect/android/tasks/InstanceUploaderTask.java
  class InstanceUploaderTask (line 58) | public class InstanceUploaderTask extends AsyncTask<Long, Integer, Insta
Copy disabled (too large) Download .json
Condensed preview — 2434 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (12,983K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 13777,
    "preview": "# This config and the the Gradle flags/opts are based on: https://circleci.com/docs/2.0/language-android/\n# and https://"
  },
  {
    "path": ".circleci/generate-app-test-list.sh",
    "chars": 295,
    "preview": "ls -R collect_app/src/test/java/ | grep Test.java > .circleci/collect_app_test_files.txt\nls -R collect_app/src/test/java"
  },
  {
    "path": ".circleci/gradle-large.properties",
    "chars": 271,
    "preview": "# Gradle config for \"X-Large\" Circle CI resource (https://circleci.com/pricing/price-list/)\n\norg.gradle.jvmargs=-Xmx8g -"
  },
  {
    "path": ".circleci/gradle.properties",
    "chars": 235,
    "preview": "# Gradle config for \"Large\" Circle CI resource (https://circleci.com/pricing/price-list/)\n\norg.gradle.jvmargs=-Xmx2560m "
  },
  {
    "path": ".circleci/test_modules.txt",
    "chars": 270,
    "preview": "shared\nforms-test\nandroidshared\nasync\nstrings\naudio-clips\naudio-recorder\nprojects\nlocation\ngeo\nupgrade\npermissions\nsetti"
  },
  {
    "path": ".editorconfig",
    "chars": 1481,
    "preview": "root = true\n\n[*.{kt,kts}]\nktlint_standard_no-blank-lines-in-chained-method-calls = disabled\nktlint_standard_trailing-com"
  },
  {
    "path": ".gitattributes",
    "chars": 10,
    "preview": "* text=lf\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 124,
    "preview": "Please refer to the project-wide [ODK Code of Conduct](https://github.com/getodk/governance/blob/master/CODE-OF-CONDUCT."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 424,
    "preview": "blank_issues_enabled: true\ncontact_links: \n  - name: \"Report an issue\"\n    about: \"For when Collect is behaving in an un"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1162,
    "preview": "<!-- \n\nThank you for taking the time to report an ODK Collect issue!\n\nThis space is for bugs that have clear reproductio"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1491,
    "preview": "Closes #\n\n<!-- \nThank you for contributing to ODK Collect!\n\nBefore sending this PR, please read\nhttps://github.com/getod"
  },
  {
    "path": ".github/TESTING_RESULT_TEMPLATES.md",
    "chars": 475,
    "preview": "# Testing result templates\n\n## Tested with success!\n#### Verified on: [List of devices/os versions]\n#### Verified cases:"
  },
  {
    "path": ".gitignore",
    "chars": 778,
    "preview": "build\n.gradle\n.idea\n.kotlin\nlocal.properties\n*.iml\n.DS_Store\n*.sublime-project\n\n# emacs backup files\n*.*~\n\n# gradle env "
  },
  {
    "path": ".hgtags",
    "chars": 5792,
    "preview": "5836a17a0e6f28b4e5b7a7abc9152446f4806ee2 v1.0.0\n30d9314729db181177bb7209d1c16cd65a5095eb v1.1.0\n827cf67bd902b80c37dce8d4"
  },
  {
    "path": "LICENSE.md",
    "chars": 10426,
    "preview": "Apache License\n==============\n\n_Version 2.0, January 2004_  \n_&lt;<http://www.apache.org/licenses/>&gt;_\n\n### Terms and "
  },
  {
    "path": "README.md",
    "chars": 21484,
    "preview": "# ODK Collect\n\n![Platform](https://img.shields.io/badge/platform-Android-blue.svg)\n[![License](https://img.shields.io/ba"
  },
  {
    "path": "SECURITY.md",
    "chars": 116,
    "preview": "# Security Policy\n\n## Reporting a Vulnerability\n\nSee our [Vulnerability Disclosure Policy](https://getodk.org/vdp).\n"
  },
  {
    "path": "analytics/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "analytics/build.gradle.kts",
    "chars": 877,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n}\n\napply(from = \"../config/quality.gradle\")\n\nandroid {\n    compileSdk ="
  },
  {
    "path": "analytics/proguard-rules.pro",
    "chars": 751,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "analytics/src/main/AndroidManifest.xml",
    "chars": 336,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-"
  },
  {
    "path": "analytics/src/main/java/org/odk/collect/analytics/Analytics.kt",
    "chars": 1561,
    "preview": "package org.odk.collect.analytics\n\ninterface Analytics {\n    fun logEvent(event: String)\n    fun logEventWithParam(event"
  },
  {
    "path": "analytics/src/main/java/org/odk/collect/analytics/BlockableFirebaseAnalytics.kt",
    "chars": 1279,
    "preview": "package org.odk.collect.analytics\n\nimport android.app.Application\nimport android.os.Bundle\nimport com.google.firebase.an"
  },
  {
    "path": "analytics/src/main/java/org/odk/collect/analytics/NoopAnalytics.kt",
    "chars": 442,
    "preview": "package org.odk.collect.analytics\n\nclass NoopAnalytics : Analytics {\n    override fun logEvent(event: String) {}\n    ove"
  },
  {
    "path": "androidshared/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "androidshared/build.gradle.kts",
    "chars": 2128,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n    alias(libs.plugins.kotlinKsp)\n    alias(libs.plugins.composeCompile"
  },
  {
    "path": "androidshared/src/androidTest/java/org/odk/collect/androidshared/bitmap/ImageCompressorTest.kt",
    "chars": 7838,
    "preview": "/*\n * Copyright 2017 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/androidTest/java/org/odk/collect/androidshared/bitmap/ImageFileUtilsTest.kt",
    "chars": 9474,
    "preview": "/*\n * Copyright 2017 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/main/AndroidManifest.xml",
    "chars": 328,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/async/TrackableWorker.kt",
    "chars": 1149,
    "preview": "package org.odk.collect.androidshared.async\n\nimport org.odk.collect.androidshared.livedata.MutableNonNullLiveData\nimport"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/bitmap/ImageCompressor.kt",
    "chars": 4573,
    "preview": "/*\n * Copyright 2017 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/bitmap/ImageFileUtils.kt",
    "chars": 7272,
    "preview": "package org.odk.collect.androidshared.bitmap\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.CompressForm"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/data/AppState.kt",
    "chars": 2615,
    "preview": "package org.odk.collect.androidshared.data\n\nimport android.app.Activity\nimport android.app.Application\nimport android.ap"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/data/Consumable.kt",
    "chars": 733,
    "preview": "package org.odk.collect.androidshared.data\n\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LiveData\n"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/data/Data.kt",
    "chars": 2967,
    "preview": "package org.odk.collect.androidshared.data\n\nimport kotlinx.coroutines.flow.StateFlow\nimport org.odk.collect.androidshare"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/livedata/LiveDataExt.kt",
    "chars": 945,
    "preview": "package org.odk.collect.androidshared.livedata\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MediatorLiv"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/livedata/LiveDataUtils.java",
    "chars": 3102,
    "preview": "package org.odk.collect.androidshared.livedata;\n\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MediatorL"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/livedata/NonNullLiveData.kt",
    "chars": 563,
    "preview": "package org.odk.collect.androidshared.livedata\n\nimport androidx.lifecycle.LiveData\n\n/**\n * Allows creating LiveData valu"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/BroadcastReceiverRegister.kt",
    "chars": 690,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nim"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/CameraUtils.java",
    "chars": 2318,
    "preview": "package org.odk.collect.androidshared.system;\n\n/*\nCopyright 2018 Theodoros Tyrovouzis\n\nLicensed under the Apache License"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/ContextExt.kt",
    "chars": 943,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.app.Activity\nimport android.content.Context\nimport android."
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/ExternalFilesUtils.kt",
    "chars": 1096,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.content.Context\nimport java.io.File\nimport java.io.IOExcept"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/IntentLauncher.kt",
    "chars": 1522,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.app.Activity\nimport android.content.Context\nimport android."
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/OpenGLVersionChecker.kt",
    "chars": 1148,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.app.ActivityManager\nimport android.content.Context\n\n/**\n * "
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/PlayServicesChecker.java",
    "chars": 1084,
    "preview": "package org.odk.collect.androidshared.system;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com."
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/ProcessRestoreDetector.kt",
    "chars": 886,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.content.Context\nimport android.os.Bundle\nimport org.odk.col"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/system/UriExt.kt",
    "chars": 3150,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.content.ContentResolver\nimport android.content.Context\nimpo"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/AlertStore.kt",
    "chars": 613,
    "preview": "package org.odk.collect.androidshared.ui\n\n/**\n * Component for recording \"alerts\". This is useful for testing transient "
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/Animations.kt",
    "chars": 2456,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.animation.Animator\nimport android.animation.AnimatorSet\nimport "
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ColorPickerDialog.kt",
    "chars": 5016,
    "preview": "package org.odk.collect.androidshared\n\nimport android.app.Dialog\nimport android.graphics.Color\nimport android.graphics.d"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ComposeThemeProvider.kt",
    "chars": 1787,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.platform"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/DialogFragmentUtils.kt",
    "chars": 3165,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.os.Bundle\nimport androidx.fragment.app.DialogFragment\nimport an"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/DialogUtils.kt",
    "chars": 548,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.content.Context\nimport androidx.annotation.StringRes\nimport com"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/DisplayString.kt",
    "chars": 398,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.content.Context\n\nsealed class DisplayString {\n\n    data class R"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/EdgeToEdge.kt",
    "chars": 2449,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.app.Activity\nimport android.content.Context\nimport android.view"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/FragmentFactoryBuilder.kt",
    "chars": 1361,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentFac"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/GroupClickListener.kt",
    "chars": 540,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.view.View\nimport androidx.constraintlayout.widget.Group\n\n// htt"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ListFragmentStateAdapter.kt",
    "chars": 710,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentAct"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/MenuExt.kt",
    "chars": 502,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.annotation.SuppressLint\nimport android.view.Menu\nimport android"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt",
    "chars": 1430,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.content.Context\nimport android.os.Handler\nimport android.util.A"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/OneSignTextWatcher.kt",
    "chars": 872,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.text.Editable\nimport android.text.TextWatcher\nimport android.wi"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/PrefUtils.kt",
    "chars": 2224,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.content.Context\nimport androidx.preference.ListPreference\nimpor"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ReturnToAppActivity.kt",
    "chars": 505,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.app.Activity\nimport android.os.Bundle\n\n/**\n * This Activity wil"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/SnackbarUtils.kt",
    "chars": 5733,
    "preview": "/*\n\nCopyright 2018 Shobhit\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file exc"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/ToastUtils.kt",
    "chars": 2921,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.app.Activity\nimport android.app.Application\nimport android.os.B"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/compose/Margins.kt",
    "chars": 517,
    "preview": "package org.odk.collect.androidshared.ui.compose\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui."
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/DoubleClickSafeMaterialButton.kt",
    "chars": 723,
    "preview": "package org.odk.collect.androidshared.ui.multiclicksafe\n\nimport android.content.Context\nimport android.util.AttributeSet"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickGuard.kt",
    "chars": 1525,
    "preview": "package org.odk.collect.androidshared.ui.multiclicksafe\n\nimport android.os.SystemClock\n\nobject MultiClickGuard {\n    @Jv"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSafeMaterialButton.kt",
    "chars": 929,
    "preview": "package org.odk.collect.androidshared.ui.multiclicksafe\n\nimport android.content.Context\nimport android.util.AttributeSet"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSafeTextInputEditText.kt",
    "chars": 585,
    "preview": "package org.odk.collect.androidshared.ui.multiclicksafe\n\nimport android.content.Context\nimport android.util.AttributeSet"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/ui/multiclicksafe/MultiClickSaveOnClickListener.kt",
    "chars": 542,
    "preview": "package org.odk.collect.androidshared.ui.multiclicksafe\n\nimport android.view.View\n\nabstract class MultiClickSafeOnClickL"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/AppBarUtils.kt",
    "chars": 532,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport android.app.Activity\nimport androidx.appcompat.app.AppCompatActivity"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/ColorUtils.kt",
    "chars": 768,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport androidx.annotation.ColorInt\nimport androidx.core.graphics.ColorUtil"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/CompressionUtils.kt",
    "chars": 2648,
    "preview": "/*\n * Copyright (C) 2017 Shobhit\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use t"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/FileExt.kt",
    "chars": 595,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport androi"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/InMemUniqueIdGenerator.kt",
    "chars": 366,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass InMemUniqueIdGenera"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/PathUtils.kt",
    "chars": 1215,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport org.odk.collect.shared.files.FileExt.sanitizedCanonicalPath\nimport t"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/PreferenceFragmentCompatUtils.kt",
    "chars": 254,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport androidx.preference.Preference\nimport androidx.preference.Preference"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/ScreenUtils.java",
    "chars": 1635,
    "preview": "/*\n * Copyright 2019 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/SettingsUniqueIdGenerator.kt",
    "chars": 1071,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport org.odk.collect.shared.settings.Settings\n\nclass SettingsUniqueIdGene"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/UniqueIdGenerator.kt",
    "chars": 117,
    "preview": "package org.odk.collect.androidshared.utils\n\ninterface UniqueIdGenerator {\n    fun getInt(identifier: String): Int\n}\n"
  },
  {
    "path": "androidshared/src/main/java/org/odk/collect/androidshared/utils/Validator.kt",
    "chars": 1419,
    "preview": "/*\n * Copyright 2016 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/main/res/color/color_error_button_icon.xml",
    "chars": 294,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "androidshared/src/main/res/color/color_on_primary_low_emphasis.xml",
    "chars": 416,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\nProvides a medium emphasis version of the `colorOnPrimary` Material Theming"
  },
  {
    "path": "androidshared/src/main/res/color/color_on_surface_high_emphasis.xml",
    "chars": 520,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\nProvides a medium emphasis version of the `colorOnSurface` Material Theming"
  },
  {
    "path": "androidshared/src/main/res/color/color_on_surface_low_emphasis.xml",
    "chars": 519,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\nProvides a medium emphasis version of the `colorOnSurface` Material Theming"
  },
  {
    "path": "androidshared/src/main/res/color/color_on_surface_medium_emphasis.xml",
    "chars": 522,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\nProvides a medium emphasis version of the `colorOnSurface` Material Theming"
  },
  {
    "path": "androidshared/src/main/res/color/color_primary_low_emphasis.xml",
    "chars": 515,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\nProvides a medium emphasis version of the `colorPrimary` Material Theming a"
  },
  {
    "path": "androidshared/src/main/res/drawable/color_circle.xml",
    "chars": 132,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "androidshared/src/main/res/drawable/ic_close_24.xml",
    "chars": 408,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n  "
  },
  {
    "path": "androidshared/src/main/res/drawable/list_item_divider.xml",
    "chars": 424,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--"
  },
  {
    "path": "androidshared/src/main/res/drawable/radio_button_inset.xml",
    "chars": 246,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:dra"
  },
  {
    "path": "androidshared/src/main/res/drawable/shadow_up.xml",
    "chars": 449,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item"
  },
  {
    "path": "androidshared/src/main/res/layout/app_bar_layout.xml",
    "chars": 2391,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     When scrolling, the top app bar fills with a contrasting color to creat"
  },
  {
    "path": "androidshared/src/main/res/layout/color_picker_dialog_layout.xml",
    "chars": 16380,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:"
  },
  {
    "path": "androidshared/src/main/res/values/attrs.xml",
    "chars": 200,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"MultiClickSafeMaterialButton\">\n        <"
  },
  {
    "path": "androidshared/src/main/res/values/color_picker_dialog_colors.xml",
    "chars": 719,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Color picker palette -->\n    <color name=\"color1\">#EA4633</c"
  },
  {
    "path": "androidshared/src/main/res/values/dimens.xml",
    "chars": 676,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- \"Standard\" set of margin sizes for Android (pre and post Mat"
  },
  {
    "path": "androidshared/src/main/res/values/styles.xml",
    "chars": 397,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"Widget.AndroidShared.ButtonBar\" parent=\"\">\n        <"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/async/TrackableWorkerTest.kt",
    "chars": 891,
    "preview": "package org.odk.collect.androidshared.async\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Co"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/livedata/LiveDataUtilsTest.kt",
    "chars": 1650,
    "preview": "package org.odk.collect.androidshared.livedata\n\nimport androidx.arch.core.executor.testing.InstantTaskExecutorRule\nimpor"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/system/UriExtTest.kt",
    "chars": 1383,
    "preview": "package org.odk.collect.androidshared.system\n\nimport android.app.Application\nimport androidx.core.net.toUri\nimport andro"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/ui/ColorPickerDialogTest.kt",
    "chars": 5052,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.graphics.Color\nimport android.graphics.drawable.GradientDrawabl"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/ui/OneSignTextWatcherTest.kt",
    "chars": 932,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport android.widget.EditText\nimport androidx.test.platform.app.Instrumentati"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/ui/ReturnToAppActivityTest.kt",
    "chars": 622,
    "preview": "package org.odk.collect.androidshared.ui\n\nimport androidx.lifecycle.Lifecycle\nimport androidx.test.ext.junit.rules.Activ"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/ColorUtilsTest.kt",
    "chars": 1291,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Ma"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/CompressionUtilsTest.kt",
    "chars": 1946,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Ma"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/DialogFragmentUtilsTest.java",
    "chars": 2465,
    "preview": "package org.odk.collect.androidshared.utils;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.ham"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/InMemUniqueIdGeneratorTest.kt",
    "chars": 207,
    "preview": "package org.odk.collect.androidshared.utils\n\nclass InMemUniqueIdGeneratorTest : UniqueIdGeneratorTest() {\n    override f"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/IntentLauncherImplTest.kt",
    "chars": 4202,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport android.app.Activity\nimport android.content.Context\nimport android.c"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/PathUtilsTest.kt",
    "chars": 1463,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers.e"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/SettingsUniqueIdGeneratorTest.kt",
    "chars": 1346,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers.e"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/UniqueIdGeneratorTest.kt",
    "chars": 729,
    "preview": "package org.odk.collect.androidshared.utils\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers.e"
  },
  {
    "path": "androidshared/src/test/java/org/odk/collect/androidshared/utils/ValidatorTest.kt",
    "chars": 6234,
    "preview": "/*\n * Copyright 2017 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "androidshared/src/test/resources/robolectric.properties",
    "chars": 7,
    "preview": "sdk=33\n"
  },
  {
    "path": "androidtest/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "androidtest/README.md",
    "chars": 218,
    "preview": "# androidtest\n\nIncludes helpers (arguably missing from `androidx.test:core`) for writing [\"Local tests\" and \"Instrumente"
  },
  {
    "path": "androidtest/build.gradle.kts",
    "chars": 1466,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n}\n\napply(from = \"../config/quality.gradle\")\n\nandroid {\n    compileSdk ="
  },
  {
    "path": "androidtest/src/main/AndroidManifest.xml",
    "chars": 122,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</manifest"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/ActivityScenarioExtensions.kt",
    "chars": 944,
    "preview": "package org.odk.collect.androidtest\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.os.PersistableB"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/ActivityScenarioLauncherRule.kt",
    "chars": 1571,
    "preview": "package org.odk.collect.androidtest\n\nimport android.app.Activity\nimport android.content.Intent\nimport androidx.test.core"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/DrawableMatcher.kt",
    "chars": 2780,
    "preview": "package org.odk.collect.androidtest\n\nimport android.app.Application\nimport android.graphics.Bitmap\nimport android.graphi"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/FakeLifecycleOwner.kt",
    "chars": 547,
    "preview": "package org.odk.collect.androidtest\n\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleOwner\nimport"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/FragmentScenarioExtensions.kt",
    "chars": 494,
    "preview": "package org.odk.collect.androidtest\n\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentResultLi"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/LiveDataTestUtils.kt",
    "chars": 1636,
    "preview": "package org.odk.collect.androidtest\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.Observer\nimport java.u"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/MainDispatcherRule.kt",
    "chars": 884,
    "preview": "package org.odk.collect.androidtest\n\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.ExperimentalCorouti"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/NodeInteractionExtensions.kt",
    "chars": 1029,
    "preview": "package org.odk.collect.androidtest\n\nimport android.app.Application\nimport androidx.annotation.StringRes\nimport androidx"
  },
  {
    "path": "androidtest/src/main/java/org/odk/collect/androidtest/RecordedIntentsRule.kt",
    "chars": 967,
    "preview": "package org.odk.collect.androidtest\n\nimport androidx.test.core.app.ActivityScenario\nimport androidx.test.espresso.intent"
  },
  {
    "path": "async/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "async/build.gradle.kts",
    "chars": 1400,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n}\n\napply(from = \"../config/quality.gradle\")\n\nandroid {\n    compileSdk ="
  },
  {
    "path": "async/proguard-rules.pro",
    "chars": 750,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "async/src/main/AndroidManifest.xml",
    "chars": 557,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/Cancellable.kt",
    "chars": 83,
    "preview": "package org.odk.collect.async\n\ninterface Cancellable {\n    fun cancel(): Boolean\n}\n"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/OngoingWorkListener.kt",
    "chars": 860,
    "preview": "/*\n * Copyright 2018 Nafundi\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/Scheduler.kt",
    "chars": 4026,
    "preview": "package org.odk.collect.async\n\nimport androidx.annotation.StringRes\nimport kotlinx.coroutines.flow.Flow\nimport java.util"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/SchedulerAsyncTaskMimic.kt",
    "chars": 2281,
    "preview": "package org.odk.collect.async\n\nimport android.os.AsyncTask\n\n/**\n * Basic reimplementation of the [AsyncTask] API that al"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/SchedulerBuilder.kt",
    "chars": 2910,
    "preview": "package org.odk.collect.async\n\nimport kotlinx.coroutines.flow.Flow\nimport java.util.function.Consumer\nimport java.util.f"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/ScopeCancellable.kt",
    "chars": 278,
    "preview": "package org.odk.collect.async\n\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.cancel\n\ninternal class"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/TaskRunner.kt",
    "chars": 450,
    "preview": "package org.odk.collect.async\n\nimport kotlinx.coroutines.Runnable\nimport kotlinx.coroutines.flow.Flow\nimport java.util.f"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/TaskSpec.kt",
    "chars": 1881,
    "preview": "package org.odk.collect.async\n\nimport android.content.Context\nimport androidx.work.BackoffPolicy\nimport java.util.functi"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/TaskSpecRunner.kt",
    "chars": 173,
    "preview": "package org.odk.collect.async\n\ninterface TaskSpecRunner {\n    fun run(tag: String, taskSpec: TaskSpec, inputData: Map<St"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/TaskSpecScheduler.kt",
    "chars": 354,
    "preview": "package org.odk.collect.async\n\ninterface TaskSpecScheduler {\n    fun schedule(\n        tag: String,\n        spec: TaskSp"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/coroutines/CoroutineTaskRunner.kt",
    "chars": 1963,
    "preview": "package org.odk.collect.async.coroutines\n\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/network/ConnectivityProvider.kt",
    "chars": 917,
    "preview": "package org.odk.collect.async.network\n\nimport android.content.Context\nimport android.net.ConnectivityManager\nimport org."
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/network/NetworkStateProvider.kt",
    "chars": 262,
    "preview": "package org.odk.collect.async.network\n\nimport org.odk.collect.async.Scheduler\n\ninterface NetworkStateProvider {\n    val "
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/services/ForegroundServiceTaskSpecRunner.kt",
    "chars": 4571,
    "preview": "package org.odk.collect.async.services\n\nimport android.app.Application\nimport android.app.NotificationChannel\nimport and"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/workmanager/TaskSpecWorker.kt",
    "chars": 1891,
    "preview": "package org.odk.collect.async.workmanager\n\nimport android.content.Context\nimport androidx.work.Worker\nimport androidx.wo"
  },
  {
    "path": "async/src/main/java/org/odk/collect/async/workmanager/WorkManagerTaskSpecScheduler.kt",
    "chars": 3829,
    "preview": "package org.odk.collect.async.workmanager\n\nimport android.net.NetworkCapabilities\nimport android.net.NetworkRequest\nimpo"
  },
  {
    "path": "async/src/test/java/org/odk/collect/async/TaskSpecTest.kt",
    "chars": 1009,
    "preview": "package org.odk.collect.async\n\nimport android.content.Context\nimport androidx.work.BackoffPolicy\nimport org.hamcrest.Mat"
  },
  {
    "path": "async/src/test/java/org/odk/collect/async/workmanager/TaskSpecWorkerTest.kt",
    "chars": 5612,
    "preview": "package org.odk.collect.async.workmanager\n\nimport android.content.Context\nimport androidx.test.core.app.ApplicationProvi"
  },
  {
    "path": "audio-clips/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "audio-clips/build.gradle.kts",
    "chars": 1405,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n}\n\napply(from = \"../config/quality.gradle\")\n\nandroid {\n    compileSdk ="
  },
  {
    "path": "audio-clips/src/main/AndroidManifest.xml",
    "chars": 88,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    /\n</manifest>"
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/AudioClipViewModel.kt",
    "chars": 6797,
    "preview": "package org.odk.collect.audioclips\n\nimport android.media.MediaPlayer\nimport androidx.lifecycle.LiveData\nimport androidx."
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/AudioPlayer.kt",
    "chars": 530,
    "preview": "package org.odk.collect.audioclips\n\nimport androidx.lifecycle.LiveData\nimport java.util.function.Consumer\n\ninterface Aud"
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/AudioPlayerFactory.kt",
    "chars": 265,
    "preview": "package org.odk.collect.audioclips\n\nimport androidx.activity.ComponentActivity\nimport androidx.lifecycle.LifecycleOwner\n"
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/Clip.kt",
    "chars": 89,
    "preview": "package org.odk.collect.audioclips\n\ndata class Clip(val clipID: String, val uRI: String)\n"
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/PlaybackFailedException.kt",
    "chars": 125,
    "preview": "package org.odk.collect.audioclips\n\ndata class PlaybackFailedException(val uRI: String, val exceptionMsg: Int) : Excepti"
  },
  {
    "path": "audio-clips/src/main/java/org/odk/collect/audioclips/ThreadSafeMediaPlayerWrapper.kt",
    "chars": 2260,
    "preview": "package org.odk.collect.audioclips\n\nimport android.media.MediaPlayer\nimport android.os.StrictMode\nimport java.io.IOExcep"
  },
  {
    "path": "audio-clips/src/test/java/org/odk/collect/audioclips/AudioClipViewModelTest.kt",
    "chars": 15921,
    "preview": "package org.odk.collect.audioclips\n\nimport android.media.MediaPlayer\nimport androidx.arch.core.executor.testing.InstantT"
  },
  {
    "path": "audio-recorder/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "audio-recorder/build.gradle.kts",
    "chars": 1821,
    "preview": "plugins {\n    alias(libs.plugins.androidLibrary)\n    alias(libs.plugins.kotlinKsp)\n}\n\napply(from = \"../config/quality.gr"
  },
  {
    "path": "audio-recorder/src/main/AndroidManifest.xml",
    "chars": 370,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/DaggerSetup.kt",
    "chars": 2962,
    "preview": "package org.odk.collect.audiorecorder\n\nimport android.app.Application\nimport android.media.MediaRecorder\nimport dagger.B"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/mediarecorder/MediaRecorderRecordingResource.kt",
    "chars": 2120,
    "preview": "package org.odk.collect.audiorecorder.mediarecorder\n\nimport android.media.MediaRecorder\nimport org.odk.collect.audioreco"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recorder/Recorder.kt",
    "chars": 490,
    "preview": "package org.odk.collect.audiorecorder.recorder\n\nimport org.odk.collect.audiorecorder.recording.MicInUseException\nimport "
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recorder/RecordingResource.kt",
    "chars": 515,
    "preview": "package org.odk.collect.audiorecorder.recorder\n\nimport java.io.IOException\n\n/**\n * Allows faking/stubbing/mocking with o"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recorder/RecordingResourceRecorder.kt",
    "chars": 2139,
    "preview": "package org.odk.collect.audiorecorder.recorder\n\nimport org.odk.collect.audiorecorder.recording.MicInUseException\nimport "
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/AudioRecorder.kt",
    "chars": 1130,
    "preview": "package org.odk.collect.audiorecorder.recording\n\nimport androidx.lifecycle.LiveData\nimport org.odk.collect.androidshared"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/AudioRecorderFactory.kt",
    "chars": 519,
    "preview": "package org.odk.collect.audiorecorder.recording\n\nimport android.app.Application\nimport org.odk.collect.androidshared.dat"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/AudioRecorderService.kt",
    "chars": 4590,
    "preview": "package org.odk.collect.audiorecorder.recording\n\nimport android.app.Application\nimport android.app.Service\nimport androi"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/internal/ForegroundServiceAudioRecorder.kt",
    "chars": 2798,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport android.app.Application\nimport android.content.Intent\ni"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/internal/RecordingForegroundServiceNotification.kt",
    "chars": 2799,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport android.app.NotificationChannel\nimport android.app.Noti"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/recording/internal/RecordingRepository.kt",
    "chars": 1822,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.M"
  },
  {
    "path": "audio-recorder/src/main/java/org/odk/collect/audiorecorder/testsupport/StubAudioRecorder.kt",
    "chars": 2955,
    "preview": "package org.odk.collect.audiorecorder.testsupport\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableL"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/mediarecorder/AMRRecordingResourceTest.kt",
    "chars": 1023,
    "preview": "package org.odk.collect.audiorecorder.mediarecorder\n\nimport android.media.MediaRecorder\nimport org.junit.Test\nimport org"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/recorder/RecordingResourceRecorderTest.kt",
    "chars": 7045,
    "preview": "package org.odk.collect.audiorecorder.recorder\n\nimport com.google.common.io.Files\nimport org.hamcrest.MatcherAssert.asse"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/recording/AudioRecorderTest.kt",
    "chars": 4552,
    "preview": "package org.odk.collect.audiorecorder.recording\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matche"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/recording/internal/AudioRecorderServiceTest.kt",
    "chars": 9920,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport android.app.Application\nimport android.content.Intent\ni"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/recording/internal/ForegroundServiceAudioRecorderTest.kt",
    "chars": 4984,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport android.app.Application\nimport androidx.arch.core.execu"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/recording/internal/RecordingForegroundServiceNotificationTest.kt",
    "chars": 1778,
    "preview": "package org.odk.collect.audiorecorder.recording.internal\n\nimport android.app.Application\nimport android.app.Notification"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/support/FakeRecorder.kt",
    "chars": 1770,
    "preview": "package org.odk.collect.audiorecorder.support\n\nimport org.odk.collect.audiorecorder.recorder.Output\nimport org.odk.colle"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/testsupport/RobolectricApplication.kt",
    "chars": 1389,
    "preview": "package org.odk.collect.audiorecorder.testsupport\n\nimport android.app.Application\nimport org.odk.collect.androidshared.d"
  },
  {
    "path": "audio-recorder/src/test/java/org/odk/collect/audiorecorder/testsupport/StubAudioRecorderTest.kt",
    "chars": 836,
    "preview": "package org.odk.collect.audiorecorder.testsupport\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.junit"
  },
  {
    "path": "audio-recorder/src/test/resources/robolectric.properties",
    "chars": 83,
    "preview": "application=org.odk.collect.audiorecorder.testsupport.RobolectricApplication\nsdk=33"
  },
  {
    "path": "benchmark.sh",
    "chars": 130,
    "preview": "./gradlew collect_app:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.package=org.odk.collect.android."
  },
  {
    "path": "build.gradle",
    "chars": 3487,
    "preview": "apply from: 'secrets.gradle'\n\n// Top-level build file where you can add configuration options common to all sub-projects"
  },
  {
    "path": "check-size.sh",
    "chars": 236,
    "preview": "set -e\n\nif [ $(ls -l collect_app/build/outputs/apk/selfSignedRelease/*.apk | awk '{print $5}') -gt $1 ];then\n  echo \"APK"
  },
  {
    "path": "codecov.yml",
    "chars": 159,
    "preview": "codecov:\n  notify:\n    require_ci_to_pass: no\ncoverage:\n  precision: 2\n  round: down\n  range: \"10...100\"\n  status:\n    p"
  },
  {
    "path": "collect_app/build.gradle",
    "chars": 16044,
    "preview": "plugins {\n    alias(libs.plugins.androidApplication)\n    alias(libs.plugins.kotlinKsp)\n    alias(libs.plugins.kotlinParc"
  },
  {
    "path": "collect_app/google-services.json",
    "chars": 1069,
    "preview": "{\n  \"project_info\": {\n    \"project_number\": \"640412404956\",\n    \"firebase_url\": \"https://opendatakit-forks.firebaseio.co"
  },
  {
    "path": "collect_app/proguard-rules.txt",
    "chars": 1422,
    "preview": "-dontwarn com.google.**\n-dontwarn au.com.bytecode.**\n-dontwarn org.joda.time.**\n-dontwarn org.osmdroid.**\n-dontwarn org."
  },
  {
    "path": "collect_app/src/androidTest/assets/instances/One Question_2021-06-22_15-55-50.xml",
    "chars": 284,
    "preview": "<?xml version='1.0' ?><data id=\"one_question\" orx:version=\"1\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" xmlns:orx=\"ht"
  },
  {
    "path": "collect_app/src/androidTest/assets/instances/one-question-google_2023-08-08_14-51-00.xml",
    "chars": 308,
    "preview": "<?xml version='1.0' encoding='UTF-8' ?><data id=\"one_question_google\" orx:version=\"1\" xmlns:ev=\"http://www.w3.org/2001/x"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/benchmark/EntitiesBenchmarkTest.kt",
    "chars": 4896,
    "preview": "package org.odk.collect.android.benchmark\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Matc"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/benchmark/FormsUpdateBenchmarkTest.kt",
    "chars": 2151,
    "preview": "package org.odk.collect.android.benchmark\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Matc"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/benchmark/SearchBenchmarkTest.kt",
    "chars": 2457,
    "preview": "package org.odk.collect.android.benchmark\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport org.hamcrest.Matc"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/benchmark/support/Benchmarker.kt",
    "chars": 1595,
    "preview": "package org.odk.collect.android.benchmark.support\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matc"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/feature/entitymanagement/ViewEntitiesTest.kt",
    "chars": 1814,
    "preview": "package org.odk.collect.android.feature.entitymanagement\n\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.r"
  },
  {
    "path": "collect_app/src/androidTest/java/org/odk/collect/android/feature/external/AndroidShortcutsTest.kt",
    "chars": 2616,
    "preview": "package org.odk.collect.android.feature.external\n\nimport android.content.Intent\nimport android.content.Intent.EXTRA_SHOR"
  }
]

// ... and 2234 more files (download for full content)

About this extraction

This page contains the full source code of the opendatakit/collect GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2434 files (11.5 MB), approximately 3.2M tokens, and a symbol index with 5828 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!