Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.odk.collect.android.feature.formentry

import android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.provider.MediaStore
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import org.hamcrest.Matcher
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.odk.collect.android.storage.StoragePathProvider
import org.odk.collect.android.support.StorageUtils
import org.odk.collect.android.support.rules.FormEntryActivityTestRule
import org.odk.collect.android.support.rules.TestRuleChain.chain
import org.odk.collect.androidtest.RecordedIntentsRule
import org.odk.collect.draw.DrawActivity
import org.odk.collect.testshared.WaitFor.waitFor
import org.odk.collect.strings.R.string
import org.odk.collect.testshared.AssertionFramework
import java.io.File
import java.io.FileOutputStream

class ImageCompressionTest {
private val rule = FormEntryActivityTestRule()

@get:Rule
var chain: RuleChain = chain()
.around(RecordedIntentsRule())
.around(rule)

@Test
fun imageWidget_scalesCapturedImageDownToMaxPixels() {
rule
.setUpProjectAndCopyForm("image-compression.xml")
.fillNewForm("image-compression.xml", "image-compression")
.also {
stubCaptureReturningImage(hasAction(MediaStore.ACTION_IMAGE_CAPTURE))
}.clickOnString(string.capture_image, AssertionFramework.COMPOSE)

assertSavedImageWasScaledDownToMaxPixels()
Comment thread
grzesiek2010 marked this conversation as resolved.
Outdated
}

@Test
fun annotateWidget_scalesCapturedImageDownToMaxPixels() {
rule
.setUpProjectAndCopyForm("image-compression.xml")
.fillNewForm("image-compression.xml", "image-compression")
.swipeToNextQuestion("Annotate")
.also {
stubCaptureReturningImage(hasAction(MediaStore.ACTION_IMAGE_CAPTURE))
}.clickOnString(string.capture_image)

assertSavedImageWasScaledDownToMaxPixels()
}

@Test
fun drawWidget_scalesCapturedImageDownToMaxPixels() {
rule
.setUpProjectAndCopyForm("image-compression.xml")
.fillNewForm("image-compression.xml", "image-compression")
.swipeToNextQuestion("Annotate")
.swipeToNextQuestion("Draw")
.also {
stubCaptureReturningImage(hasComponent(DrawActivity::class.java.name))
}.clickOnString(string.draw_image)

assertSavedImageWasScaledDownToMaxPixels()
}

@Test
fun signatureWidget_scalesCapturedImageDownToMaxPixels() {
rule
.setUpProjectAndCopyForm("image-compression.xml")
.fillNewForm("image-compression.xml", "image-compression")
.swipeToNextQuestion("Annotate")
.swipeToNextQuestion("Draw")
.swipeToNextQuestion("Signature")
.also {
stubCaptureReturningImage(hasComponent(DrawActivity::class.java.name))
}.clickOnString(string.sign_button)

assertSavedImageWasScaledDownToMaxPixels()
}

private fun stubCaptureReturningImage(captureIntent: Matcher<Intent>) {
// Long edge (2000) is twice the form's max image size, so it should be scaled down to 1000.
val bitmap = Bitmap.createBitmap(2000, 1000, Bitmap.Config.ARGB_8888)
Comment thread
grzesiek2010 marked this conversation as resolved.
Outdated
val tmpImage = File(StoragePathProvider().getTmpImageFilePath())
FileOutputStream(tmpImage).use { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, it) }

Intents.intending(captureIntent).respondWith(
Instrumentation.ActivityResult(Activity.RESULT_OK, null)
)
}

private fun assertSavedImageWasScaledDownToMaxPixels() {
waitFor {
val instanceDir = File(StorageUtils.getInstancesDirPath()).listFiles()!!.single()
val image = instanceDir.listFiles()!!.single { it.extension.equals("jpg", ignoreCase = true) }

val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeFile(image.absolutePath, options)
assertThat(maxOf(options.outWidth, options.outHeight), equalTo(1000))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,9 @@ abstract class Page<T : Page<T>> {
return destination
}

fun clickOnString(stringID: Int): T {
clickOnText(getTranslatedString(stringID))
@JvmOverloads
fun clickOnString(stringID: Int, assertionFramework: AssertionFramework = AssertionFramework.ESPRESSO): T {
clickOnText(getTranslatedString(stringID), assertionFramework)
return this as T
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.odk.collect.android.utilities.ImageCompressionController;
import org.odk.collect.android.widgets.BaseImageWidget;
import org.odk.collect.android.widgets.QuestionWidget;
import org.odk.collect.android.widgets.image.ImageWidget;
import org.odk.collect.androidshared.ui.DialogFragmentUtils;
import org.odk.collect.settings.SettingsProvider;

Expand Down Expand Up @@ -52,7 +53,7 @@ protected File doInBackground(Uri... uris) {
QuestionWidget questionWidget = formFillingActivity.get().getWidgetWaitingForBinaryData();

// apply image conversion if the widget is an image widget
if (questionWidget instanceof BaseImageWidget) {
if (questionWidget instanceof BaseImageWidget || questionWidget instanceof ImageWidget) {
Comment thread
grzesiek2010 marked this conversation as resolved.
Outdated
String imageSizeMode = settingsProvider.getUnprotectedSettings().getString(KEY_IMAGE_SIZE);
imageCompressionController.execute(newFile.getPath(), questionWidget, formFillingActivity.get(), imageSizeMode);
}
Expand Down
45 changes: 45 additions & 0 deletions test-forms/src/main/resources/forms/image-compression.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0"?>
<h:html
xmlns="http://www.w3.org/2002/xforms"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jr="http://openrosa.org/javarosa"
xmlns:orx="http://openrosa.org/xforms"
xmlns:odk="http://www.opendatakit.org/xforms">
<h:head>
<h:title>image-compression</h:title>
<model odk:xforms-version="1.0.0">
<instance>
<data id="image-compression">
<image/>
<annotate/>
<draw/>
<signature/>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<bind nodeset="/data/image" type="binary" orx:max-pixels="1000"/>
<bind nodeset="/data/annotate" type="binary" orx:max-pixels="1000"/>
<bind nodeset="/data/draw" type="binary" orx:max-pixels="1000"/>
<bind nodeset="/data/signature" type="binary" orx:max-pixels="1000"/>
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/>
</model>
</h:head>
<h:body>
<upload mediatype="image/*" ref="/data/image">
<label>Image</label>
</upload>
<upload appearance="annotate" mediatype="image/*" ref="/data/annotate">
<label>Annotate</label>
</upload>
<upload appearance="draw" mediatype="image/*" ref="/data/draw">
<label>Draw</label>
</upload>
<upload appearance="signature" mediatype="image/*" ref="/data/signature">
<label>Signature</label>
</upload>
</h:body>
</h:html>