Git Product home page Git Product logo

dimagi / commcare-android Goto Github PK

View Code? Open in Web Editor NEW
37.0 28.0 25.0 316.38 MB

Offline First Android software client for CommCare, the world's largest platform for designing, managing, and deploying robust mobile applications to frontline workers worldwide

Home Page: https://www.dimagi.com/open-source/

License: Apache License 2.0

Java 82.43% Python 0.71% Shell 0.03% CSS 0.02% JavaScript 9.74% Kotlin 7.06% Ruby 0.02%
mobile-data-collection android mhealth global-development xforms social-impact global-health java

commcare-android's Introduction

commcare-android

CommCare is an easily customizable, open source mobile platform that supports frontline workers in low-resource settings. By replacing paper-based forms, frontline workers can use CommCare to track and support their clients with registration forms, checklists, SMS reminders, and multimedia.

This repository represents the Android version of CommCare. It depends on the CommCare Core repository, which contains the XForm engine and case/lookup table implementations.

Setup

To set up an Android dev environment for commcare-android, do the following:

  • Install Android Studio.
  • Install Java 17 if you don't have it yet. For ease of test suite setup (see below) OpenJDK is preferred over Oracle's version of Java.

Go ahead and open Android Studio if this is your first time using it; it may take you through some sort of setup wizard, and it's nice to get that out of the way. If it's not the first time, ensure that there are no references to removed Java options in your environment, most commonly found are MaxPermSize and PermSize

Android Studio's default project space is ~/AndroidStudioProjects so I'm going to use that in the example. CommCare Android depends on CommCare Core, and CommCare Android expects the core directory to live side by side in your directory structure. You can acheive this with the following commands (in bash):

cd ~/AndroidStudioProjects
mkdir CommCare
cd CommCare
git clone https://github.com/dimagi/commcare-android.git
git clone https://github.com/dimagi/commcare-core.git
  • Open Android Studio
  • If this is your first time using Android Studio, click "Config" and setup the Android SDK.
  • Download the Android 12 (API 31) SDK Platform and the Google APIs for 31.
  • Now go back to the Android Studio Welcome dashboard and click "Import project (Eclipse ADT, Gradle, etc.)"
  • Select AndroidStudioProjects > CommCare > commcare-android and hit OK
  • Click "OK" to use the Gradle wrapper
  • Wait while Android Studio spins its wheels
  • Download any build dependencies that the SDK Manager tells you you need.
  • Disable Instant Run found in Settings > Build, Execution, Deployment > Instant Run. (It does not play well with multidexing, which we have enabled, or with some of the processes we have set up for Google Services)

Building

Now you're basically ready to go. To build CommCare Android and get it running on your phone, plug in an android phone that

