├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_x.png │ │ │ │ ├── body_back.png │ │ │ │ ├── body_front.png │ │ │ │ ├── ic_mm_logo.png │ │ │ │ ├── illo_mole.png │ │ │ │ ├── illo_name.png │ │ │ │ ├── button_undo.png │ │ │ │ ├── ic_flash_auto.png │ │ │ │ ├── ic_flash_off.png │ │ │ │ ├── ic_flash_on.png │ │ │ │ ├── ic_minus_16dp.png │ │ │ │ ├── ic_plus_16dp.png │ │ │ │ ├── button_capture.png │ │ │ │ ├── head_top_active.png │ │ │ │ ├── head_back_active.png │ │ │ │ ├── head_back_inactive.png │ │ │ │ ├── head_front_active.png │ │ │ │ ├── head_left_active.png │ │ │ │ ├── head_left_inactive.png │ │ │ │ ├── head_right_active.png │ │ │ │ ├── head_top_inactive.png │ │ │ │ ├── ic_action_toggle.png │ │ │ │ ├── ic_arrow_up_16dp.png │ │ │ │ ├── button_confirm_photo.png │ │ │ │ ├── head_front_inactive.png │ │ │ │ ├── head_right_inactive.png │ │ │ │ └── consent_section_withdraw.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── ic_x.png │ │ │ │ ├── body_back.png │ │ │ │ ├── body_front.png │ │ │ │ ├── ic_mm_logo.png │ │ │ │ ├── illo_mole.png │ │ │ │ ├── illo_name.png │ │ │ │ ├── button_undo.png │ │ │ │ ├── ic_flash_auto.png │ │ │ │ ├── ic_flash_off.png │ │ │ │ ├── ic_flash_on.png │ │ │ │ ├── ic_minus_16dp.png │ │ │ │ ├── ic_plus_16dp.png │ │ │ │ ├── button_capture.png │ │ │ │ ├── head_top_active.png │ │ │ │ ├── head_back_active.png │ │ │ │ ├── head_back_inactive.png │ │ │ │ ├── head_front_active.png │ │ │ │ ├── head_left_active.png │ │ │ │ ├── head_left_inactive.png │ │ │ │ ├── head_right_active.png │ │ │ │ ├── head_top_inactive.png │ │ │ │ ├── ic_action_toggle.png │ │ │ │ ├── ic_arrow_up_16dp.png │ │ │ │ ├── button_confirm_photo.png │ │ │ │ ├── head_front_inactive.png │ │ │ │ ├── head_right_inactive.png │ │ │ │ └── consent_section_withdraw.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── ic_x.png │ │ │ │ ├── body_back.png │ │ │ │ ├── illo_mole.png │ │ │ │ ├── illo_name.png │ │ │ │ ├── body_front.png │ │ │ │ ├── button_undo.png │ │ │ │ ├── ic_body_map.png │ │ │ │ ├── ic_flash_off.png │ │ │ │ ├── ic_flash_on.png │ │ │ │ ├── ic_mm_logo.png │ │ │ │ ├── ic_plus_16dp.png │ │ │ │ ├── button_capture.png │ │ │ │ ├── ic_action_add.png │ │ │ │ ├── ic_action_info.png │ │ │ │ ├── ic_flash_auto.png │ │ │ │ ├── ic_minus_16dp.png │ │ │ │ ├── head_back_active.png │ │ │ │ ├── head_front_active.png │ │ │ │ ├── head_left_active.png │ │ │ │ ├── head_right_active.png │ │ │ │ ├── head_top_active.png │ │ │ │ ├── head_top_inactive.png │ │ │ │ ├── ic_action_profile.png │ │ │ │ ├── ic_action_toggle.png │ │ │ │ ├── ic_arrow_up_16dp.png │ │ │ │ ├── ic_tabbar_moles.png │ │ │ │ ├── logo_institution.png │ │ │ │ ├── head_back_inactive.png │ │ │ │ ├── head_front_inactive.png │ │ │ │ ├── head_left_inactive.png │ │ │ │ ├── head_right_inactive.png │ │ │ │ ├── ic_action_add_24dp.png │ │ │ │ ├── ic_action_settings.png │ │ │ │ ├── ic_tabbar_dashboard.png │ │ │ │ ├── logo_disease_large.png │ │ │ │ ├── button_confirm_photo.png │ │ │ │ ├── ic_action_camera_24dp.png │ │ │ │ ├── ic_action_camera_48dp.png │ │ │ │ └── consent_section_withdraw.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_x.png │ │ │ │ ├── body_back.png │ │ │ │ ├── body_front.png │ │ │ │ ├── button_undo.png │ │ │ │ ├── ic_flash_on.png │ │ │ │ ├── ic_mm_logo.png │ │ │ │ ├── illo_mole.png │ │ │ │ ├── illo_name.png │ │ │ │ ├── ic_flash_auto.png │ │ │ │ ├── ic_flash_off.png │ │ │ │ ├── ic_minus_16dp.png │ │ │ │ ├── ic_plus_16dp.png │ │ │ │ ├── button_capture.png │ │ │ │ ├── head_back_active.png │ │ │ │ ├── head_left_active.png │ │ │ │ ├── head_top_active.png │ │ │ │ ├── ic_action_toggle.png │ │ │ │ ├── ic_arrow_up_16dp.png │ │ │ │ ├── head_back_inactive.png │ │ │ │ ├── head_front_active.png │ │ │ │ ├── head_left_inactive.png │ │ │ │ ├── head_right_active.png │ │ │ │ ├── head_top_inactive.png │ │ │ │ ├── button_confirm_photo.png │ │ │ │ ├── head_front_inactive.png │ │ │ │ ├── head_right_inactive.png │ │ │ │ └── consent_section_withdraw.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── ic_x.png │ │ │ │ ├── body_back.png │ │ │ │ ├── body_front.png │ │ │ │ ├── ic_mm_logo.png │ │ │ │ ├── illo_mole.png │ │ │ │ ├── illo_name.png │ │ │ │ ├── button_undo.png │ │ │ │ ├── ic_flash_off.png │ │ │ │ ├── ic_flash_on.png │ │ │ │ ├── ic_plus_16dp.png │ │ │ │ ├── button_capture.png │ │ │ │ ├── head_top_active.png │ │ │ │ ├── ic_flash_auto.png │ │ │ │ ├── ic_minus_16dp.png │ │ │ │ ├── head_back_active.png │ │ │ │ ├── head_front_active.png │ │ │ │ ├── head_left_active.png │ │ │ │ ├── head_right_active.png │ │ │ │ ├── head_top_inactive.png │ │ │ │ ├── ic_action_toggle.png │ │ │ │ ├── ic_arrow_up_16dp.png │ │ │ │ ├── button_confirm_photo.png │ │ │ │ ├── head_back_inactive.png │ │ │ │ ├── head_front_inactive.png │ │ │ │ ├── head_left_inactive.png │ │ │ │ ├── head_right_inactive.png │ │ │ │ └── consent_section_withdraw.png │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable │ │ │ │ ├── ic_arrow_left_24dp.xml │ │ │ │ ├── ic_place_black_24dp.xml │ │ │ │ ├── ic_image_multiple_24dp.xml │ │ │ │ ├── bg_measurement_scale.xml │ │ │ │ ├── bg_measurement_move.xml │ │ │ │ ├── ic_spinner_down_16dp.xml │ │ │ │ ├── head_back.xml │ │ │ │ ├── head_left.xml │ │ │ │ ├── head_top.xml │ │ │ │ ├── head_front.xml │ │ │ │ ├── head_right.xml │ │ │ │ ├── vic_check_20dp.xml │ │ │ │ ├── vic_arrow_back_black_24dp.xml │ │ │ │ ├── vic_arrow_left_24dp.xml │ │ │ │ ├── bg_selectable.xml │ │ │ │ ├── vic_delete_black_24dp.xml │ │ │ │ ├── vic_remove_circle_black_24dp.xml │ │ │ │ ├── vic_image_multiple_24dp.xml │ │ │ │ ├── vic_place_black_24dp.xml │ │ │ │ ├── vic_survey_20dp.xml │ │ │ │ ├── bg_mole_splash.xml │ │ │ │ └── vic_mole_20dp.xml │ │ │ ├── color │ │ │ │ ├── text_color_settings_title.xml │ │ │ │ └── text_color_settings_summary.xml │ │ │ ├── values │ │ │ │ ├── ids.xml │ │ │ │ ├── dimens.xml │ │ │ │ └── colors.xml │ │ │ ├── layout │ │ │ │ ├── view_toggle.xml │ │ │ │ ├── item_spinner_drop_down.xml │ │ │ │ ├── activity_learn.xml │ │ │ │ ├── activity_body_map.xml │ │ │ │ ├── item_mole_header.xml │ │ │ │ ├── item_spinner_view.xml │ │ │ │ ├── item_mole.xml │ │ │ │ ├── activity_photo.xml │ │ │ │ ├── item_learn.xml │ │ │ │ ├── activity_mole_history.xml │ │ │ │ ├── fragment_mole_dashboard.xml │ │ │ │ ├── item_mole_survey.xml │ │ │ │ ├── fragment_mole_mapper.xml │ │ │ │ ├── dialog_remove.xml │ │ │ │ ├── view_mole_detail.xml │ │ │ │ ├── dialog_edit.xml │ │ │ │ └── item_chart_general.xml │ │ │ ├── menu │ │ │ │ ├── menu_measure_history.xml │ │ │ │ ├── menu_body_map.xml │ │ │ │ └── menu_body_zone.xml │ │ │ ├── values-v19 │ │ │ │ └── themes.xml │ │ │ ├── values-v21 │ │ │ │ └── styles.xml │ │ │ └── layout-v16 │ │ │ │ └── item_learn.xml │ │ ├── assets │ │ │ ├── pdf │ │ │ │ └── app_consent_pdf.pdf │ │ │ ├── html │ │ │ │ ├── logo_institution.png │ │ │ │ ├── study_overview_join.html │ │ │ │ ├── learn_style.css │ │ │ │ ├── consent_section_html_study_survey.html │ │ │ │ ├── consent_section_html_security.html │ │ │ │ ├── consent_section_html_talktodoctor.html │ │ │ │ ├── consent_section_html_study_task.html │ │ │ │ ├── consent_section_html_withdraw.html │ │ │ │ ├── study_overview_about.html │ │ │ │ ├── consent_section_styles.css │ │ │ │ ├── consent_section_html_dataprocessing.html │ │ │ │ ├── learn_faq.html │ │ │ │ ├── consent_section_html_time.html │ │ │ │ ├── learn_credits.html │ │ │ │ ├── consent_section_html_datause.html │ │ │ │ ├── consent_section_html_withdrawing.html │ │ │ │ ├── learn_story.html │ │ │ │ ├── consent_section_html_protectingdata.html │ │ │ │ ├── study_overview_learn.html │ │ │ │ ├── study_overview_styles.css │ │ │ │ └── consent_section_html_sharing_rsch.html │ │ │ └── json │ │ │ │ ├── app_feedback.json │ │ │ │ ├── study_overview.json │ │ │ │ └── learn.json │ │ └── java │ │ │ └── org │ │ │ └── researchstack │ │ │ └── molemapper │ │ │ ├── ui │ │ │ ├── view │ │ │ │ ├── MoleHelper.java │ │ │ │ ├── MeasurementControlView.java │ │ │ │ ├── AutoFitTextureView.java │ │ │ │ └── PhotoGridView.java │ │ │ ├── fragment │ │ │ │ ├── PhotoCaptureCallbacks.java │ │ │ │ └── CameraFragment.java │ │ │ ├── EmptyItemDecoration.java │ │ │ ├── StatusBarUtils.java │ │ │ ├── TempGraphHelper.java │ │ │ └── MoleEditDialog.java │ │ │ ├── bridge │ │ │ ├── IdentifierHolder.java │ │ │ ├── BridgeMessageResponse.java │ │ │ ├── body │ │ │ │ ├── WithdrawalBody.java │ │ │ │ ├── EmailBody.java │ │ │ │ ├── SignInBody.java │ │ │ │ ├── SharingOptionBody.java │ │ │ │ ├── ConsentSignatureBody.java │ │ │ │ └── SignUpBody.java │ │ │ ├── UploadSession.java │ │ │ ├── BridgeErrorResponse.java │ │ │ ├── UploadQueue.java │ │ │ ├── FileInfo.java │ │ │ ├── Feedback.java │ │ │ ├── MoleRemoved.java │ │ │ ├── UploadRequest.java │ │ │ ├── MeasurementData.java │ │ │ ├── BridgeDataInput.java │ │ │ ├── Followup.java │ │ │ ├── Info.java │ │ │ ├── UploadValidationStatus.java │ │ │ └── BridgeEncryptedDatabase.java │ │ │ ├── network │ │ │ └── body │ │ │ │ └── UvHourly.java │ │ │ ├── MoleMapperApplication.java │ │ │ ├── models │ │ │ ├── Zone.java │ │ │ ├── Mole.java │ │ │ ├── MoleNameHelper.java │ │ │ └── Measurement.java │ │ │ ├── MoleMapperTaskProvider.java │ │ │ ├── MoleMapperSettingsActivity.java │ │ │ ├── MoleMappePermissionRequestManager.java │ │ │ ├── PhotoCaptureActivity.java │ │ │ ├── MoleMapperResearchStack.java │ │ │ ├── MoleMapperUiManager.java │ │ │ └── task │ │ │ └── FollowupTask.java │ ├── androidTest │ │ └── java │ │ │ └── org │ │ │ └── researchstack │ │ │ └── molemapper │ │ │ └── ApplicationTest.java │ └── test │ │ └── java │ │ └── co │ │ └── touchlab │ │ └── researchstack │ │ └── molemapper │ │ └── ExampleUnitTest.java ├── lint.xml └── proguard-rules.pro ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_x.png -------------------------------------------------------------------------------- /app/src/main/assets/pdf/app_consent_pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/assets/pdf/app_consent_pdf.pdf -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_x.png -------------------------------------------------------------------------------- /app/src/main/assets/html/logo_institution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/assets/html/logo_institution.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/body_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/body_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/body_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/body_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_mm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_mm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/illo_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/illo_mole.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/illo_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/illo_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/body_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/body_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/body_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/body_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_mm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_mm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/illo_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/illo_mole.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/illo_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/illo_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/body_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/body_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/illo_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/illo_mole.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/illo_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/illo_name.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/button_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/button_undo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_minus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_minus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_plus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_plus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/button_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/button_undo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_minus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_minus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_plus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_plus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/body_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/body_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/button_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/button_undo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_body_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_body_map.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_mm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_mm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_plus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_plus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/body_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/body_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/body_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/body_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/button_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/button_undo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_mm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_mm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/illo_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/illo_mole.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/illo_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/illo_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/body_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/body_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/body_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/body_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_mm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_mm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/illo_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/illo_mole.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/illo_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/illo_name.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/view/MoleHelper.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui.view; 2 | public class MoleHelper 3 | { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/button_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/button_capture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_top_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_top_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/button_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/button_capture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_top_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_top_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/button_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/button_capture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_info.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_minus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_minus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_minus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_minus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_plus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_plus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/button_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/button_undo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_plus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_plus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_back_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_back_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_back_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_back_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_front_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_front_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_left_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_left_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_left_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_left_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_right_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_right_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_top_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_top_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_action_toggle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow_up_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/ic_arrow_up_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_back_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_back_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_back_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_back_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_front_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_front_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_left_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_left_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_left_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_left_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_right_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_right_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_top_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_top_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_action_toggle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_arrow_up_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/ic_arrow_up_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_back_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_back_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_front_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_front_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_left_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_left_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_right_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_right_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_top_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_top_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_top_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_top_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_profile.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_toggle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_arrow_up_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_up_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_tabbar_moles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_tabbar_moles.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/logo_institution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/logo_institution.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/button_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/button_capture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_back_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_back_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_left_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_left_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_top_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_top_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_toggle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_up_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/ic_arrow_up_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/button_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/button_capture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_top_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_top_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_minus_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_minus_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/button_confirm_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/button_confirm_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_front_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_front_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/head_right_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/head_right_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/button_confirm_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/button_confirm_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_front_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_front_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/head_right_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/head_right_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_back_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_back_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_front_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_front_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_left_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_left_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_right_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/head_right_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_add_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_add_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_tabbar_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_tabbar_dashboard.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/logo_disease_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/logo_disease_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_back_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_back_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_front_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_front_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_left_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_left_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_right_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_right_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_top_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_top_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_back_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_back_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_front_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_front_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_left_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_left_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_right_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_right_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_top_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_top_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_action_toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_action_toggle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_arrow_up_16dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_16dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/button_confirm_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/button_confirm_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_camera_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_camera_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_camera_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/ic_action_camera_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/button_confirm_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/button_confirm_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_front_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_front_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_right_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/head_right_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/button_confirm_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/button_confirm_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_back_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_back_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_front_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_front_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_left_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_left_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/head_right_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/head_right_inactive.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/consent_section_withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-hdpi/consent_section_withdraw.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/consent_section_withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-mdpi/consent_section_withdraw.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/consent_section_withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xhdpi/consent_section_withdraw.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/consent_section_withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxhdpi/consent_section_withdraw.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/consent_section_withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResearchStack/MoleMapperAndroid/HEAD/app/src/main/res/drawable-xxxhdpi/consent_section_withdraw.png -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_left_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_place_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_multiple_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/fragment/PhotoCaptureCallbacks.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui.fragment; 2 | public interface PhotoCaptureCallbacks 3 | { 4 | void captureCanceled(); 5 | 6 | void captureCompleted(); 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_measurement_scale.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_measurement_move.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Mar 01 15:33:12 EST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/IdentifierHolder.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | /** 3 | * Created by bradleymcdermott on 1/29/16. 4 | */ 5 | public class IdentifierHolder 6 | { 7 | public String type; 8 | public String identifier; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/BridgeMessageResponse.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | public class BridgeMessageResponse 3 | { 4 | private String message; 5 | 6 | public String getMessage() 7 | { 8 | return message; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/color/text_color_settings_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/color/text_color_settings_summary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/body/WithdrawalBody.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge.body; 2 | public class WithdrawalBody 3 | { 4 | 5 | private final String reason; 6 | 7 | public WithdrawalBody(String reason) 8 | { 9 | this.reason = reason; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_spinner_down_16dp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/UploadSession.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | /** 3 | * Created by bradleymcdermott on 2/11/16. 4 | */ 5 | public class UploadSession 6 | { 7 | public String id; 8 | public String url; 9 | public String expires; 10 | public String type; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_toggle.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/BridgeErrorResponse.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import java.util.List; 3 | import java.util.Map; 4 | 5 | public class BridgeErrorResponse 6 | { 7 | public String message; 8 | public Map> errors; 9 | 10 | public BridgeErrorResponse() 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/UploadQueue.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | 3 | /** 4 | * Created by bradleymcdermott on 3/8/16. 5 | */ 6 | public interface UploadQueue 7 | { 8 | UploadRequest loadNextUploadRequest(); 9 | 10 | void saveUploadRequest(UploadRequest request); 11 | 12 | void deleteUploadRequest(UploadRequest request); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head_back.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_measure_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/network/body/UvHourly.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.network.body; 2 | /** 3 | * Created by bradleymcdermott on 2/16/16. 4 | */ 5 | public class UvHourly 6 | { 7 | private int ORDER; 8 | private int ZIP; 9 | public String DATE_TIME; 10 | public int UV_VALUE; 11 | 12 | public UvHourly() 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head_front.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-v19/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMapperApplication.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | 3 | import android.app.Application; 4 | import android.support.multidex.MultiDex; 5 | 6 | import com.crashlytics.android.Crashlytics; 7 | 8 | import org.researchstack.skin.ResearchStack; 9 | 10 | import io.fabric.sdk.android.Fabric; 11 | 12 | public class MoleMapperApplication extends Application 13 | { 14 | @Override 15 | public void onCreate() 16 | { 17 | super.onCreate(); 18 | MultiDex.install(this); 19 | // TODO remove Fabric/Crashlytics after QA process 20 | Fabric.with(this, new Crashlytics()); 21 | 22 | ResearchStack.init(this, new MoleMapperResearchStack()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/models/Zone.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.models; 2 | import java.io.Serializable; 3 | import java.util.List; 4 | 5 | import co.touchlab.squeaky.field.DatabaseField; 6 | import co.touchlab.squeaky.field.ForeignCollectionField; 7 | import co.touchlab.squeaky.table.DatabaseTable; 8 | 9 | /** 10 | * Created by bradleymcdermott on 2/4/16. 11 | */ 12 | @DatabaseTable 13 | public class Zone implements Serializable 14 | { 15 | @DatabaseField(id = true) 16 | public int id; 17 | 18 | @DatabaseField 19 | public String photo; 20 | 21 | @ForeignCollectionField(eager = true, foreignFieldName = "zone") 22 | public List moles; 23 | 24 | public Zone() 25 | { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mole.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/body/SharingOptionBody.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge.body; 2 | public class SharingOptionBody 3 | { 4 | /** 5 | * One of three string values:
  • no_sharing: Don't share data generated by this 6 | * participant;
  • sponsors_and_partners: share data in data sets that are 7 | * available to the study researchers and their researcher partners only
  • 8 | *
  • all_qualified_researchers: Share data with researchers who qualify under the 9 | * specific governance qualifications to access the study's data set. These researchers may do 10 | * research on new questions after the lifetime of the initial research
  • 11 | */ 12 | private String scope; 13 | 14 | public SharingOptionBody(String scope) 15 | { 16 | this.scope = scope; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_photo.xml: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_learn.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v16/item_learn.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/assets/html/study_overview_join.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    12 | 13 |
    14 | 15 | 16 | 17 |

    Would you like to help our research?

    18 | 19 |

    Tap "JOIN THE STUDY" to learn about this research study run by OHSU and Sage 20 | Bionetworks or tap 21 | "JOIN LATER" to begin mapping

    22 | 23 |
    24 | 25 |
    26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/assets/html/learn_style.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | body { 4 | font-family: sans-serif; 5 | font-style: normal; 6 | color:#000000; 7 | line-height:normal; 8 | font-weight:normal; 9 | } 10 | 11 | h3 { 12 | padding-top:12px; 13 | padding-bottom:12px; 14 | margin: 0px; 15 | } 16 | 17 | h5 { 18 | color:#009891; 19 | padding-top:16px; 20 | padding-bottom:16px; 21 | margin-top: 8px; 22 | margin-bottom: 0px; 23 | font-size:12pt; 24 | } 25 | 26 | p { 27 | font-size:12pt; 28 | padding-top:8px; 29 | padding-bottom:8px; 30 | margin: 0px; 31 | } 32 | 33 | p.a { 34 | padding-top:16px; 35 | padding-bottom:16px; 36 | } 37 | 38 | a, a:active { 39 | color:#255aa8; 40 | font-weight: bold; 41 | text-decoration: none; 42 | } 43 | 44 | .content { 45 | padding: 8px 16px 16px 50px; 46 | } 47 | 48 | img { 49 | display: block; 50 | padding: 0; 51 | margin: 0 auto; 52 | max-height: 100%; 53 | max-width: 100%; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/assets/json/learn.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "section_title": "Help", 5 | "row_items": [ 6 | { 7 | "title": "FAQs", 8 | "details": "learn_faq" 9 | }, 10 | { 11 | "title": "Support", 12 | "details": "learn_support" 13 | } 14 | ] 15 | }, 16 | { 17 | "section_title": "Info", 18 | "row_items": [ 19 | { 20 | "title": "OHSU War on Melanoma", 21 | "details": "ohsu" 22 | }, 23 | { 24 | "title": "The Mole Mapper story", 25 | "details": "learn_story" 26 | }, 27 | { 28 | "title": "Credits", 29 | "details": "learn_credits" 30 | } 31 | ] 32 | }, 33 | { 34 | "section_title": "Feedback", 35 | "row_items": [ 36 | { 37 | "title": "Help us improve!", 38 | "details": "feedback" 39 | } 40 | ] 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/EmptyItemDecoration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.researchstack.molemapper.ui; 18 | 19 | import android.graphics.Color; 20 | 21 | public class EmptyItemDecoration extends ColorItemDecoration 22 | { 23 | public EmptyItemDecoration(int orientation, int size) 24 | { 25 | super(orientation, size, Color.TRANSPARENT, false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/UploadRequest.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import co.touchlab.squeaky.field.DatabaseField; 3 | import co.touchlab.squeaky.table.DatabaseTable; 4 | 5 | /** 6 | * Created by bradleymcdermott on 2/11/16. 7 | */ 8 | @DatabaseTable 9 | public class UploadRequest 10 | { 11 | @DatabaseField(generatedId = true) 12 | public int id; 13 | @DatabaseField 14 | public String name; 15 | @DatabaseField 16 | public long contentLength; 17 | @DatabaseField 18 | public String contentMd5; 19 | @DatabaseField 20 | public String contentType; 21 | @DatabaseField(canBeNull = true) 22 | public String bridgeId; 23 | @DatabaseField 24 | public long uploadDate; 25 | 26 | public UploadRequest() 27 | { 28 | 29 | } 30 | 31 | public UploadRequest(String name, long contentLength, String contentMd5, String contentType) 32 | { 33 | this.name = name; 34 | this.contentLength = contentLength; 35 | this.contentMd5 = contentMd5; 36 | this.contentType = contentType; 37 | this.uploadDate = 0L; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_study_survey.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Study Questions 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | We will ask you questions, such as your profession, zip code where you live, 20 | hair/skin color and your prior experience with melanoma. These questions will be 21 | used to evaluate your exposure to UV radiation and your melanoma risk. Each month we 22 | will also ask you questions about your sun exposure, your health and whether you had 23 | moles removed. 24 |

      25 | You can skip any questions you do not wish to answer. 26 |

    27 | 28 |
    29 |
    30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/StatusBarUtils.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui; 2 | import android.content.Context; 3 | import android.view.View; 4 | import android.widget.RelativeLayout; 5 | 6 | public class StatusBarUtils 7 | { 8 | public static void adjustForTransparentStatusBar(View... views) 9 | { 10 | int statusBarHeight = getStatusBarHeight(views[0].getContext()); 11 | 12 | for(View v : views) 13 | { 14 | RelativeLayout.MarginLayoutParams params = (RelativeLayout.MarginLayoutParams) v.getLayoutParams(); 15 | params.topMargin = statusBarHeight; 16 | v.requestLayout(); 17 | } 18 | } 19 | 20 | public static int getStatusBarHeight(Context context) 21 | { 22 | int result = 0; 23 | int resourceId = context.getResources() 24 | .getIdentifier("status_bar_height", "dimen", "android"); 25 | if(resourceId > 0) 26 | { 27 | result = context.getResources().getDimensionPixelSize(resourceId); 28 | } 29 | else 30 | { 31 | result = (int) (context.getResources().getDisplayMetrics().density * 25 + .5f); 32 | } 33 | return result; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMapperTaskProvider.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | import android.content.Context; 3 | 4 | import org.researchstack.backbone.task.Task; 5 | import org.researchstack.molemapper.task.MoleMapperInitialTask; 6 | import org.researchstack.skin.TaskProvider; 7 | import org.researchstack.skin.task.ConsentTask; 8 | import org.researchstack.skin.task.SignInTask; 9 | import org.researchstack.skin.task.SignUpTask; 10 | 11 | import java.util.HashMap; 12 | 13 | public class MoleMapperTaskProvider extends TaskProvider 14 | { 15 | private HashMap map = new HashMap<>(); 16 | 17 | public MoleMapperTaskProvider(Context context) 18 | { 19 | put(TASK_ID_INITIAL, MoleMapperInitialTask.create(context, TASK_ID_INITIAL)); 20 | put(TASK_ID_CONSENT, ConsentTask.create(context, TASK_ID_CONSENT)); 21 | put(TASK_ID_SIGN_IN, new SignInTask(context)); 22 | put(TASK_ID_SIGN_UP, new SignUpTask(context)); 23 | } 24 | 25 | @Override 26 | public Task get(String taskId) 27 | { 28 | return map.get(taskId); 29 | } 30 | 31 | @Override 32 | public void put(String id, Task task) 33 | { 34 | map.put(id, task); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/body/ConsentSignatureBody.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge.body; 2 | 3 | import org.researchstack.backbone.utils.FormatHelper; 4 | 5 | import java.util.Date; 6 | 7 | public class ConsentSignatureBody 8 | { 9 | /** 10 | * The identifier for the study under which the user is signing in 11 | */ 12 | public String study; 13 | 14 | /** 15 | * User's name 16 | */ 17 | public String name; 18 | 19 | /** 20 | * User's birthdate 21 | */ 22 | public String birthdate; 23 | 24 | /** 25 | * User's signature image data 26 | */ 27 | public String imageData; 28 | 29 | /** 30 | * User's signature image mime type 31 | */ 32 | public String imageMimeType; 33 | 34 | /** 35 | * User's sharing scope choice 36 | */ 37 | public String scope; 38 | 39 | public ConsentSignatureBody(String study, String name, Date birthdate, String imageData, String imageMimeType, String scope) 40 | { 41 | this.study = study; 42 | this.name = name; 43 | this.birthdate = FormatHelper.SIMPLE_FORMAT_DATE.format(birthdate); 44 | this.imageData = imageData; 45 | this.imageMimeType = imageMimeType; 46 | this.scope = scope; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_security.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Protecting Your Data 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | 19 |

    20 | We will use strict information technology procedures to safeguard your data and 21 | prevent improper access. 22 |

    23 | Your data will be stored by our vendor Sage Bionetworks and OHSU on separate secure 24 | Cloud servers in a manner that keeps your information as safe as possible and 25 | prevents unauthorized people from getting to your data. 26 |  

    27 | Your coded study data may be shared with researchers in other countries, including 28 | countries that may have different data protection laws than your country of 29 | residence. 30 |

    31 | 32 |
    33 |
    34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/vic_mole_20dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 21 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/body/SignUpBody.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge.body; 2 | public class SignUpBody 3 | { 4 | 5 | /** 6 | * The identifier for the study under which the user is signing in 7 | */ 8 | private String study; 9 | 10 | /** 11 | * User's email address, cannot be change once created 12 | */ 13 | private String email; 14 | 15 | /** 16 | * User's username 17 | */ 18 | private String username; 19 | 20 | /** 21 | * User's password. Constraints for an acceptable password can be set per study. 22 | */ 23 | private String password; 24 | 25 | /** 26 | * An array of roles to assign to this user (admins only) 27 | */ 28 | private String[] roles; 29 | 30 | /** 31 | * An array of data group tags to assign to this user. Client applications can set this up 32 | * during sign up, it's not required to be an admin to add these. 33 | */ 34 | private String[] dataGroups; 35 | 36 | private String type = "SignUp"; 37 | 38 | public SignUpBody(String study, String email, String username, String password, String[] roles, String[] dataGroups) 39 | { 40 | this.study = study; 41 | this.email = email; 42 | this.username = username; 43 | this.password = password; 44 | this.roles = roles; 45 | this.dataGroups = dataGroups; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_talktodoctor.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Issues to Consider 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | This study will NOT provide you with information related to your specific health or 20 | melanoma risks. 21 |
    22 | This is NOT a medical diagnostic tool and isn’t designed to provide medical advice, 23 | professional diagnosis, opinion, treatment or healthcare services. 24 |
    25 | You should not use the information provided in Mole Mapper or the study 26 | documentation in place of a consultation with your physician or health care 27 | provider. 28 |
    29 | If you have any questions or concerns related to your health, you should seek the 30 | advice of a medical professional. 31 |

    32 | 33 |
    34 |
    35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_study_task.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Potential Benefits 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | 19 |

    20 | This project could create the largest dataset of longitudinal tracking of moles and 21 | may provide insights into the progression of moles to melanoma. 22 |

    23 | You may or may not personally benefit from this study. However, using the Mole 24 | Mapper app may help you monitor your moles over time. You will be able to share your 25 | mole photos and measurements as you wish, with your medical doctor and anyone you 26 | choose. You will also receive alerts about future melanoma educational and community 27 | events, free skin cancer screenings and/or skin cancer research opportunities from 28 | the War on Melanoma™ Community Registry. 29 |

    30 | 31 |
    32 |
    33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/MeasurementData.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import org.researchstack.backbone.utils.FormatHelper; 3 | import org.researchstack.molemapper.models.Measurement; 4 | import org.researchstack.molemapper.models.Mole; 5 | import org.researchstack.molemapper.models.Zone; 6 | 7 | /** 8 | * Created by bradleymcdermott on 2/8/16. 9 | */ 10 | public class MeasurementData 11 | { 12 | public static final String FILENAME = "measurementData.json"; 13 | public static final String PHOTO_FILENAME = "measurementPhoto.jpg"; 14 | public static final String ITEM = "moleMeasurement"; 15 | public static final int REVISION = 2; 16 | 17 | public String measurementID; 18 | public String zoneID; 19 | public String moleID; 20 | public float xCoordinate; 21 | public float yCoordinate; 22 | public float diameter; 23 | public String dateMeasured; 24 | 25 | public MeasurementData(Zone zone, Mole mole, Measurement measurement) 26 | { 27 | this.measurementID = String.valueOf(measurement.id); 28 | this.moleID = String.valueOf(mole.id); 29 | this.zoneID = String.valueOf(zone.id); 30 | this.xCoordinate = measurement.measurementX; 31 | this.yCoordinate = measurement.measurementY; 32 | this.diameter = measurement.absoluteMoleDiameter; 33 | this.dateMeasured = FormatHelper.DEFAULT_FORMAT.format(measurement.date); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMapperSettingsActivity.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | import android.os.Bundle; 3 | import android.support.v7.app.ActionBar; 4 | import android.support.v7.widget.Toolbar; 5 | import android.view.MenuItem; 6 | 7 | import org.researchstack.molemapper.ui.fragment.MoleMapperSettingsFragment; 8 | import org.researchstack.skin.ui.BaseActivity; 9 | 10 | public class MoleMapperSettingsActivity extends BaseActivity 11 | { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) 14 | { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.rss_activity_fragment); 17 | 18 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 19 | setSupportActionBar(toolbar); 20 | 21 | ActionBar actionBar = getSupportActionBar(); 22 | actionBar.setDisplayHomeAsUpEnabled(true); 23 | actionBar.setDisplayShowTitleEnabled(true); 24 | 25 | if(savedInstanceState == null) 26 | { 27 | getSupportFragmentManager().beginTransaction() 28 | .add(R.id.container, new MoleMapperSettingsFragment()) 29 | .commit(); 30 | } 31 | } 32 | 33 | 34 | @Override 35 | public boolean onOptionsItemSelected(MenuItem item) 36 | { 37 | if(item.getItemId() == android.R.id.home) 38 | { 39 | onBackPressed(); 40 | return true; 41 | } 42 | 43 | return super.onOptionsItemSelected(item); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_withdraw.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Consent Docs 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | You may decide not to participate in the study or you may leave the study and/or the 20 | War on Melanoma™ Community Registry at any time. 21 |

      22 | You can continue using the Mole Mapper app after you leave the study. 23 |

    24 | If you withdraw from the study, we will stop collecting new data. The coded study 25 | data collected prior to withdrawing may still be used in the study, it will not be 26 | destroyed or deleted. 27 |

    28 | The study team may also withdraw you from the study at any time for any reason. 29 |

    30 | To withdraw from the Mole Mapper study and the War on Melanoma™ Community Registry, 31 | please use the ‘Leave Study’ button on the Profile page of the Mole Mapper app. 32 |

    33 | 34 |
    35 |
    36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_mole_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 20 | 21 | 37 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/assets/html/study_overview_about.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    12 | 13 |
    14 | 15 |

    What is involved

    16 | 17 |

    18 | To join this study, we will ask you to do: 19 | 20 |

      21 |
    • Consent to participate
    • 22 |
    • Register with your email address
    • 23 |
    • Answer questions about yourself
    • 24 |
    • Take pictures and measurements of your moles over time and share your mole data with 25 | the study team 26 |
    • 27 |
    28 | 29 | This app is designed for research and educational purposes only. You should not rely on 30 | this information as a substitute for personal medical attention, diagnosis or hands-on 31 | treatment. If you are concerned about your health or that of a child, please consult 32 | your family's health provider immediately. Do not wait for a response from our 33 | professionals. 34 | 35 |

    36 | 37 | Learn about the study first 38 | 39 |

    40 | 41 |
    42 | 43 |
    44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_styles.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | a:link, a:active, a:visited, a:active { 4 | font-family: sans-serif-medium; 5 | font-style: normal; 6 | font-size:11pt; 7 | text-decoration: none; 8 | color:#5a95cd; 9 | } 10 | 11 | img { 12 | display: inline; 13 | height: auto; 14 | max-width: 100%; 15 | } 16 | 17 | body { 18 | font-family: sans-serif; 19 | font-style: normal; 20 | font-size:11pt; 21 | color:#000000; 22 | padding-top:0px; 23 | padding-bottom:20px; 24 | } 25 | 26 | p, h2 { 27 | margin-top: 0; 28 | padding-right: 0px; 29 | padding-left: 0px; 30 | } 31 | 32 | h1 { 33 | font-family: sans-serif; 34 | font-style: normal; 35 | font-size:15.8pt; 36 | color:#000000; 37 | padding-top:0px; 38 | padding-bottom:0px; 39 | } 40 | 41 | .footer { 42 | background-color: #FFFFFF; 43 | width: 20%; 44 | margin: 0 auto; 45 | } 46 | 47 | .content { 48 | padding: 10px 10px 10px 10px; 49 | } 50 | 51 | .content ul, .content ol { 52 | padding: 0 10px 15px 15px; 53 | } 54 | 55 | IMG.displayed { 56 | display: block; 57 | margin-left: auto; 58 | margin-right: auto 59 | } 60 | 61 | bold { 62 | font-family:sans-serif-medium; 63 | font-size:16pt; 64 | color:#000000; 65 | line-height:normal; 66 | font-weight:normal; 67 | padding-top:0px; 68 | padding-bottom:0px; 69 | } 70 | 71 | ul, ol { 72 | font-family: sans-serif; 73 | font-style: normal; 74 | font-size:11pt; 75 | color:#000000; 76 | list-style-type: disk; 77 | list-style-position: inside; 78 | 79 | } 80 | 81 | .ExternalClass * { 82 | line-height: 100% 83 | } -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_dataprocessing.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Tracking Moles 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | 19 |

    20 | If you join this research study we will ask you to share your mole measurements 21 | collected using Mole Mapper. You will: 22 |

      23 |
    • Take pictures of your moles with the smartphone camera
    • 24 |
    • Map them to zones on the Mole Mapper body map
    • 25 |
    • Measure their size relative to a reference object like a coin photographed next 26 | to the mole. 27 |
    • 28 |
    29 | 30 |

    31 | We will prompt you to re-measure your moles each month and send your updated data 32 | along with any information about new moles and whether you had any moles removed. If 33 | you have had a mole removed in a given month, we will ask you to take a photo and 34 | measurement of the biopsy site. 35 |

    36 | You can track your moles at your convenience, track more or fewer moles or stop 37 | sharing your mole measurements at any time. 38 |

    39 |
    40 |
    41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/assets/html/learn_faq.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | About this Study 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | Frequently asked questions 20 |

    21 | 22 |
    23 | What should I be looking for or concerned about? 24 |
    25 | 26 |

    27 | Check out the National Cancer Institute’s guide to moles. 28 |

    29 | 30 |

    31 | SEE THE GUIDE 32 |

    33 | 34 |
    35 | Does this app tell me if I have melanoma? 36 |
    37 | 38 |

    39 | This app is designed for self-tracking to help 40 | you monitor the size, shape, and color of your 41 | moles. This app does not make any claim to 42 | detect, diagnose, or treat any skin condition. 43 | 44 | Any data stored within the app is for personal 45 | use only. We encourage you to share your 46 | photos and measurements with a licensed 47 | professional and refer to their professional 48 | opinion. 49 |

    50 | 51 |
    52 | 53 |
    54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/BridgeDataInput.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import android.content.Context; 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | 7 | import org.researchstack.backbone.StorageAccess; 8 | 9 | import java.io.ByteArrayInputStream; 10 | import java.io.FileNotFoundException; 11 | import java.io.InputStream; 12 | 13 | /** 14 | * Created by bradleymcdermott on 3/14/16. 15 | */ 16 | public class BridgeDataInput 17 | { 18 | private static Gson gson = new GsonBuilder().serializeNulls().create(); 19 | private Object gsonableObject; 20 | private Class clazz; 21 | private String inputFilename; 22 | String filename; 23 | String endDate; 24 | 25 | public BridgeDataInput(Object gsonableObject, Class clazz, String filename, String endDate) 26 | { 27 | this.gsonableObject = gsonableObject; 28 | this.clazz = clazz; 29 | this.filename = filename; 30 | this.endDate = endDate; 31 | } 32 | 33 | public BridgeDataInput(String inputFilename, String filename, String endDate) 34 | { 35 | this.inputFilename = inputFilename; 36 | this.filename = filename; 37 | this.endDate = endDate; 38 | } 39 | 40 | public InputStream getInputStream(Context context) throws FileNotFoundException 41 | { 42 | if(gsonableObject != null) 43 | { 44 | return new ByteArrayInputStream(gson.toJson(gsonableObject, clazz).getBytes()); 45 | } 46 | else 47 | { 48 | return new ByteArrayInputStream(StorageAccess.getInstance() 49 | .getFileAccess() 50 | .readData(context, inputFilename)); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #255aa8 4 | #1f4884 5 | #ff5722 6 | #2196f3 7 | #009891 8 | #666666 9 | #757575 10 | #e5e5e5 11 | #fafafa 12 | #EEEEEE 13 | #fafafa 14 | #66255aa8 15 | #ff5722 16 | #009891 17 | #66FFFFFF 18 | 19 | 20 | #979797 21 | #4a4a4a 22 | #FF255aa8 23 | 24 | #FF009891 25 | #FF255aa8 26 | 27 | 28 | #66245aa8 29 | #99FFFFFF 30 | #66009891 31 | #99FFFFFF 32 | @android:color/white 33 | #FFFFFFFF 34 | 35 | 36 | #FF5392ef 37 | #FF16C6B6 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_time.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Time Commitment 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | This study involves answering survey questions and sending mole measurements and photos 19 | that you have taken. 20 |

    21 | We will send notices on your phone to re-measure your tracked moles every month and send 22 | your updated data along with any information about new moles and whether you had any 23 | moles removed. 24 |

      25 | The initial survey may take 5-10 minutes, and the follow-up surveys are expected to take 26 | about 1 minute. Measuring a mole may take 1-2 minutes per mole. You can stop and restart 27 | where you left off at any time. 28 |

    29 | For most people, participating in this study will take no more than 20 minutes per 30 | month. You can adjust your level of participation, as you desire. The number of moles 31 | you track and how often you track your moles is entirely up to you. 32 |

    33 | Transmitting data collected in this study may count against your existing mobile data 34 | plan. You may configure the application to only use WiFi connections to limit the impact 35 | this data collection has on your data plan. 36 |
    37 |
    38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/assets/html/learn_credits.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Credits 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | Credits 20 |

    21 | 22 |
    23 | Design & Development 24 |
    25 | 26 |

    27 | touchlab
    28 | America's Android First Development & Design Shop
    29 | Thank you to Wojciech Dziemianczyk & Brad McDermott for your great work on development, 30 | Liam Spradlin for his wonderful design, and Justin Mancinelli for project managing. 31 |

    32 | 33 |

    34 | Design elements from David Reese, Steve Salgado, and Chris Webster. 35 |

    36 | 37 |
    Mole Mapper Contributors
    38 | 39 |

    40 | Dan Webster
    41 | NCI Postdoc
    42 | Founder and Lead Developer of MoleMapper.org
    44 |

    45 | 46 |

    47 | Ron West
    48 | Developer 49 |

    50 | 51 |

    52 | Tracy Petrie
    53 | Product Manager 54 |

    55 | 56 |

    57 | Michael Carroll
    58 | Technologist-in-Residence at Cornell Tech
    59 |

    60 | 61 |
    62 | 63 |
    64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_datause.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Data use 10 | 11 | 12 | 13 |
    14 | 15 |
    16 | Your un-named and coded study data (the answers you provide on surveys and your mole 17 | data (photos, location, size) will be combined with the similarly de-identified data 18 | from other study participants. 19 |

    20 | By analyzing the data from many Mole Mapper app users we hope to better understand the 21 | variation in mole growth and cancer risks, and whether a mobile device can help people 22 | measure moles accurately and manage skin health. 23 |

    24 | For example, airline pilots and flight crew are about 2 times more likely to develop 25 | melanoma. But does this also mean that they have 2 times more moles, or experience more 26 | dynamic mole changes that can be caught early? Large, combined data sets are necessary 27 | to answer these types of questions. 28 |

    29 | The OHSU study team may query the data to identify and re-contact people with certain 30 | mole characteristics, and invite them to join specific melanoma-related opportunity or 31 | events that may be of interest to them through the War on Melanoma Community Registry. 32 |

    33 | Your information will not be used for commercial advertising. 34 |
    35 |
    36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_withdrawing.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Potential Risks 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |

    19 | We take great care to protect your information, however there is a slight risk of 20 | loss of privacy. This risk is low because we separate your account information 21 | (name, email, contact information, etc.) from the study data. Only key members of 22 | the study team and some IT staff will have the key to associate your coded study 23 | data to your name and account information. 24 |

    25 | However, certain skin features like tattoos or birthmarks may be unique to you and 26 | enable your re-identification. So even though your name is kept separate from your 27 | coded study data, it is possible that someone could still figure out your identity. 28 | To reduce this risk we recommend photographing moles at close range (6 inches from 29 | skin surface) to minimize capture of secondary identifiable skin features. Further, 30 | we will attempt to review and remove from the study dataset all photos that we 31 | consider identifiable or inappropriate for broad sharing with the research 32 | community. 33 |

    34 | The risk to privacy and confidentiality should be considered before participating in 35 | the study. 36 | 37 |

    38 | 39 |
    40 |
    41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_mole_dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 22 | 23 | 27 | 28 | 31 | 32 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/assets/html/learn_story.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Our Story 10 | 11 | 12 | 13 |
    14 | 15 |
    16 | 17 |

    18 | Our story 19 |

    20 | 21 |

    22 | A few years ago, I met and married a woman who means everything to me. She also has 23 | every risk factor for melanoma, an aggressive and deadly cancer that can result from 24 | changes in your moles.  25 |

    26 | 27 |

    28 | The earlier you detect melanoma, the better the outcome. And while my wife regularly 29 | goes to a dermatologist to check her moles, I wanted her to have a tool to map and 30 | measure them on her own. 31 |

    32 | 33 |

    34 | During my PhD, I studied melanoma biology in the lab and by night worked to create 35 | the 36 | app that you have in your hand now. In partnership with OHSU and Sage Bionetworks, 37 | this 38 | app can not only help you track your own moles, but now allows you to contribute 39 | your 40 | data to a research effort that aims to better understand melanoma risk. I hope Mole 41 | Mapper makes being vigilant about your health a bit more enjoyable. 42 |

    43 | 44 |

    45 | Happy Mapping, 46 |

    47 | Dan E. Webster 48 |

    49 | 50 |
    51 | 52 |
    53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mole_survey.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 19 | 20 | 29 | 30 | 39 | 40 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_protectingdata.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Your Privacy 10 | 11 | 12 | 13 | 14 | 15 |
    16 | 17 |
    18 | Your privacy is important to us. 19 |

    20 | The data collected through the app will be encrypted on the phone. 21 |

    22 | We will separate your account information (name, email, contact information, etc.) from 23 | the study data (the responses to surveys, the mole pictures and the mole measurements). 24 | The metadata will consist of your responses to survey and mole measurements only. No 25 | mole pictures will be included in the metadata. 26 |

    27 | We will use a random code instead of your name on all study data. This code cannot be 28 | used to directly re-identify you. Information about the code will be kept in a separate 29 | secure system. Only key personnel from the study team may connect your study data to 30 | your name and account information. 31 |

    32 | Sancy Leachman, MD. PhD, is leading the study teams for both the Mole Mapper study and 33 | the War on Melanoma™ Community Registry. 34 |

    35 | The photos you take using Mole Mapper are stored within the app, not on your phone 36 | photostream or other cloud storage system. 37 |

    38 | We will not access your personal phone contacts, other applications, personal photos, 39 | texts, emails or websites visited. 40 |

    41 | Please consult our Privacy Policy for more details. 42 |
    43 |
    44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/Followup.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import org.researchstack.backbone.result.StepResult; 3 | import org.researchstack.backbone.result.TaskResult; 4 | import org.researchstack.backbone.utils.FormatHelper; 5 | import org.researchstack.molemapper.task.FollowupTask; 6 | 7 | import java.util.Collection; 8 | 9 | /** 10 | * Created by bradleymcdermott on 2/11/16. 11 | */ 12 | public class Followup 13 | { 14 | public static final String FILENAME = "followup.json"; 15 | public static final String ITEM = "followup"; 16 | public static final int REVISION = 1; 17 | 18 | public Integer sunburn; 19 | public Integer moleRemoved; 20 | public Integer sunscreen; 21 | public Integer sick; 22 | public Integer tan; 23 | public String date; 24 | 25 | public Followup(TaskResult taskResult) 26 | { 27 | Collection stepResults = taskResult.getResults().values(); 28 | 29 | date = FormatHelper.DEFAULT_FORMAT.format(taskResult.getEndDate()); 30 | for(StepResult stepResult : stepResults) 31 | { 32 | if(stepResult == null) 33 | { 34 | continue; 35 | } 36 | 37 | if(stepResult.getIdentifier().equals(FollowupTask.FOLLOWUP_FORM)) 38 | { 39 | sunburn = getIntBoolean(stepResult, FollowupTask.SUNBURN); 40 | moleRemoved = getIntBoolean(stepResult, FollowupTask.MOLE_REMOVED); 41 | sick = getIntBoolean(stepResult, FollowupTask.SICK); 42 | tan = getIntBoolean(stepResult, FollowupTask.TAN); 43 | sunscreen = getIntBoolean(stepResult, FollowupTask.SUNSCREEN); 44 | 45 | } 46 | } 47 | } 48 | 49 | private Integer getIntBoolean(StepResult stepResult, String identifier) 50 | { 51 | Boolean result = ((StepResult) stepResult.getResultForIdentifier(identifier)).getResult(); 52 | 53 | // unanswered 54 | if(result == null) 55 | { 56 | return null; 57 | } 58 | 59 | return Boolean.TRUE.equals(result) ? 1 : 0; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_mole_mapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 23 | 24 | 39 | 40 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMappePermissionRequestManager.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | import android.app.Activity; 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.support.v4.content.ContextCompat; 7 | 8 | import org.researchstack.skin.PermissionRequestManager; 9 | 10 | public class MoleMappePermissionRequestManager extends PermissionRequestManager 11 | { 12 | @Override 13 | public boolean hasPermission(Context context, String permissionId) 14 | { 15 | return ContextCompat.checkSelfPermission(context, permissionId) == 16 | PackageManager.PERMISSION_GRANTED; 17 | } 18 | 19 | /** 20 | * Used to tell if the permission-id should be handled by the system (using {@link 21 | * Activity#requestPermissions(String[], int)}) or through our own custom implementation in 22 | * {@link #onRequestNonSystemPermission} 23 | * 24 | * @param permissionId 25 | * @return 26 | */ 27 | @Override 28 | public boolean isNonSystemPermission(String permissionId) 29 | { 30 | return false; 31 | } 32 | 33 | /** 34 | * This method is called when {@link #isNonSystemPermission} returns true. For example, if using 35 | * Google+ Sign In, you would create your signIn-Intent and start that activity. Any result will 36 | * then be passed through to {#link onNonSystemPermissionResult} 37 | * 38 | * @param permissionId 39 | */ 40 | @Override 41 | public void onRequestNonSystemPermission(Activity activity, String permissionId) 42 | { 43 | // Do Nothing, we don't use PermissionRequestManager 44 | } 45 | 46 | /** 47 | * Method is called when your Activity called in {@link #onRequestNonSystemPermission} has 48 | * returned with a result 49 | * 50 | * @param requestCode 51 | * @param resultCode 52 | * @param data 53 | * @return 54 | */ 55 | @Override 56 | public boolean onNonSystemPermissionResult(Activity activity, int requestCode, int resultCode, Intent data) 57 | { 58 | // Do Nothing, we don't use PermissionRequestManager 59 | return false; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/models/Mole.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.models; 2 | import java.io.Serializable; 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import co.touchlab.squeaky.field.DatabaseField; 8 | import co.touchlab.squeaky.field.ForeignCollectionField; 9 | import co.touchlab.squeaky.table.DatabaseTable; 10 | 11 | /** 12 | * Created by bradleymcdermott on 2/4/16. 13 | */ 14 | @DatabaseTable 15 | public class Mole implements Serializable 16 | { 17 | public static final int STATE_UNTRACKED = 0; 18 | public static final int STATE_TRACKED = 1; 19 | public static final int STATE_TRACKED_OUTDATED = 2; 20 | public static final int STATE_REMOVED = 3; 21 | 22 | @DatabaseField(generatedId = true) 23 | public Integer id; 24 | @DatabaseField 25 | public String moleName; 26 | @DatabaseField 27 | public int moleX; 28 | @DatabaseField 29 | public int moleY; 30 | @DatabaseField 31 | public boolean removed; 32 | @DatabaseField(foreign = true) 33 | public Zone zone; 34 | @ForeignCollectionField(eager = true, foreignFieldName = "mole") 35 | public List measurements; 36 | 37 | public Mole() 38 | { 39 | } 40 | 41 | public int getState() 42 | { 43 | if(removed) 44 | { 45 | return STATE_REMOVED; 46 | } 47 | 48 | if(measurements == null || measurements.isEmpty()) 49 | { 50 | return STATE_UNTRACKED; 51 | } 52 | 53 | // Get a Calendar object which represents the next time they should schedule their mole 54 | Date lastDate = measurements.get(measurements.size() - 1).date; 55 | Calendar calendar = Calendar.getInstance(); 56 | calendar.setTime(lastDate); 57 | calendar.add(Calendar.DAY_OF_MONTH, 30); 58 | 59 | // If the current time is before the next measure time, the measurement is "current" 60 | if(System.currentTimeMillis() < calendar.getTimeInMillis()) 61 | { 62 | return STATE_TRACKED; 63 | } 64 | else 65 | { 66 | return STATE_TRACKED_OUTDATED; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/models/MoleNameHelper.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.models; 2 | import android.content.Context; 3 | import android.content.SharedPreferences; 4 | import android.support.annotation.StringRes; 5 | import android.support.v7.preference.PreferenceManager; 6 | 7 | import org.researchstack.molemapper.R; 8 | import org.researchstack.molemapper.ui.fragment.MoleMapperSettingsFragment; 9 | 10 | import java.util.Arrays; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | /** 15 | * Created by bradleymcdermott on 4/8/16. 16 | */ 17 | public class MoleNameHelper 18 | { 19 | public enum Gender 20 | { 21 | RANDOM(R.string.naming_convention_random), 22 | MALE(R.string.naming_convention_male), 23 | FEMALE(R.string.naming_convention_female); 24 | 25 | private final int nameResourceId; 26 | 27 | Gender(@StringRes int nameResourceId) 28 | { 29 | this.nameResourceId = nameResourceId; 30 | } 31 | 32 | @StringRes 33 | public int getNameResourceId() 34 | { 35 | return nameResourceId; 36 | } 37 | } 38 | 39 | public static Set loadNames(Context context) 40 | { 41 | Gender gender = loadGenderSetting(context); 42 | 43 | Set names = new HashSet<>(); 44 | 45 | if(gender == Gender.RANDOM || gender == Gender.MALE) 46 | { 47 | names.addAll(Arrays.asList(context.getResources().getStringArray(R.array.male_names))); 48 | } 49 | 50 | if(gender == Gender.RANDOM || gender == Gender.FEMALE) 51 | { 52 | names.addAll(Arrays.asList(context.getResources() 53 | .getStringArray(R.array.female_names))); 54 | } 55 | 56 | return names; 57 | } 58 | 59 | private static Gender loadGenderSetting(Context context) 60 | { 61 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); 62 | String defaultNamingConvention = Integer.toString(MoleNameHelper.Gender.RANDOM.ordinal()); 63 | String currentNamingConvInt = sharedPreferences.getString(MoleMapperSettingsFragment.KEY_APP_MOLE_NAMING, 64 | defaultNamingConvention); 65 | int currentNamingOrdinal = Integer.parseInt(currentNamingConvInt); 66 | return MoleNameHelper.Gender.values()[currentNamingOrdinal]; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/fragment/CameraFragment.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui.fragment; 2 | import android.app.Fragment; 3 | import android.graphics.BitmapFactory; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | 7 | import org.researchstack.molemapper.PhotoCaptureActivity; 8 | 9 | public class CameraFragment extends Fragment 10 | { 11 | 12 | public static CameraFragment newInstance(int id, int type, String desc, String path) 13 | { 14 | CameraFragment fragment = getCameraFragment(); 15 | Bundle args = new Bundle(); 16 | args.putInt(PhotoCaptureActivity.KEY_ID, id); 17 | args.putInt(PhotoCaptureActivity.KEY_TYPE, type); 18 | args.putString(PhotoCaptureActivity.KEY_INSTRUCTION, desc); 19 | args.putString(PhotoCaptureActivity.KEY_PATH, path); 20 | fragment.setArguments(args); 21 | return fragment; 22 | } 23 | 24 | public CameraFragment() 25 | { 26 | super(); 27 | } 28 | 29 | public static CameraFragment getCameraFragment() 30 | { 31 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 32 | { 33 | return new LollipopCameraFragment(); 34 | } 35 | else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 36 | { 37 | return new JellyBeanCameraFragment(); 38 | } 39 | else 40 | { 41 | throw new RuntimeException("API v." + Build.VERSION.SDK_INT + " not supported"); 42 | } 43 | } 44 | 45 | public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) 46 | { 47 | // Raw height and width of image 48 | final int height = options.outHeight; 49 | final int width = options.outWidth; 50 | 51 | int inSampleSize = 1; 52 | 53 | if(height > reqHeight || width > reqWidth) 54 | { 55 | 56 | final int halfHeight = height / 2; 57 | final int halfWidth = width / 2; 58 | 59 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both 60 | // height and width larger than the requested height and width. 61 | while((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) 62 | { 63 | inSampleSize *= 2; 64 | } 65 | } 66 | 67 | return inSampleSize; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/view/MeasurementControlView.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui.view; 2 | import android.content.Context; 3 | import android.os.Handler; 4 | import android.support.v7.widget.AppCompatImageButton; 5 | import android.util.AttributeSet; 6 | import android.view.GestureDetector; 7 | import android.view.HapticFeedbackConstants; 8 | import android.view.MotionEvent; 9 | 10 | public class MeasurementControlView extends AppCompatImageButton 11 | { 12 | private Handler handler = new Handler(); 13 | private GestureDetector gestureDetector; 14 | 15 | public MeasurementControlView(Context context) 16 | { 17 | super(context); 18 | init(); 19 | } 20 | 21 | public MeasurementControlView(Context context, AttributeSet attrs) 22 | { 23 | super(context, attrs); 24 | init(); 25 | } 26 | 27 | public MeasurementControlView(Context context, AttributeSet attrs, int defStyleAttr) 28 | { 29 | super(context, attrs, defStyleAttr); 30 | init(); 31 | } 32 | 33 | private void init() 34 | { 35 | setHapticFeedbackEnabled(true); 36 | 37 | gestureDetector = new GestureDetector(getContext(), new ControlGestureListener()); 38 | } 39 | 40 | @Override 41 | public boolean onTouchEvent(MotionEvent event) 42 | { 43 | if(event.getAction() == MotionEvent.ACTION_UP) 44 | { 45 | handler.removeCallbacks(longClickRunnable); 46 | } 47 | 48 | return gestureDetector.onTouchEvent(event); 49 | } 50 | 51 | private Runnable longClickRunnable = new Runnable() 52 | { 53 | @Override 54 | public void run() 55 | { 56 | performLongClick(); 57 | handler.postDelayed(this, 30); 58 | } 59 | }; 60 | 61 | private class ControlGestureListener extends GestureDetector.SimpleOnGestureListener 62 | { 63 | @Override 64 | public boolean onDown(MotionEvent e) 65 | { 66 | performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); 67 | return true; 68 | } 69 | 70 | @Override 71 | public void onLongPress(MotionEvent e) 72 | { 73 | performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 74 | handler.post(longClickRunnable); 75 | } 76 | 77 | @Override 78 | public boolean onSingleTapUp(MotionEvent e) 79 | { 80 | callOnClick(); 81 | return true; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/TempGraphHelper.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui; 2 | import android.content.res.Resources; 3 | import android.graphics.Typeface; 4 | 5 | import com.github.mikephil.charting.charts.LineChart; 6 | import com.github.mikephil.charting.components.XAxis; 7 | import com.github.mikephil.charting.components.YAxis; 8 | import com.github.mikephil.charting.data.Entry; 9 | import com.github.mikephil.charting.data.LineData; 10 | import com.github.mikephil.charting.data.LineDataSet; 11 | 12 | import org.researchstack.molemapper.R; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by bradleymcdermott on 2/23/16. 18 | */ 19 | public class TempGraphHelper 20 | { 21 | public static LineChart updateLineChart(LineChart chart, int max, List entries, List xValues) 22 | { 23 | Resources res = chart.getContext().getResources(); 24 | 25 | chart.setDrawBorders(false); 26 | 27 | XAxis xAxis = chart.getXAxis(); 28 | xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); 29 | xAxis.setDrawAxisLine(false); 30 | xAxis.setYOffset(32f); 31 | xAxis.setDrawGridLines(false); 32 | xAxis.setLabelsToSkip(0); 33 | xAxis.setTextSize(14); 34 | xAxis.setTextColor(res.getColor(R.color.mm_warm_grey)); 35 | xAxis.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); 36 | 37 | YAxis yAxis = chart.getAxisLeft(); 38 | yAxis.setDrawAxisLine(false); 39 | yAxis.setDrawGridLines(false); 40 | yAxis.setDrawZeroLine(false); 41 | yAxis.setAxisMaxValue(max + 2); 42 | yAxis.setAxisMinValue(0); 43 | yAxis.setShowOnlyMinMax(true); 44 | yAxis.setTextSize(14); 45 | yAxis.setTextColor(res.getColor(R.color.mm_warm_grey)); 46 | yAxis.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); 47 | 48 | chart.getAxisRight().setEnabled(false); 49 | chart.getLegend().setEnabled(false); 50 | chart.setDescription(""); 51 | 52 | LineDataSet set = new LineDataSet(entries, ""); 53 | set.setCircleColor(res.getColor(R.color.mm_colorPrimary)); 54 | set.setCircleRadius(4f); 55 | set.setDrawCircleHole(false); 56 | set.setColor(res.getColor(R.color.mm_colorPrimary)); 57 | set.setLineWidth(2f); 58 | set.setDrawValues(false); 59 | 60 | LineData data = new LineData(xValues, set); 61 | chart.setData(data); 62 | chart.setVisibleXRange(0, 7); 63 | 64 | return chart; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/assets/html/study_overview_learn.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | About Study 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | Researchers from Sage Bionetworks (nonprofit) and OHSU Department of Dermatology invite 18 | you to participate in a research study about melanoma using Mole Mapper and 19 | ResearchStack. 20 |

    21 | The aims of this study are to better understand skin biology and melanoma risks and to 22 | contribute information to the Melanoma Community Registry maintained by OHSU. 23 |

    24 | By analyzing the data from many Mole Mapper app users we hope to better understand the 25 | variation in mole growth and cancer risks, and whether a mobile device can help people 26 | measure moles accurately and manage their skin health better. 27 |

    28 | By answering few questions about yourself, tracking your moles regularly and sharing 29 | your mole measurements, you can help us learn how melanoma develops and what can be done 30 | to reduce risks of melanoma. 31 |

    32 | If you are over 18 years old, we invite you to join the study and declare war on 33 | melanoma. 34 |

    35 | Questions? 36 |

    37 | 38 | Please contact the Mole Mapper study sponsor at +1-206-667-2115 39 | (toll-free 40 | +1-844-693-2137) or by email molemapperstudy@sagebase.org 42 |

    43 | 44 | For the Melanoma Community Registry, please contact the OHSU Research Integrity Office 45 | at +1-503-494-7887 or by email at WarOnMelanoma@ohsu.edu 47 |

    48 | Mole Mapper is a research study and does not provide medical advice, diagnosis or 49 | treatment 50 |
    51 | 52 |
    53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/assets/html/study_overview_styles.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | a:link, a:active, a:visited, a:active { 4 | font-family: sans-serif-medium; 5 | font-style: normal; 6 | font-size:11pt; 7 | text-decoration: none; 8 | color:#5a95cd; 9 | } 10 | 11 | img { 12 | display: block; 13 | height: auto; 14 | max-width: 100%; 15 | } 16 | 17 | body { 18 | font-family: sans-serif; 19 | font-style: normal; 20 | font-size:11pt; 21 | color:#000000; 22 | padding-top:0px; 23 | padding-bottom:20px; 24 | } 25 | 26 | p, h2 { 27 | margin-top: 0; 28 | padding-right: 0px; 29 | padding-left: 0px; 30 | } 31 | 32 | h1 { 33 | font-family: sans-serif; 34 | font-style: normal; 35 | font-size:15.8pt; 36 | color:#000000; 37 | padding-top:0px; 38 | padding-bottom:0px; 39 | } 40 | 41 | .footer { 42 | background-color: #FFFFFF; 43 | width: 20%; 44 | margin: 0 auto; 45 | } 46 | 47 | .content { 48 | padding: 10px 10px 10px 10px; 49 | } 50 | 51 | .content ul, .content ol { 52 | padding: 0 10px 15px 15px; 53 | } 54 | 55 | IMG.displayed { 56 | display: block; 57 | margin-left: auto; 58 | margin-right: auto 59 | } 60 | 61 | bold { 62 | font-family:sans-serif-medium; 63 | font-size:16pt; 64 | color:#000000; 65 | line-height:normal; 66 | font-weight:normal; 67 | padding-top:0px; 68 | padding-bottom:0px; 69 | } 70 | 71 | ul, ol { 72 | font-family: sans-serif; 73 | font-style: normal; 74 | font-size:11pt; 75 | color:#000000; 76 | list-style-type: disk; 77 | list-style-position: inside; 78 | 79 | } 80 | 81 | .ExternalClass * { 82 | line-height: 100% 83 | } 84 | 85 | @media screen and (-webkit-device-pixel-ratio:0.75) { 86 | img.logo { 87 | background-image: url('res/drawable-ldpi/logo_institution.png'); 88 | width: 75px; 89 | height: 75px; 90 | border: 1px solid #ff0000; 91 | } 92 | } 93 | 94 | @media screen and (-webkit-device-pixel-ratio:1.0) { 95 | img.logo { 96 | background-image: url('res/drawable-mdpi/logo_institution.png'); 97 | width: 100px; 98 | height: 100px; 99 | border: 1px solid #00ff00; 100 | } 101 | } 102 | 103 | @media screen and (-webkit-device-pixel-ratio:1.5) { 104 | img.logo { 105 | background-image: url('res/drawable-hdpi/logo_institution.png'); 106 | width: 150px; 107 | height: 150px; 108 | border: 1px solid #0000ff; 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/Info.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import android.content.Context; 3 | import android.content.pm.PackageInfo; 4 | import android.content.pm.PackageManager; 5 | import android.os.Build; 6 | 7 | import org.researchstack.backbone.utils.LogExt; 8 | import org.researchstack.molemapper.R; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.UUID; 13 | 14 | /** 15 | * Created by bradleymcdermott on 2/8/16. 16 | */ 17 | public class Info 18 | { 19 | public static final int BRIDGE_PHONE_INFO_LIMIT = 48; 20 | 21 | private List files; 22 | private String item; 23 | private String surveyGuid; 24 | private String surveyCreatedOn; 25 | private int schemaRevision = 1; 26 | // since this buildconfig is in skin, this won't be correct 27 | private String appVersion; 28 | private String phoneInfo; 29 | 30 | public Info(Context context, String item, int schemaRevision) 31 | { 32 | this.item = item; 33 | this.schemaRevision = schemaRevision; 34 | this.files = new ArrayList<>(); 35 | initDetails(context); 36 | } 37 | 38 | public Info(Context context, String surveyGuid, String surveyCreatedOn) 39 | { 40 | this.surveyGuid = surveyGuid; 41 | this.surveyCreatedOn = surveyCreatedOn; 42 | this.files = new ArrayList<>(); 43 | initDetails(context); 44 | } 45 | 46 | private void initDetails(Context context) 47 | { 48 | String versionName; 49 | PackageManager manager = context.getPackageManager(); 50 | 51 | try 52 | { 53 | PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); 54 | versionName = info.versionName; 55 | } 56 | catch(PackageManager.NameNotFoundException e) 57 | { 58 | LogExt.e(getClass(), "Could not find package version info"); 59 | versionName = context.getString(R.string.rss_settings_version_unknown); 60 | } 61 | 62 | String fullPhoneInfo = Build.MANUFACTURER + " " + Build.MODEL; 63 | phoneInfo = fullPhoneInfo.substring(0, 64 | Math.min(fullPhoneInfo.length(), BRIDGE_PHONE_INFO_LIMIT)); 65 | appVersion = versionName; 66 | } 67 | 68 | public void addFileInfo(FileInfo fileInfo) 69 | { 70 | files.add(fileInfo); 71 | } 72 | 73 | public String getFileName() 74 | { 75 | return UUID.randomUUID().toString() + "_" + (item == null ? surveyGuid : item) + ".zip"; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_remove.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 16 | 23 | 26 | 29 | 30 | 37 | 40 | 44 | 45 | 52 | 55 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_mole_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 21 | 22 | 30 | 37 | 43 | 44 | 45 | 53 | 60 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/UploadValidationStatus.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import com.google.gson.annotations.SerializedName; 3 | 4 | import java.util.List; 5 | 6 | public final class UploadValidationStatus 7 | { 8 | /** 9 | * Represents the lifecycle of an upload object. 10 | */ 11 | public enum UploadStatus 12 | { 13 | /** 14 | * Upload status is unknown. 15 | */ 16 | @SerializedName("unknown") 17 | UNKNOWN, 18 | 19 | /** 20 | * Initial state. Upload is requested. User needs to upload to specified URL and call 21 | * uploadComplete. 22 | */ 23 | @SerializedName("requested") 24 | REQUESTED, 25 | 26 | /** 27 | * User has called uploadComplete. Upload validation is currently taking place. 28 | */ 29 | @SerializedName("validation_in_progress") 30 | VALIDATION_IN_PROGRESS, 31 | 32 | /** 33 | * Upload validation has failed. 34 | */ 35 | @SerializedName("validation_failed") 36 | VALIDATION_FAILED, 37 | 38 | /** 39 | * Upload has succeeded, including validation. 40 | */ 41 | @SerializedName("succeeded") 42 | SUCCEEDED 43 | } 44 | 45 | private final String id; 46 | private final List messageList; 47 | private final UploadStatus status; 48 | 49 | /** 50 | * Private constructor. All construction should go through the builder. 51 | */ 52 | private UploadValidationStatus(String id, List messageList, UploadStatus status) 53 | { 54 | this.id = id; 55 | this.messageList = messageList; 56 | this.status = status; 57 | } 58 | 59 | /** 60 | * Unique upload ID, as generated by the request upload API. Always non-null and non-empty. 61 | * 62 | * @return id 63 | */ 64 | public String getId() 65 | { 66 | return id; 67 | } 68 | 69 | /** 70 | *

    List of validation messages, generally contains error messages. Since a single upload 71 | * file may fail validation in multiple ways, Bridge server will attempt to return all messages 72 | * to the user. For example, the upload file might be unencrypted, uncompressed, and it might 73 | * not fit any of the expected schemas for the study.

    This field is always non-null, 74 | * but it may be empty. The list is immutable and contains non-null, non-empty strings.

    75 | * 76 | * @return messageList 77 | */ 78 | public List getMessageList() 79 | { 80 | return messageList; 81 | } 82 | 83 | /** 84 | * Represents upload status, such as requested, validation in progress, validation failed, or 85 | * succeeded. Always non-null. 86 | * 87 | * @return uploadStatus 88 | */ 89 | public UploadStatus getStatus() 90 | { 91 | return status; 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/PhotoCaptureActivity.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | import android.app.Activity; 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import org.researchstack.backbone.ui.PinCodeActivity; 8 | import org.researchstack.molemapper.ui.fragment.CameraFragment; 9 | import org.researchstack.molemapper.ui.fragment.PhotoCaptureCallbacks; 10 | 11 | ; 12 | 13 | public class PhotoCaptureActivity extends PinCodeActivity implements PhotoCaptureCallbacks 14 | { 15 | public static final String TAG = PhotoCaptureActivity.class.getSimpleName(); 16 | public static final String KEY_TYPE = TAG + ".TYPE"; 17 | public static final String KEY_ID = TAG + ".ID"; 18 | public static final String KEY_INSTRUCTION = TAG + ".INSTRUCTION"; 19 | public static final String KEY_PATH = TAG + ".PATH"; 20 | 21 | public static final int REQUEST_CODE_ZONE = 9012; 22 | public static final int REQUEST_CODE_MOLE = 9013; 23 | public static final int ZONE = 0; 24 | public static final int MOLE = 1; 25 | 26 | public static Intent newIntent(Context context, int type, int id) 27 | { 28 | Intent intent = new Intent(context, PhotoCaptureActivity.class); 29 | intent.putExtra(KEY_ID, id); 30 | intent.putExtra(KEY_TYPE, type); 31 | intent.putExtra(KEY_PATH, getTypeImagePath(type, id)); 32 | return intent; 33 | } 34 | 35 | public static String getTypeImagePath(int type, int id) 36 | { 37 | if (type == ZONE) 38 | { 39 | return "/zones/zone_" + id; 40 | } 41 | 42 | // If we are taking a picture of a mole then its for MoleMeasurementActivity. Place it in a 43 | // temp dir. 44 | else if (type == MOLE) 45 | { 46 | return "/temp/temp_zone_" + id + ".temp"; 47 | } 48 | else 49 | { 50 | throw new IllegalArgumentException("Invalid type " + type); 51 | } 52 | } 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) 56 | { 57 | super.onCreate(savedInstanceState); 58 | super.setContentView(R.layout.activity_photo); 59 | 60 | if(null == savedInstanceState) 61 | { 62 | int id = getIntent().getIntExtra(KEY_ID, 0); 63 | String desc = getIntent().getStringExtra(KEY_INSTRUCTION); 64 | String path = getIntent().getStringExtra(KEY_PATH); 65 | int type = getIntent().getIntExtra(KEY_TYPE, MOLE); 66 | getFragmentManager().beginTransaction() 67 | .replace(R.id.container, CameraFragment.newInstance(id, type, desc, path)) 68 | .commit(); 69 | } 70 | } 71 | 72 | @Override 73 | public void captureCanceled() 74 | { 75 | setResult(Activity.RESULT_CANCELED); 76 | finish(); 77 | } 78 | 79 | @Override 80 | public void captureCompleted() 81 | { 82 | setResult(Activity.RESULT_OK, getIntent()); 83 | finish(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMapperResearchStack.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | 3 | import android.content.Context; 4 | 5 | import net.sqlcipher.database.SQLiteDatabase; 6 | 7 | import org.researchstack.backbone.storage.database.AppDatabase; 8 | import org.researchstack.backbone.storage.database.sqlite.UpdatablePassphraseProvider; 9 | import org.researchstack.backbone.storage.file.EncryptionProvider; 10 | import org.researchstack.backbone.storage.file.FileAccess; 11 | import org.researchstack.backbone.storage.file.PinCodeConfig; 12 | import org.researchstack.backbone.storage.file.SimpleFileAccess; 13 | import org.researchstack.backbone.storage.file.aes.AesProvider; 14 | import org.researchstack.skin.AppPrefs; 15 | import org.researchstack.skin.DataProvider; 16 | import org.researchstack.skin.PermissionRequestManager; 17 | import org.researchstack.skin.ResearchStack; 18 | import org.researchstack.skin.ResourceManager; 19 | import org.researchstack.skin.TaskProvider; 20 | import org.researchstack.skin.UiManager; 21 | import org.researchstack.skin.notification.NotificationConfig; 22 | import org.researchstack.skin.notification.SimpleNotificationConfig; 23 | 24 | public class MoleMapperResearchStack extends ResearchStack 25 | { 26 | 27 | @Override 28 | protected AppDatabase createAppDatabaseImplementation(Context context) 29 | { 30 | SQLiteDatabase.loadLibs(context); 31 | return new Database(context, new UpdatablePassphraseProvider()); 32 | } 33 | 34 | @Override 35 | protected FileAccess createFileAccessImplementation(Context context) 36 | { 37 | return new SimpleFileAccess(); 38 | } 39 | 40 | @Override 41 | protected PinCodeConfig getPinCodeConfig(Context context) 42 | { 43 | long autoLockTime = AppPrefs.getInstance(context).getAutoLockTime(); 44 | return new PinCodeConfig(autoLockTime); 45 | } 46 | 47 | @Override 48 | protected EncryptionProvider getEncryptionProvider(Context context) 49 | { 50 | return new AesProvider(); 51 | } 52 | 53 | @Override 54 | protected ResourceManager createResourceManagerImplementation(Context context) 55 | { 56 | return new MoleMapperResourceManager(); 57 | } 58 | 59 | @Override 60 | protected UiManager createUiManagerImplementation(Context context) 61 | { 62 | return new MoleMapperUiManager(); 63 | } 64 | 65 | @Override 66 | protected DataProvider createDataProviderImplementation(Context context) 67 | { 68 | return new MoleMapperDataProvider(); 69 | } 70 | 71 | @Override 72 | protected TaskProvider createTaskProviderImplementation(Context context) 73 | { 74 | return new MoleMapperTaskProvider(context); 75 | } 76 | 77 | @Override 78 | protected NotificationConfig createNotificationConfigImplementation(Context context) 79 | { 80 | return new SimpleNotificationConfig(); 81 | } 82 | 83 | @Override 84 | protected PermissionRequestManager createPermissionRequestManagerImplementation(Context context) 85 | { 86 | return new MoleMappePermissionRequestManager(); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/MoleEditDialog.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui; 2 | import android.app.Dialog; 3 | import android.content.Context; 4 | import android.support.v7.app.AlertDialog; 5 | import android.support.v7.view.ContextThemeWrapper; 6 | import android.text.TextUtils; 7 | import android.view.Gravity; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | import android.widget.EditText; 12 | 13 | import org.researchstack.molemapper.R; 14 | import org.researchstack.molemapper.models.Mole; 15 | 16 | /** 17 | * TODO Refactor into class 18 | */ 19 | public class MoleEditDialog 20 | { 21 | 22 | public static Dialog newInstance(Context context, Mole mole, boolean allowEdit, MoleEditCallbacks callbacks) 23 | { 24 | LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(context, 25 | R.style.Dialog_Body)); 26 | View layout = inflater.inflate(R.layout.dialog_edit, null); 27 | 28 | Dialog dialog = new AlertDialog.Builder(context, R.style.Dialog_Body).show(); 29 | dialog.setCancelable(true); 30 | 31 | layout.findViewById(R.id.dialog_mole_cancel).setOnClickListener(v -> { 32 | dialog.dismiss(); 33 | callbacks.onCancel(); 34 | }); 35 | 36 | View remove = layout.findViewById(R.id.dialog_edit_remove); 37 | if(allowEdit) 38 | { 39 | remove.setOnClickListener(v -> { 40 | dialog.dismiss(); 41 | callbacks.onDeleteMole(); 42 | }); 43 | } 44 | else 45 | { 46 | remove.setVisibility(View.GONE); 47 | } 48 | 49 | EditText editText = (EditText) layout.findViewById(R.id.dialog_edit_edittext); 50 | editText.setText(mole.moleName); 51 | layout.findViewById(R.id.dialog_mole_update).setOnClickListener(v -> { 52 | dialog.dismiss(); 53 | 54 | String newTitle = editText.getText().toString(); 55 | 56 | // Update title if its not empty and not the same 57 | if(! TextUtils.isEmpty(newTitle) && ! newTitle.equals(mole.moleName)) 58 | { 59 | callbacks.onUpdateMoleName(newTitle); 60 | } 61 | 62 | // Clear Focus 63 | editText.clearFocus(); 64 | }); 65 | 66 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 67 | params.copyFrom(dialog.getWindow().getAttributes()); 68 | params.width = WindowManager.LayoutParams.MATCH_PARENT; 69 | params.height = WindowManager.LayoutParams.WRAP_CONTENT; 70 | params.gravity = Gravity.CENTER; 71 | dialog.setContentView(layout); 72 | dialog.getWindow().setAttributes(params); 73 | dialog.getWindow() 74 | .clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 75 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 76 | return dialog; 77 | } 78 | 79 | public interface MoleEditCallbacks 80 | { 81 | void onCancel(); 82 | 83 | void onDeleteMole(); 84 | 85 | void onUpdateMoleName(String newTitle); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/view/AutoFitTextureView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.researchstack.molemapper.ui.view; 18 | 19 | import android.content.Context; 20 | import android.graphics.Canvas; 21 | import android.util.AttributeSet; 22 | import android.view.TextureView; 23 | 24 | /** 25 | * A {@link TextureView} that can be adjusted to a specified aspect ratio. 26 | */ 27 | public class AutoFitTextureView extends TextureView 28 | { 29 | 30 | private int mRatioWidth = 0; 31 | private int mRatioHeight = 0; 32 | 33 | public AutoFitTextureView(Context context) 34 | { 35 | this(context, null); 36 | } 37 | 38 | public AutoFitTextureView(Context context, AttributeSet attrs) 39 | { 40 | this(context, attrs, 0); 41 | } 42 | 43 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) 44 | { 45 | super(context, attrs, defStyle); 46 | } 47 | 48 | /** 49 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio 50 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that 51 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result. 52 | * 53 | * @param width Relative horizontal size 54 | * @param height Relative vertical size 55 | */ 56 | public void setAspectRatio(int width, int height) 57 | { 58 | if(width < 0 || height < 0) 59 | { 60 | throw new IllegalArgumentException("Size cannot be negative."); 61 | } 62 | mRatioWidth = width; 63 | mRatioHeight = height; 64 | requestLayout(); 65 | } 66 | 67 | @Override 68 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 69 | { 70 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 71 | int width = MeasureSpec.getSize(widthMeasureSpec); 72 | int height = MeasureSpec.getSize(heightMeasureSpec); 73 | if(0 == mRatioWidth || 0 == mRatioHeight) 74 | { 75 | setMeasuredDimension(width, height); 76 | } 77 | else 78 | { 79 | if(width < height * mRatioWidth / mRatioHeight) 80 | { 81 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); 82 | } 83 | else 84 | { 85 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); 86 | } 87 | } 88 | } 89 | 90 | @Override 91 | public void onDrawForeground(Canvas canvas) 92 | { 93 | super.onDrawForeground(canvas); 94 | } 95 | } -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/models/Measurement.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.models; 2 | import java.io.Serializable; 3 | import java.util.Date; 4 | 5 | import co.touchlab.squeaky.field.DatabaseField; 6 | import co.touchlab.squeaky.table.DatabaseTable; 7 | 8 | /** 9 | * Created by bradleymcdermott on 2/4/16. 10 | */ 11 | @DatabaseTable 12 | public class Measurement implements Serializable 13 | { 14 | @DatabaseField(generatedId = true) 15 | public int id; 16 | 17 | /** 18 | * Image Path for the current measurement. Path is initially stored with a temp name of 19 | * mole_{MOLE_ID}. After the object is initially saved and an ID is provided by the ORM, the 20 | * this temp file is moved and renamed to /mole_measurement_{MEASUREMENT_ID} and updated. 21 | */ 22 | @DatabaseField 23 | public String measurementPhoto; 24 | 25 | /** 26 | * Value in DP 27 | */ 28 | @DatabaseField 29 | public float measurementX; 30 | 31 | /** 32 | * Value in DP 33 | */ 34 | @DatabaseField 35 | public float measurementY; 36 | 37 | /** 38 | * Value in DP 39 | */ 40 | @DatabaseField 41 | public float measurementDiameter; 42 | 43 | /** 44 | * Value in Millimeters 45 | */ 46 | @DatabaseField 47 | public float absoluteMoleDiameter; 48 | 49 | /** 50 | * Value in DP 51 | */ 52 | @DatabaseField 53 | public float referenceX; 54 | 55 | /** 56 | * Value in DP 57 | */ 58 | @DatabaseField 59 | public float referenceY; 60 | 61 | /** 62 | * Value in DP 63 | */ 64 | @DatabaseField 65 | public float referenceDiameter; 66 | 67 | /** 68 | * Value in Millimeters 69 | */ 70 | @DatabaseField 71 | public float absoluteReferenceDiameter; 72 | 73 | /** 74 | * int id that should be position of the object within your reference-object-array 75 | */ 76 | @DatabaseField 77 | public String referenceObject; 78 | 79 | /** 80 | * Date object is set when entering the MoleMeasurementActivity as thats closer to the time the 81 | * picture was taken. 82 | */ 83 | @DatabaseField 84 | public Date date; 85 | 86 | @DatabaseField(foreign = true) 87 | public Mole mole; 88 | 89 | public Measurement() 90 | { 91 | } 92 | 93 | public Measurement(String measurementPhoto, float measurementDiameter, float measurementX, float measurementY, float absoluteMoleDiameter, float referenceX, float referenceY, float referenceDiameter, String referenceObject, float absoluteReferenceDiameter, Date date, Mole mole) 94 | { 95 | this.measurementPhoto = measurementPhoto; 96 | this.measurementDiameter = measurementDiameter; 97 | this.measurementX = measurementX; 98 | this.measurementY = measurementY; 99 | this.absoluteMoleDiameter = absoluteMoleDiameter; 100 | this.referenceX = referenceX; 101 | this.referenceY = referenceY; 102 | this.referenceDiameter = referenceDiameter; 103 | this.referenceObject = referenceObject; 104 | this.absoluteReferenceDiameter = absoluteReferenceDiameter; 105 | this.date = date; 106 | this.mole = mole; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/MoleMapperUiManager.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper; 2 | import android.content.Context; 3 | 4 | import org.researchstack.backbone.answerformat.BooleanAnswerFormat; 5 | import org.researchstack.backbone.result.StepResult; 6 | import org.researchstack.backbone.step.QuestionStep; 7 | import org.researchstack.backbone.step.Step; 8 | import org.researchstack.molemapper.ui.MoleLearnActivity; 9 | import org.researchstack.molemapper.ui.fragment.MoleDashboardFragment; 10 | import org.researchstack.molemapper.ui.fragment.MoleMapperFragment; 11 | import org.researchstack.skin.ActionItem; 12 | import org.researchstack.skin.UiManager; 13 | import org.researchstack.skin.task.OnboardingTask; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class MoleMapperUiManager extends UiManager 19 | { 20 | /** 21 | * @return List of NavigationItems 22 | */ 23 | @Override 24 | public List getMainTabBarItems() 25 | { 26 | List navItems = new ArrayList<>(); 27 | 28 | navItems.add(new ActionItem.ActionItemBuilder().setId(R.id.nav_body_map) 29 | .setTitle(R.string.body_map) 30 | .setIcon(R.drawable.ic_tabbar_moles) 31 | .setClass(MoleMapperFragment.class) 32 | .build()); 33 | 34 | navItems.add(new ActionItem.ActionItemBuilder().setId(R.id.nav_dashboard) 35 | .setTitle(R.string.rss_dashboard) 36 | .setIcon(R.drawable.ic_tabbar_dashboard) 37 | .setClass(MoleDashboardFragment.class) 38 | .build()); 39 | 40 | return navItems; 41 | } 42 | 43 | @Override 44 | public List getMainActionBarItems() 45 | { 46 | List navItems = new ArrayList<>(); 47 | 48 | navItems.add(new ActionItem.ActionItemBuilder().setId(R.id.nav_learn) 49 | .setTitle(R.string.learn_more) 50 | .setIcon(R.drawable.ic_action_info) 51 | .setClass(MoleLearnActivity.class) 52 | .build()); 53 | 54 | navItems.add(new ActionItem.ActionItemBuilder().setId(R.id.nav_settings) 55 | .setTitle(R.string.rss_settings) 56 | .setIcon(R.drawable.ic_action_settings) 57 | .setClass(MoleMapperSettingsActivity.class) 58 | .build()); 59 | 60 | return navItems; 61 | } 62 | 63 | @Override 64 | public Step getInclusionCriteriaStep(Context context) 65 | { 66 | QuestionStep step = new QuestionStep(OnboardingTask.SignUpInclusionCriteriaStepIdentifier); 67 | step.setStepTitle(R.string.rss_eligibility); 68 | step.setTitle(context.getString(R.string.eligibility_title)); 69 | step.setText(context.getString(R.string.eligibility_text)); 70 | step.setAnswerFormat(new BooleanAnswerFormat(context.getString(R.string.rsb_yes), 71 | context.getString(R.string.rsb_no))); 72 | step.setOptional(false); 73 | return step; 74 | } 75 | 76 | @Override 77 | public boolean isInclusionCriteriaValid(StepResult stepResult) 78 | { 79 | return stepResult != null ? ((StepResult) stepResult).getResult() : false; 80 | } 81 | 82 | @Override 83 | public boolean isConsentSkippable() 84 | { 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | MoleMapper Android is an open source port of the [Mole Mapper](https://github.com/Sage-Bionetworks/MoleMapper) ResearchKit(TM) melanoma research study to ResearchStack. 4 | 5 | This implementation of MoleMapper on Android was created to serve as an open source example of best practices for creating a production-ready ResearchStack application. Initial funding was generous provided by a grant from the Robert Wood Johnson Foundation. 6 | 7 | Oregon Health & Science University will be posting their public fork of Mole Mapper for Android in the near future, which will more closely follow the Mole Mapper Android app (being released soon by OHSU on Google Play). We will prove links to that project and the app on Google Play as they become available. 8 | 9 | # About MoleMapper 10 | 11 | Mole Mapper is a personalized tool to help you map, measure, and monitor the moles on your skin. Using a familiar Maps-like interface, you can measure the size of a mole using the camera and a common reference object like a coin. 12 | 13 | If you are 18 or older, Mole Mapper also gives you the option to participate in a research study developed in partnership with researchers at Oregon Health & Science University and Sage Bionetworks, a 501 (c)(3) nonprofit research organization to better understand skin biology and melanoma risks. 14 | 15 | Keeping track of the size, shape and color of your moles is the best way to catch potential skin cancers like melanoma in their early stages. Whether you use Mole Mapper to keep track of a single suspicious mole over time or construct a full-body map, we hope this app will make being vigilant about your health a bit more enjoyable. 16 | 17 | The MoleMapper research study was created in partnership with researchers at Oregon Health & Science University and Sage Bionetworks. Unless otherwise noted, it should be assumed that all images, logos, and trademarks are copyrighted and should be used only with permission of the original copyright owners. 18 | 19 | Happy Mapping! 20 | 21 | ### 3rd-party library disclosures 22 | 23 | 24 | com.android.support:appcompat-v7
    25 | com.android.support:cardview-v7
    26 | com.android.support:design 27 |
    28 | 29 | - Used for theming and styling views within the app. Libraries also provide backward-compatible versions of Android framework APIs (e.g. vector icon support) 30 | 31 | com.android.support:support-v13:23.2.0 32 | 33 | - Support is a set of code libraries that provide backward-compatible versions of Android framework APIs. We use support for FragmentCompat and its use in receiving the results for permission requests. 34 | 35 | com.android.support:multidex 36 | 37 | - The Android MultiDex support library enables us to go past the default 65K method limit for an android project. 38 | 39 | com.davemorrissey.labs:subsampling-scale-image-view 40 | 41 | - Used within the MoleMeasurementActivity, allows user to zoom and pan an image with subsampling for low impact on memory 42 | 43 | co.touchlab.squeaky:squeaky-processor:0.4.0.0 44 | 45 | - Annotation processor for the Squeaky ORMLite database library. The library creates auto-generated code at compile time for our database pojos (see Mole or Measurement classes) 46 | 47 | 48 | pl.charmas.android:android-reactive-location
    49 | com.google.android.gms:play-services-location
    50 |
    51 | - play-services-location allows the app to get the user's location while being conscious of battery life. Android-reactive-location library wraps the location services API’s in Rx Observables. 52 | 53 | com.crashlytics.sdk.android:crashlytics 54 | 55 | - Crash / Logging library being used during the QA period. This library will be removed at v1.0 release. 56 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/ui/view/PhotoGridView.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.ui.view; 2 | import android.annotation.TargetApi; 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.PorterDuff; 8 | import android.graphics.PorterDuffXfermode; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | public class PhotoGridView extends View 13 | { 14 | private Paint paint; 15 | private Paint cutoutPaint; 16 | 17 | 18 | public PhotoGridView(Context context) 19 | { 20 | super(context); 21 | init(); 22 | } 23 | 24 | public PhotoGridView(Context context, AttributeSet attrs) 25 | { 26 | super(context, attrs); 27 | init(); 28 | } 29 | 30 | public PhotoGridView(Context context, AttributeSet attrs, int defStyleAttr) 31 | { 32 | super(context, attrs, defStyleAttr); 33 | init(); 34 | } 35 | 36 | @TargetApi(21) 37 | public PhotoGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 38 | { 39 | super(context, attrs, defStyleAttr, defStyleRes); 40 | init(); 41 | } 42 | 43 | int lineSize; 44 | 45 | private void init() 46 | { 47 | setLayerType(LAYER_TYPE_SOFTWARE, null); 48 | 49 | lineSize = (int) (getResources().getDisplayMetrics().density * 2 + .5f); 50 | 51 | paint = new Paint(); 52 | paint.setAntiAlias(true); 53 | paint.setColor(Color.WHITE); 54 | paint.setStrokeWidth(lineSize); 55 | paint.setAlpha(102); 56 | 57 | cutoutPaint = new Paint(); 58 | cutoutPaint.setAntiAlias(true); 59 | cutoutPaint.setColor(Color.TRANSPARENT); 60 | cutoutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 61 | } 62 | 63 | @Override 64 | protected void onDraw(Canvas canvas) 65 | { 66 | super.onDraw(canvas); 67 | 68 | // Draw transparent black 69 | canvas.drawColor(0x66000000); 70 | 71 | // Draw cut-out 72 | canvas.drawRect(getPaddingLeft(), 73 | getPaddingTop(), 74 | getWidth() - getPaddingRight(), 75 | getHeight() - getPaddingBottom(), 76 | cutoutPaint); 77 | 78 | // Set guide style 79 | paint.setStyle(Paint.Style.FILL); 80 | paint.setColor(0x66FFFFFF); 81 | 82 | // Draw vertical guides 83 | canvas.drawRect(getPaddingLeft(), 0, getPaddingLeft() + lineSize, getHeight(), paint); 84 | canvas.drawRect(getWidth() - getPaddingRight() - lineSize, 85 | 0, 86 | getWidth() - getPaddingRight(), 87 | getHeight(), 88 | paint); 89 | 90 | // Draw horizontal guides 91 | canvas.drawRect(0, getPaddingTop(), getWidth(), getPaddingTop() + lineSize, paint); 92 | canvas.drawRect(0, 93 | getHeight() - getPaddingBottom() - lineSize, 94 | getWidth(), 95 | getHeight() - getPaddingBottom(), 96 | paint); 97 | 98 | // Set guide box style 99 | paint.setColor(Color.WHITE); 100 | paint.setStyle(Paint.Style.STROKE); 101 | 102 | // Draw guide box 103 | float strokeOffset = (int) (paint.getStrokeWidth() / 2f + .5f); 104 | canvas.drawRect(getPaddingLeft() + strokeOffset, 105 | getPaddingTop() + strokeOffset, 106 | getWidth() - getPaddingRight() - strokeOffset, 107 | getHeight() - getPaddingBottom() - strokeOffset, 108 | paint); 109 | 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/task/FollowupTask.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.task; 2 | import android.content.Context; 3 | 4 | import org.researchstack.backbone.answerformat.AnswerFormat; 5 | import org.researchstack.backbone.answerformat.BooleanAnswerFormat; 6 | import org.researchstack.backbone.step.FormStep; 7 | import org.researchstack.backbone.step.InstructionStep; 8 | import org.researchstack.backbone.step.QuestionStep; 9 | import org.researchstack.backbone.step.Step; 10 | import org.researchstack.backbone.task.OrderedTask; 11 | import org.researchstack.backbone.task.Task; 12 | import org.researchstack.molemapper.R; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class FollowupTask 18 | { 19 | public static final String TASK_FOLLOW_UP = "followup"; 20 | 21 | public static final String TAN = "tan"; 22 | public static final String SUNBURN = "sunburn"; 23 | public static final String SUNSCREEN = "sunscreen"; 24 | public static final String SICK = "sick"; 25 | public static final String MOLE_REMOVED = "moleRemoved"; 26 | public static final String FOLLOWUP_FORM = "followupInfo"; 27 | 28 | private FollowupTask() 29 | { 30 | } 31 | 32 | public static Task create(Context context) 33 | { 34 | List steps = new ArrayList<>(); 35 | 36 | InstructionStep intro = new InstructionStep("intro", 37 | context.getString(R.string.task_followup_title), 38 | context.getString(R.string.task_followup_text)); 39 | intro.setStepTitle(R.string.mole_follow_up); 40 | 41 | FormStep followupInfo = new FormStep(FOLLOWUP_FORM, null, null); 42 | followupInfo.setStepTitle(R.string.mole_follow_up); 43 | followupInfo.setOptional(false); 44 | 45 | ArrayList followupItems = new ArrayList<>(); 46 | AnswerFormat booleanAnswerFormat = new BooleanAnswerFormat(context.getString(R.string.rsb_yes), 47 | context.getString(R.string.rsb_no)); 48 | 49 | QuestionStep tan = new QuestionStep(TAN, 50 | context.getString(R.string.task_followup_tan_title), 51 | booleanAnswerFormat); 52 | tan.setOptional(false); 53 | followupItems.add(tan); 54 | 55 | QuestionStep sunburn = new QuestionStep(SUNBURN, 56 | context.getString(R.string.task_followup_sunburn_title), booleanAnswerFormat); 57 | sunburn.setOptional(false); 58 | followupItems.add(sunburn); 59 | 60 | QuestionStep sunscreen = new QuestionStep(SUNSCREEN, 61 | context.getString(R.string.task_followup_sunscreen_title), booleanAnswerFormat); 62 | sunscreen.setOptional(false); 63 | followupItems.add(sunscreen); 64 | 65 | QuestionStep sick = new QuestionStep(SICK, 66 | context.getString(R.string.task_followup_sick_title), booleanAnswerFormat); 67 | sick.setOptional(false); 68 | followupItems.add(sick); 69 | 70 | QuestionStep removed = new QuestionStep(MOLE_REMOVED, 71 | context.getString(R.string.task_followup_removed_title), booleanAnswerFormat); 72 | removed.setOptional(false); 73 | followupItems.add(removed); 74 | 75 | followupInfo.setFormSteps(followupItems); 76 | 77 | InstructionStep thankYouStep = new InstructionStep("thankYou", 78 | context.getString(R.string.task_followup_thankyou_title), 79 | context.getString(R.string.task_followup_thankyou_text)); 80 | thankYouStep.setStepTitle(R.string.mole_follow_up); 81 | 82 | steps.add(intro); 83 | steps.add(followupInfo); 84 | steps.add(thankYouStep); 85 | 86 | return new OrderedTask(TASK_FOLLOW_UP, steps); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 30 | 31 | 41 | 42 | 54 | 55 | 62 | 63 | 74 | 75 | 89 | 90 | -------------------------------------------------------------------------------- /app/src/main/java/org/researchstack/molemapper/bridge/BridgeEncryptedDatabase.java: -------------------------------------------------------------------------------- 1 | package org.researchstack.molemapper.bridge; 2 | import android.content.Context; 3 | import android.text.format.DateUtils; 4 | 5 | import net.sqlcipher.database.SQLiteDatabase; 6 | 7 | import org.researchstack.backbone.storage.database.sqlite.SqlCipherDatabaseHelper; 8 | import org.researchstack.backbone.storage.database.sqlite.UpdatablePassphraseProvider; 9 | import org.researchstack.backbone.utils.LogExt; 10 | 11 | import java.sql.SQLException; 12 | import java.util.List; 13 | 14 | import co.touchlab.squeaky.dao.Dao; 15 | import co.touchlab.squeaky.db.sqlcipher.SQLiteDatabaseImpl; 16 | import co.touchlab.squeaky.table.TableUtils; 17 | 18 | /** 19 | * Created by bradleymcdermott on 3/8/16. 20 | */ 21 | public class BridgeEncryptedDatabase extends SqlCipherDatabaseHelper implements UploadQueue 22 | { 23 | public BridgeEncryptedDatabase(Context context, String name, SQLiteDatabase.CursorFactory cursorFactory, int version, UpdatablePassphraseProvider passphraseProvider) 24 | { 25 | super(context, name, cursorFactory, version, passphraseProvider); 26 | } 27 | 28 | @Override 29 | public void onCreate(SQLiteDatabase sqLiteDatabase) 30 | { 31 | super.onCreate(sqLiteDatabase); 32 | try 33 | { 34 | TableUtils.createTables(new SQLiteDatabaseImpl(sqLiteDatabase), UploadRequest.class); 35 | } 36 | catch(SQLException e) 37 | { 38 | throw new RuntimeException(e); 39 | } 40 | } 41 | 42 | @Override 43 | public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) 44 | { 45 | super.onUpgrade(sqLiteDatabase, oldVersion, newVersion); 46 | // handle future db upgrades here 47 | } 48 | 49 | public void saveUploadRequest(UploadRequest uploadRequest) 50 | { 51 | LogExt.d(this.getClass(), "saveUploadRequest() id: " + uploadRequest.id); 52 | 53 | try 54 | { 55 | this.getDao(UploadRequest.class).createOrUpdate(uploadRequest); 56 | } 57 | catch(SQLException e) 58 | { 59 | throw new RuntimeException(e); 60 | } 61 | } 62 | 63 | public UploadRequest loadNextUploadRequest() 64 | { 65 | try 66 | { 67 | // don't get spam the same request, ignore requests tried less than a minute ago 68 | // also grab random one so we don't get stuck on one failing request for some reason 69 | long aMinAgo = System.currentTimeMillis() - DateUtils.MINUTE_IN_MILLIS; 70 | Dao dao = this.getDao(UploadRequest.class); 71 | List requests = dao.query("uploadDate <= ?", new String[] { 72 | String.valueOf(aMinAgo) 73 | }).orderBy("RANDOM()").limit(1).list(); 74 | 75 | if(requests.isEmpty()) 76 | { 77 | return null; 78 | } 79 | else 80 | { 81 | UploadRequest request = requests.get(0); 82 | // set attempted upload time so explained above 83 | request.uploadDate = System.currentTimeMillis(); 84 | dao.update(request); 85 | 86 | return request; 87 | } 88 | } 89 | catch(SQLException e) 90 | { 91 | throw new RuntimeException(e); 92 | } 93 | } 94 | 95 | public void deleteUploadRequest(UploadRequest request) 96 | { 97 | 98 | LogExt.d(this.getClass(), "deleteUploadRequest() id: " + request.id); 99 | 100 | try 101 | { 102 | this.getDao(UploadRequest.class).delete(request); 103 | } 104 | catch(SQLException e) 105 | { 106 | throw new RuntimeException(e); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/assets/html/consent_section_html_sharing_rsch.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sharing Research 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | This study gives you the option to share your data in 2 ways: 18 |
      19 |
    1. Share with the research world (“Share broadly”): You can choose to share your 20 | study data with the study team and its partners and your coded study data with 21 | qualified researchers worldwide for use in this research and beyond. Coded study 22 | data is data that does not include personal information such as your name or 23 | email. Qualified researchers are registered users of Synapse who have agreed to 24 | use the data in an ethical manner for research purposes, and have agreed to not 25 | attempt to re-identify you. If you choose to share your coded study data, the 26 | metadata (your response to survey questions and the mole measurements without 27 | the mole photo) will be added to a shared dataset available to qualified 28 | researchers on the Sage Bionetworks Synapse servers at synapse.org. Your mole 29 | photos will be available to qualified researchers who have received ethical 30 | approval to use the photos for their research. Sage Bionetworks will have no 31 | oversight on the future research that qualified researchers may conduct with the 32 | coded study data. 33 |
    2. 34 | 35 |
    3. Only share with the study team (“Share sparsely”): You can choose to share your 36 | study data only with the study team and its partners. The study team includes 37 | the Principal Investigator of the research and any other researchers or partners 38 | named in the consent document. Sharing your study data this way means that your 39 | data will not be made available to anyone other than those listed in the consent 40 | document for the purposes of this study, and to be part of and to be part of the 41 | OHSU War on Melanoma™ Community Registry. If required by law, your study data, 42 | account information and the signed consent form may be disclosed to: 43 |
        44 |
      • The US Department of Health and Human Services, the Office for Human 45 | Research Protection, and other agencies for verification of the research 46 | procedures and data. 47 |
      • 48 |
      • Institutional Review Board who monitors the safety, effectiveness and 49 | conduct of the research being conducted 50 |
      • 51 | 52 |
      • The results of this research study may be presented at meetings or in 53 | publications. If the results of this study are made public, only coded 54 | study data and de-identified mole photos will be used, that is, your 55 | personal information will not be disclosed. 56 |
      • 57 |
      58 |
    4. 59 |
    60 | You can change the data sharing setting though the app preference at anytime. For 61 | additional information review the study privacy policy 62 |
    63 |
    64 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_chart_general.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 17 | 18 | 24 | 25 | 30 | 31 | 37 | 38 | 43 | 44 | 45 | 46 | 54 | 55 | 56 | 57 | 63 | 64 | 71 | 72 | 80 | 81 | 82 | 83 | 87 | 88 | 96 | 97 | 98 | 99 | --------------------------------------------------------------------------------