In Android Studio, hit the build button (a green "play" symbol in the toolbar). The first build will take a minute. Then it'll ask you what device to run it on

  • Make sure your screen is unlocked (or else you'll see something like this)
  • select your device

Enjoy!

Building from the command-line

CommCare has several different build variants. The normal build variant is commcare and can built built from the command-line with the following command:

cd commcare-android
./gradlew assembleCommcareDebug
# the apk can now be found in the build/outputs/apk/ directory

Unit Tests

The commcare-android repository uses Robolectric, which provides mocks, allowing you to run Android specific code on your local machine.

Run unit-tests from the command-line

cd commcare-android
./gradlew testCommcareDebug

and view the results from the output file generated.

Run unit-tests from Android Studio

Create a new Android Studio JUnit Build configuration using the following steps.

  • Click Run -> Edit Configruations and create a new JUnit configuration by pressing the green plus button.
  • Set Name to "commcare android test suite"
  • Set Test kind to "All in directory"
  • set Directory to /absolute/path/to/commcare-android/app/unit-tests/src/
  • Right click on this directory and click the "Create 'All Tests'" option that should be listed more than half-way down the list.
  • Set VM options to -ea -noverify
  • Set Working directory to /absolute/path/to/commcare-android/app/
  • Set Use classpath of module to app
  • Click OK to finish creating the configuration.
  • Select the "commcare android test suite" under the configuration drop down to the left of the green play button.
  • Press the green play button to run the tests.

Instrumentation Tests

The commcare-android repository uses Espresso to write UI tests. You need to have two keys in your gradle.properties before being able to run any instrumentation tests. But make sure you never commit these keys to github.

HQ_API_USERNAME=<ASK_ANOTHER_DEV_FOR_KEY>
HQ_API_PASSWORD=<ASK_ANOTHER_DEV_FOR_KEY>

Run instrumentation-tests from the command-line

cd commcare-android
./gradlew connectedCommcareDebugAndroidTest

It's also a common requirement to run a particular test, such as when you’re fixing a bug or developing a new test. You can achieve the same in command-line using:

./gradlew connectedCommcareDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=<FULLY_QUALIFIED_NAME_OF_YOUR_TEST>

You can view the results from the output file generated.

Run instrumentation-tests from Android Studio

Before running tests from Android-Studio make sure you've disabled animations in your device. Note, this is only required when you're running tests from Android Studio

Go to Setting -> Developer Options, and under the Drawing section, switch all of the following options:

Window animation scale -> off
Transition animation scale -> off
Animator duration scale -> off

Create a new Android Studio Android Instrumented Test Build configuration using the following steps.

  • Click Run -> Edit Configruations and create a new Android Instrumented Test configuration by pressing the green plus button.
  • Set Name to "commcare android instrumentation tests"
  • Set Test kind to "All in Package"
  • set Package to org.commcare.androidTests
  • Click OK to finish creating the configuration.
  • Select the "commcare android instrumentation tests" under the configuration drop down to the left of the green play button.
  • Press the green play button to run the tests.

Run instrumentation-tests skipped on browserstack

cd commcare-android
./gradlew connectedCommcareDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.notAnnotation=org.commcare.annotations.BrowserstackTests

Code Style Settings

In order to comply with code style guidelines we follow, please use Commcare Coding Style file and Commcare Inspection Profile as your respective code style and inpection profile in Android Studio. To do so follow these instructions

  1. Copy the config files to your Android Studio installation as follows (Replace AndroidStudio3.0 with the respective directory for the AS version you are using) -
cp .android_studio_settings/inspection/CommCare\ Inpsection\ Profile.xml ~/Library/Preferences/AndroidStudio3.0/inspection/.

cp .android_studio_settings/codestyles/CommCare\ Coding\ Style.xml ~/Library/Preferences/AndroidStudio3.0/codestyles/.  

  1. Restart Android Studio

  2. Go to AS preferences -> Editor -> Code Style and select Scheme as 'Commcare Coding Style' and to AS preferences -> Editor -> Inspections and select Profile as 'Commcare Inspection Profile'

Common Errors

If you experience the following exception when running individual tests from Android Studio Editor on Mac

No such manifest file: build/intermediates/bundles/debug/AndroidManifest.xml

If you are on a Mac, you will probably need to configure the default JUnit test runner configuration in order to work around a bug where IntelliJ / Android Studio does not set the working directory to the module being tested. This can be accomplished by editing the run configurations, Defaults -> JUnit and changing the working directory value to $MODULE_DIR$

Error on attempt to install CommCare app on phone: Unknown failure during app install

Android Monitor in Android Studio shows the following exceptions:

java.lang.RuntimeException: CommCare ran into an issue deserializing data while inflating type
    ...
Caused by: org.javarosa.core.util.externalizable.DeserializationException:
No datatype registered to serialization code [4b a9 e5 89]

Resolution:

  • Disable Instant Run found in Settings > Build, Execution, Deployment > Instant Run.

  • Maybe also edit ~/.gradle/gradle.properties (may not exist) and add a line like org.gradle.jvmargs=-Xmx1536M if the build fails due to OOM or you see a message like the following during the build:

    To run dex in process, the Gradle daemon needs a larger heap.
    It currently has 1024 MB.
    For faster builds, increase the maximum heap size for the Gradle daemon to at least 1536 MB.
    To do this set org.gradle.jvmargs=-Xmx1536M in the project gradle.properties.
    
  • Click Run 'app' to rebuid and run on phone.

commcare-android's People

Contributors

amsagoff avatar amstone326 avatar avazirna avatar benrudolph avatar biyeun avatar charl1996 avatar ctsims avatar czue avatar dannyroberts avatar dcluna avatar dependabot[bot] avatar emord avatar kbo001 avatar lu16j avatar millerdev avatar noahcarnahan avatar orangeandgreen avatar orangejenny avatar philomates avatar proteusvacuum avatar rristovic avatar shivampokhriyal avatar shubham1g5 avatar sjain28 avatar snopoke avatar stephherbers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

commcare-android's Issues

Improve image capture resizing

The current naive strategy for downsampling captured images doesn't perform well when resizing images with light patterns, as they end up very stippled. We should experiment with different platform methods for resizing which don't amplify these underlying shadow overlays

image

Divide By Zero Error in Edge Case with Automatic Image resizing

There is a bug in automated image resizing when an image's existing / native size size is exactly the width of the screen.

Discovered with a specific image and replicated with the following virtual device profile:
image

Adding this 456x456 image as the multimedia image for a question label with the above device screen parameters should result in a crash. I can't quite remember if the bug was when this image was 456x456 or 480x480 (exact screen size or size minus padding maybe), but resizing to one of those should work.
download

Further Context: https://dimagi.atlassian.net/browse/SUPPORT-16630

Fuzzy matching isn't a good fit for some searches

Entity lists currently support fuzzy matching as a global option, but fuzzy matches are a poor fit for some types of search results like QR code scans.

To support this, individual fields should probably support their own tags for what types of matches are relevant / desirable. Fields with canonical inputs rather than 'human' inputs should have different matching criteria.

Relevant user feedback discussion

Impossible to make a selection on owner_id in Case Content Provider

Hello!

This is Milen from Simprints. I'm currently working on an integration with CommCare's Case Content Provider and I believe I have found a bug in it's implementation. Following this documentation I'm trying to access the case metadata listing and make a selection based on the owner_id. This is my code:

selection = "owner_id = ?"
selectionArgs = arrayOf(decryptedAttendantId.value)
val caseMetadataCursor = context.contentResolver.query(CASE_METADATA_URI, null, selection, selectionArgs, null)

However, I'm getting a null cursor and looking at the logs from CommCare I see the following exception:

java.lang.RuntimeException: Invalid selection key for case metadata: owner_id

Digging in your code I found out that the OWNER_ID column is actually defined as "owner_ID". I tried passing "owner_ID" in my selection but got the exact same exception. Digging further in your code I found this line which converts all selection keys to lowercase. This essentially makes it impossible to make a selection on the "owner_ID" column.

Let me know if I'm missing something or if you need any more info!

Resolve Strict Mode violations

Turning Strict mode with death penalty currently causes app to crash at several places. There does not appear to be much logging around why these issues are occuring. We should look more into these violations and try to resolve them if possible.

Clean up Any references to J2ME settings

Clean up following J2ME properties from test files (these should not be getting used anywhere in live code) -

  • properties.password_format  # Password Format
    
  • properties.cc-send-procedure  # Send Data
    
  • properties.server-tether  # Sync Mode
    
  • features.sense  # CommCare Sense
    
  • properties.extra_key_action  # Extra Key Action
    
  • properties.cc-entry-mode  # Item Selection Mode
    
  • properties.cc-send-unsent  # Send Forms Mode
    
  • properties.ViewStyle  # Form Entry Style
    
  • properties.cc-user-mode  # User Login Mode
    
  • properties.cc-login-images # Login Buttons
    

Resolve instrumentation test flakiness.

  • Fix Allow GPS popup on opening a form.
  • Browserstack sometimes automatically re-open wifi, after we manually disableWifi causing tests to fail.
  • Update FormSubmissionTest to directly use the submitted form instance ID for receiving acknowledgement.
  • Fix and revert #2381

Improve user location feedback in case list maps

The Case List Map feature supports a single roaming indicator of the user's current position, based on the current location reading from the device.

This single geopoint is helpful but limited in helping users to most effectively use the map for 'homing' tasks where the user is attempting to use the map to physically navigate to a precise GPS point.

The following would be strong additions:

  • Include an accuracy circle which can communicate the uncertainty in the user's current location
  • When accuracy is sufficiently poor (above some threshold), remove the 'dot' indicating the user's current location, to prevent them from misinterpreting it as an accurate depiction
  • Provide a pop-over banner on the screen when a user's location is sufficiently inaccurate, to inform them as to why they can't see their precise location
  • Support for the "compass" functionality otherwise available in google maps, in which a cone is thrown based on the direction the device is facing, allowing users to disambiguate between equally close points

Log usage of `cc-enforce-secure-endpoint` in Analytics

We would like to deprecate cc-enforce-secure-endpoint property, though we are not sure if there are self hosters utilising this. We should log any usage of this property in Analytics to be able to verify if it's getting used by anyone.

Respect image orientation during resizing

When image resizing is used in captured images, EXIF Data is currently stripped. Since most Cameras in Android don't natively rotate the pixels in a photo, but rather set the orientation captured in EXIF, this means that resized images don't display in the same orientation as the original captured photo.

We should either pass-through some EXIF info during resizing, or read the orientation flag and manually rotate the captured image.

Allow the use of a custom Barcode Scanning Application

Right now we solely use the embedded zxing library, but there are circumstances where users might want to jump out to a much more powerful version that's more appropriate for their device or use case.

The need for this would be negated by implementing #2321, but that's potentially a significantly larger scope of work compared to a fallback option for telling the barcode scanner to use the traditional zxing intent, rather than the built-in one.

This seems to me like an App setting rather than a callout specific setting, so I think the best course of action would be to make it an application preference ("Use intent callout for scanner") that is loaded in the FormEntryActivity and passed into the widget factory .

Passthrough Allow-Listed EXIF properties (GPS specifically) with resized images

The image capture process creates a new copy of the source image without passing through any existing captured EXIF properties. In most cases this makes sense because details about the captured image (Camera, resolution, etc) are no longer meaningfully true, but most notably this means that GPS / Geolocation data is stripped.

There isn't total consistency in what EXIF properties exist and are valid, but the common tags for location data could be retained without significantly concern. It would be worth a quick look to see if there are any other common properties that users may want to retain.

Move tests to espresso.

  • DeletedUser
  • FormEntry
  • Fixtures
  • MenuTests
  • Login
  • FormSettings
  • CaseSharing
  • Languages
  • CaseListSearch
  • CaseListSort
  • Settings
  • FormFiltering
  • Tiles
  • SessionExpiration
  • Dialogs
  • InstallList
  • DemoUserOnline
  • DemoUserOffline
  • LookupTableOptionSorting
  • ManualQuarantine
  • LogSubmission

Support either a "long" or a "short" text appearance

Currently the String Widget doesn't support EditorInfo.IME_ACTION_NEXT like numeric entry widgets, since it's mixed use for both "short" text entry (IE: Names on one line) and for long (multiline paragraph entry) cases.

This is very unfortunate for the 99% use case of short text entry. It would be great to support both, and eventually transition the default behavior to be 'short' once people have had enough time to adjust defaults.

feature request: allow arbitrarily named string as IntentCallout responses

The IntentCallout activity assumes that called services have knowledge of ODK's incredibly specific expectations. Namely that the result be bundled and named odk_intent_data. This makes the callout feature unusable when trying to receive a result from most applications.

Would it be possible to see if odk_intent_data is actually returned, and if not try to getString() for the available keys that match the requested keys? Even if you can only handle strings, it would go a long way to making generally IntentCallout useful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.