diff --git a/RapidFTR-Android/res/layout/form_photo_thumbnail.xml b/RapidFTR-Android/res/layout/form_photo_thumbnail.xml deleted file mode 100644 index 2ae9e888..00000000 --- a/RapidFTR-Android/res/layout/form_photo_thumbnail.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/RapidFTR-Android/res/layout/form_photo_upload_box.xml b/RapidFTR-Android/res/layout/form_photo_upload_box.xml index c4b9613f..e3e0bc17 100644 --- a/RapidFTR-Android/res/layout/form_photo_upload_box.xml +++ b/RapidFTR-Android/res/layout/form_photo_upload_box.xml @@ -4,12 +4,19 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="fill_parent" + android:scrollbars="vertical"> - + diff --git a/RapidFTR-Android/res/layout/form_section.xml b/RapidFTR-Android/res/layout/form_section.xml index 3bec908e..a612041f 100644 --- a/RapidFTR-Android/res/layout/form_section.xml +++ b/RapidFTR-Android/res/layout/form_section.xml @@ -6,7 +6,8 @@ + android:layout_height="fill_parent" + android:scrollbars="vertical"> @@ -14,7 +15,8 @@ + android:layout_height="fill_parent" + android:scrollbars="vertical"/> diff --git a/RapidFTR-Android/res/menu/image_menu.xml b/RapidFTR-Android/res/menu/image_menu.xml new file mode 100644 index 00000000..b9409228 --- /dev/null +++ b/RapidFTR-Android/res/menu/image_menu.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/RapidFTR-Android/res/values-ar/strings.xml b/RapidFTR-Android/res/values-ar/strings.xml index ed1bcf63..892f235c 100644 --- a/RapidFTR-Android/res/values-ar/strings.xml +++ b/RapidFTR-Android/res/values-ar/strings.xml @@ -48,6 +48,7 @@ حدث خطأ عند تحميل الصورة لم يتم إلتقاط صورة للسجل غير قادر على مسح الصورة. الرجاء الذهاب إلى الأستوديو و مسحها يدويا + Set as primary photo تزامن الكل إلغاء تزامن الكل diff --git a/RapidFTR-Android/res/values-es/strings.xml b/RapidFTR-Android/res/values-es/strings.xml index f6d9b23b..ac560646 100644 --- a/RapidFTR-Android/res/values-es/strings.xml +++ b/RapidFTR-Android/res/values-es/strings.xml @@ -48,6 +48,7 @@ An error occurred while loading the photo No photo captured for the record Unable to delete photo from Gallery. Please go to Gallery and delete it manually + Set as primary photo Synchronize All Cancel Synchronize All diff --git a/RapidFTR-Android/res/values-fr/strings.xml b/RapidFTR-Android/res/values-fr/strings.xml index 45c7d0a3..cd6e30c5 100644 --- a/RapidFTR-Android/res/values-fr/strings.xml +++ b/RapidFTR-Android/res/values-fr/strings.xml @@ -49,6 +49,7 @@ An error occurred while loading the photo No photo captured for the record Unable to delete photo from Gallery. Please go to Gallery and delete it manually + Set as primary photo Synchronize All Cancel Synchronize All diff --git a/RapidFTR-Android/res/values-ru/strings.xml b/RapidFTR-Android/res/values-ru/strings.xml index 844eb182..ac9c38bb 100644 --- a/RapidFTR-Android/res/values-ru/strings.xml +++ b/RapidFTR-Android/res/values-ru/strings.xml @@ -48,6 +48,7 @@ An error occurred while loading the photo No photo captured for the record Unable to delete photo from Gallery. Please go to Gallery and delete it manually + Set as primary photo Synchronize All Cancel Synchronize All diff --git a/RapidFTR-Android/res/values-zh/strings.xml b/RapidFTR-Android/res/values-zh/strings.xml index 899d164f..fc814962 100644 --- a/RapidFTR-Android/res/values-zh/strings.xml +++ b/RapidFTR-Android/res/values-zh/strings.xml @@ -48,6 +48,7 @@ An error occurred while loading the photo No photo captured for the record Unable to delete photo from Gallery. Please go to Gallery and delete it manually + Set as primary photo Synchronize All Cancel Synchronize All diff --git a/RapidFTR-Android/res/values/strings.xml b/RapidFTR-Android/res/values/strings.xml index 2ff87a6d..1e3f7772 100644 --- a/RapidFTR-Android/res/values/strings.xml +++ b/RapidFTR-Android/res/values/strings.xml @@ -49,6 +49,8 @@ An error occurred while loading the photo No photo captured for the record Unable to delete photo from Gallery. Please go to Gallery and delete it manually + Set as primary photo + Synchronize All Cancel Synchronize All diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/activity/ViewPhotoActivity.java b/RapidFTR-Android/src/main/java/com/rapidftr/activity/ViewPhotoActivity.java index cebba6f8..dd5371e0 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/activity/ViewPhotoActivity.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/activity/ViewPhotoActivity.java @@ -1,7 +1,9 @@ package com.rapidftr.activity; +import android.content.Intent; import android.os.Bundle; import android.view.Menu; +import android.view.MenuItem; import android.widget.ImageView; import com.rapidftr.R; import com.rapidftr.utils.PhotoCaptureHelper; @@ -19,9 +21,24 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean onCreateOptionsMenu(Menu menu) { - return true; + if (getIntent().getBooleanExtra("enabled", false)) { + getMenuInflater().inflate(R.menu.image_menu, menu); + return true; + } + return false; } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.set_as_primary: + Intent intent = new Intent(); + intent.putExtra("file_name", getIntent().getStringExtra("file_name")); + setResult(RESULT_OK, intent); + finish(); + } + return true; + } protected ImageView getImageView() { return (ImageView) findViewById(R.id.photo); diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ChildViewAdapter.java b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ChildViewAdapter.java index aa2e8e26..3c90d03f 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ChildViewAdapter.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ChildViewAdapter.java @@ -47,11 +47,11 @@ public View getView(int position, View convertView, ViewGroup parent) { if (child != null) { TextView uniqueIdView = (TextView) view.findViewById(R.id.row_child_unique_id); TextView nameView = (TextView) view.findViewById(R.id.row_child_name); -// ImageView imageView = (ImageView) view.findViewById(R.id.thumbnail); + ImageView imageView = (ImageView) view.findViewById(R.id.thumbnail); try { setFields(String.valueOf(child.getShortId()), uniqueIdView); setFields(String.valueOf(child.optString("name")), nameView); -// assignThumbnail(child, imageView); + assignThumbnail(child, imageView); view.setOnClickListener(clickListener(child)); } catch (JSONException e) { diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java index 526aeb0c..1b0fa247 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/adapter/ImageAdapter.java @@ -53,6 +53,8 @@ public View getView(int position, View convertView, ViewGroup parent) { try { bitmap = photoCaptureHelper.getThumbnailOrDefault(photoKeys.get(position).toString()); imageView = new ImageView(context); + imageView.setPadding(0,0,0,0); + imageView.setAdjustViewBounds(true); imageView.setImageBitmap(bitmap); } catch (JSONException e) { throw new RuntimeException(e); diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/service/ChildService.java b/RapidFTR-Android/src/main/java/com/rapidftr/service/ChildService.java index 5dede6bb..f486e2a4 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/service/ChildService.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/service/ChildService.java @@ -32,6 +32,7 @@ import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; import static com.rapidftr.database.Database.ChildTableColumn.internal_id; +import static com.rapidftr.view.fields.PhotoUploadBox.PHOTO_KEYS; import static java.util.Arrays.asList; public class ChildService { @@ -96,11 +97,15 @@ private void setChildAttributes(Child child) throws JSONException { } private void addMultiMediaFilesToTheRequest(Child child) throws JSONException { - if (child.opt("current_photo_key") != null && !child.optString("current_photo_key").equals("")) { - List photoKeys = getPhotoKeys(child); - if (!photoKeys.contains(child.optString("current_photo_key"))) { - fluentRequest.param("current_photo_key", child.optString("current_photo_key")); + JSONArray photoKeys = child.optJSONArray(PHOTO_KEYS); + JSONArray photoKeysToAdd = new JSONArray(); + if(photoKeys != null){ + for(int i = 0; i< photoKeys.length(); i++){ + if(!photoKeys.optString(i).startsWith("photo-")){ + photoKeysToAdd.put(photoKeys.optString(i)); + } } + fluentRequest.param("photo_keys", photoKeysToAdd.toString()); } if (child.opt("recorded_audio") != null && !child.optString("recorded_audio").equals("")) { if (!getAudioKey(child).equals(child.optString("recorded_audio"))) { @@ -174,20 +179,32 @@ public Child apply(Map content) { public void setPhoto(Child child) throws IOException, JSONException { PhotoCaptureHelper photoCaptureHelper = new PhotoCaptureHelper(context); - String currentPhotoKey = child.optString("current_photo_key"); - try { - if (!currentPhotoKey.equals("")) { - photoCaptureHelper.getFile(currentPhotoKey, ".jpg"); + + JSONArray photoKeys = child.optJSONArray("photo_keys"); + if(photoKeys != null){ + getPhotoFromServerIfNeeded(child, photoCaptureHelper, photoKeys); + } + + } + + private void getPhotoFromServerIfNeeded(Child child, PhotoCaptureHelper photoCaptureHelper, JSONArray photoKeys) throws JSONException, IOException { + for(int i = 0; i < photoKeys.length(); i++){ + String photoKey = photoKeys.get(i).toString(); + try { + if (!photoKey.equals("")) { + photoCaptureHelper.getFile(photoKey, ".jpg"); + } + } + catch (FileNotFoundException e) { + getPhotoFromServer(child, photoCaptureHelper, photoKey); } - } catch (FileNotFoundException e) { - getPhotoFromServer(child, photoCaptureHelper, currentPhotoKey); } } - public void getPhotoFromServer(Child child, PhotoCaptureHelper photoCaptureHelper, String currentPhotoKey) throws IOException { - HttpResponse httpResponse = getPhoto(child); + public void getPhotoFromServer(Child child, PhotoCaptureHelper photoCaptureHelper, String fileName) throws IOException { + HttpResponse httpResponse = getPhoto(child, fileName); Bitmap bitmap = BitmapFactory.decodeStream(httpResponse.getEntity().getContent()); - savePhoto(bitmap, photoCaptureHelper, currentPhotoKey); + savePhoto(bitmap, photoCaptureHelper, fileName); } @@ -208,7 +225,7 @@ private void getAudioFromServer(Child child, AudioCaptureHelper audioCaptureHelp audioCaptureHelper.saveAudio(child, response.getEntity().getContent()); } - private void savePhoto(Bitmap bitmap, PhotoCaptureHelper photoCaptureHelper, String current_photo_key) throws IOException { + public void savePhoto(Bitmap bitmap, PhotoCaptureHelper photoCaptureHelper, String current_photo_key) throws IOException { if (bitmap != null && !current_photo_key.equals("")) { try { photoCaptureHelper.saveThumbnail(bitmap, 0, current_photo_key); @@ -219,9 +236,9 @@ private void savePhoto(Bitmap bitmap, PhotoCaptureHelper photoCaptureHelper, Str } } - public HttpResponse getPhoto(Child child) throws IOException { + public HttpResponse getPhoto(Child child, String fileName) throws IOException { return fluentRequest - .path(String.format("/children/%s/photo/%s", child.optString("_id"), child.optString("current_photo_key"))) + .path(String.format("/children/%s/photo/%s", child.optString("_id"), fileName)) .context(context) .get(); } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/utils/http/FluentRequest.java b/RapidFTR-Android/src/main/java/com/rapidftr/utils/http/FluentRequest.java index 7546457a..d96bc236 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/utils/http/FluentRequest.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/utils/http/FluentRequest.java @@ -24,15 +24,16 @@ import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; +import org.json.JSONArray; import org.json.JSONException; import java.io.*; import java.net.URI; +import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.*; @@ -126,11 +127,9 @@ protected FluentResponse executeMultiPart(HttpEntityEnclosingRequestBase request MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); if (params.size() > 0) { for (Map.Entry param : params.entrySet()){ - if(param.getKey().equals("current_photo_key")){ + if(param.getKey().equals("photo_keys")){ try { - multipartEntity.addPart("child[photo]", - new ByteArrayBody(IOUtils.toByteArray(new PhotoCaptureHelper((RapidFtrApplication) context).getDecodedImageStream(param.getValue())), - "image/jpg", param.getValue()+".jpg")); + addPhotoToMultipart(multipartEntity, param.getValue()); } catch (Exception e) { throw new RuntimeException(e); } @@ -156,13 +155,23 @@ protected FluentResponse executeMultiPart(HttpEntityEnclosingRequestBase request } } } - - } request.setEntity(multipartEntity); return execute(request); } + public void addPhotoToMultipart(MultipartEntity multipartEntity, String param) throws IOException, GeneralSecurityException, JSONException { + JSONArray photoKeys = new JSONArray(param); + for(int i = 0; i < photoKeys.length(); i++){ + multipartEntity.addPart("child[photo]["+i+"]", attachPhoto(photoKeys.get(i).toString())); + } + } + + protected ByteArrayBody attachPhoto(String fileName) throws IOException, GeneralSecurityException { + return new ByteArrayBody(IOUtils.toByteArray(new PhotoCaptureHelper((RapidFtrApplication) context).getDecodedImageStream(fileName)), + "image/jpg", fileName+".jpg"); + } + protected FluentResponse executeUnenclosed(HttpRequestBase request) throws IOException { if (params.size() > 0) { for (Map.Entry param : params.entrySet()) diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/view/fields/PhotoUploadBox.java b/RapidFTR-Android/src/main/java/com/rapidftr/view/fields/PhotoUploadBox.java index 6a8f0236..5d74e4f8 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/view/fields/PhotoUploadBox.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/view/fields/PhotoUploadBox.java @@ -9,6 +9,7 @@ import android.util.AttributeSet; import android.util.Log; import android.view.View; +import android.view.WindowManager; import android.widget.*; import com.rapidftr.R; import com.rapidftr.RapidFtrApplication; @@ -27,7 +28,9 @@ public class PhotoUploadBox extends BaseView implements RapidFtrActivity.ResultListener { public static final int CAPTURE_IMAGE_REQUEST = 100; + public static final int SHOW_FULL_IMAGE_REQUEST = 200; public static final String PHOTO_KEYS = "photo_keys"; + public static final String CURRENT_PHOTO_KEY = "current_photo_key"; protected PhotoCaptureHelper photoCaptureHelper; private boolean enabled; @@ -49,16 +52,24 @@ protected void initialize() throws JSONException { RapidFtrActivity activity = (RapidFtrActivity) getContext(); activity.addResultListener(CAPTURE_IMAGE_REQUEST, this); activity.addResultListener(CLOSE_ACTIVITY, this); - - getImageContainer().setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - onImageClick(); - } - }); + activity.addResultListener(SHOW_FULL_IMAGE_REQUEST, this); repaint(); } + private void toggleVisibility() { + if (enabled) { + getImageContainer().setVisibility(View.VISIBLE); + getImageContainer().setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onImageClick(); + } + }); + } else { + getImageContainer().setVisibility(View.GONE); + } + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -70,12 +81,18 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case CLOSE_ACTIVITY: deleteCapture(); break; + case SHOW_FULL_IMAGE_REQUEST: + if (data != null && data.getStringExtra("file_name") != null) { + child.put(CURRENT_PHOTO_KEY, data.getStringExtra("file_name")); + } + break; } } @Override public void setEnabled(boolean isEnabled) { this.enabled = isEnabled; + toggleVisibility(); } protected void deleteCapture() { @@ -85,14 +102,12 @@ protected void deleteCapture() { } public View getImageContainer() { - return findViewById(R.id.capture); + return findViewById(R.id.thumbnail); } public void onImageClick() { if (enabled) { startCapture(); - } else { - showFullPhoto(null); } } @@ -104,7 +119,8 @@ protected void showFullPhoto(String fileName) { } else { Intent intent = new Intent(context, ViewPhotoActivity.class); intent.putExtra("file_name", fileName); - context.startActivity(intent); + intent.putExtra("enabled", enabled); + context.startActivityForResult(intent, SHOW_FULL_IMAGE_REQUEST); } } catch (Exception e) { Toast.makeText(RapidFtrApplication.getApplicationInstance(), R.string.photo_view_error, Toast.LENGTH_LONG).show(); @@ -129,11 +145,18 @@ public void saveCapture() { Log.e("REGISTER", "start of async task "); new EncryptImageAsyncTask(getContext(), photoCaptureHelper, bitmap, fileName, this, rotationDegree).execute(); addPhotoToPhotoKeys(fileName); + addCurrentPhotoKeyIfNotPresent(fileName); } catch (Exception e) { Toast.makeText(RapidFtrApplication.getApplicationInstance(), R.string.photo_capture_error, Toast.LENGTH_LONG).show(); } } + private void addCurrentPhotoKeyIfNotPresent(String fileName) { + if (child.optString(CURRENT_PHOTO_KEY).equals("")) { + child.put(CURRENT_PHOTO_KEY, fileName); + } + } + private void addPhotoToPhotoKeys(String fileName) throws JSONException { if (child.optJSONArray(PHOTO_KEYS) == null) { JSONArray photo_keys = new JSONArray(); @@ -142,7 +165,6 @@ private void addPhotoToPhotoKeys(String fileName) throws JSONException { } else { child.getJSONArray(PHOTO_KEYS).put(fileName); } - child.put(formField.getId(), fileName); } protected String createCaptureFileName() { @@ -158,10 +180,28 @@ public void repaint() throws JSONException { final JSONArray photoKeys = child.optJSONArray(PHOTO_KEYS); addImageClickListener(photoGridView, photoKeys); if (photoKeys != null) { + setGridAttributes(photoGridView, photoKeys); photoGridView.setAdapter(new ImageAdapter(getContext(), child, photoCaptureHelper, enabled)); } } + protected void setGridAttributes(GridView photoGridView, JSONArray photoKeys) { + LayoutParams layoutParams = (LayoutParams) photoGridView.getLayoutParams(); + layoutParams.height = measureRealHeightForGridView(photoGridView, photoKeys.length()); + } + + private int measureRealHeightForGridView(GridView gridView, int imagesCount){ + WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + final int screenWidth = windowManager.getDefaultDisplay().getWidth(); + final double screenDensity = getResources().getDisplayMetrics().density; + final int horizontalSpacing = (int) (2 * screenDensity + 0.5f); + final int verticalSpacing = (int) (2 * screenDensity + 0.5f); + final int columnWidth = (int) (90 * screenDensity + 0.5f); + final int columnsCount = (screenWidth - gridView.getVerticalScrollbarWidth()) / (columnWidth + horizontalSpacing); + final int rowsCount = imagesCount / columnsCount + (imagesCount % columnsCount == 0 ? 0 : 1); + return columnWidth * rowsCount + verticalSpacing * (rowsCount - 1); + } + private void addImageClickListener(GridView photoGridView, final JSONArray photoKeys) { photoGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/service/ChildServiceTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/service/ChildServiceTest.java index 104090d2..6c5ecd84 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/service/ChildServiceTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/service/ChildServiceTest.java @@ -1,19 +1,22 @@ package com.rapidftr.service; +import android.graphics.Bitmap; import com.rapidftr.CustomTestRunner; import com.rapidftr.RapidFtrApplication; import com.rapidftr.database.Database; import com.rapidftr.model.Child; import com.rapidftr.model.User; import com.rapidftr.repository.ChildRepository; +import com.rapidftr.utils.PhotoCaptureHelper; import com.rapidftr.utils.http.FluentRequest; import com.xtremelabs.robolectric.tester.org.apache.http.TestHttpResponse; +import org.apache.http.entity.mime.MultipartEntity; import org.json.JSONArray; import org.json.JSONException; -import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Matchers; import org.mockito.Mock; import java.io.IOException; @@ -39,6 +42,7 @@ public class ChildServiceTest { @Mock private User currentUser; FluentRequest fluentRequest; + public static final String RESPONSE = "{\"unique_identifier\":\"adf7c0c9-0137-4cae-beea-b7d282344829\",\"created_at\":\"2013-02-08 12:18:37\",\"created_by_full_name\":\"RapidFTR\",\"couchrest-type\":\"Child\",\"short_id\":\"2344829\",\"_id\":\"b7f89b978870da823e0af6491c3e295b\",\"_rev\":\"2-bc72af384e177fcaa8e9e8d181bfe05b\",\"name\":\"\",\"last_updated_at\":\"2013-02-08 11:37:33\",\"current_photo_key\":\"photo--1475374810-2013-02-08T175138\",\"created_by\":\"rapidftr\",\"photo_keys\":[\"photo--1475374810-2013-02-08T175138\"],\"created_organisation\":\"N/A\",\"posted_at\":\"2013-02-08 12:16:55UTC\",\"last_updated_by_full_name\":\"RapidFTR\"}"; @Before public void setUp() throws Exception { @@ -49,12 +53,11 @@ public void setUp() throws Exception { @Test public void shouldParseJsonResponseAndConvertToChildren() throws IOException, JSONException { - String response = "{\"photo_keys\":[],\"evacuation_status\":\"\",\"id_document\":\"\",\"disclosure_authorities\":\"\",\"wishes_address_1\":\"\",\"ethnicity_or_tribe\":\"\",\"evacuation_date\":\"\",\"other_child_1_telephone\":\"\",\"concerns_followup_details\":\"\",\"nick_name\":\"\",\"rc_id_no\":\"\",\"wishes_name_3\":\"\",\"disclosure_deny_details\":\"\",\"concerns_needs_followup\":\"\",\"interview_place\":\"\",\"care_arrangements\":\"\",\"concerns_further_info\":\"\",\"fathers_name\":\"\",\"wishes_wants_contact\":\"\",\"governing_org\":\"\",\"disclosure_public_name\":\"\",\"other_child_2_telephone\":\"\",\"separation_details\":\"\",\"care_arrangements_address\":\"\",\"other_child_3\":\"\",\"caregivers_name\":\"\",\"separation_place\":\"\",\"mothers_name\":\"\",\"concerns_other\":\"\",\"wishes_telephone_2\":\"\",\"is_caregiver_alive\":\"\",\"disclosure_public_photo\":\"\",\"care_arrangements_came_from\":\"\",\"other_child_3_dob\":\"\",\"wishes_address_2\":\"\",\"couchrest-type\":\"Child\",\"_id\":\"be5d92ff528c8d82c8753934a7712eb1\",\"additional_tracing_info\":\"\",\"care_arrangments_name\":\"\",\"concerns_girl_mother\":\"\",\"_rev\":\"1-dfd36730cc723481387511804b21a320\",\"mother_death_details\":\"\",\"interview_subject\":\"\",\"other_org_place\":\"\",\"other_org_name\":\"\",\"care_arrangements_relationship\":\"\",\"wishes_name_1\":\"\",\"concerns_medical_case\":\"\",\"other_child_3_telephone\":\"\",\"disclosure_public_relatives\":\"\",\"concerns_chh\":\"\",\"wishes_contacted\":\"\",\"name\":\"Akash Bhalla\",\"unique_identifier\":\"fworkerxxxdea2f\",\"evacuation_from\":\"\",\"interview_subject_details\":\"\",\"father_death_details\":\"\",\"interview_date\":\"\",\"characteristics\":\"\",\"documents\":\"\",\"other_child_2_relationship\":\"\",\"evacuation_to\":\"\",\"created_by_full_name\":\"testing\",\"is_father_alive\":\"\",\"other_child_1_address\":\"\",\"names_origin\":\"\",\"wishes_telephone_3\":\"\",\"other_child_1\":\"\",\"birthplace\":\"\",\"care_arrangements_arrival_date\":\"\",\"other_child_1_relationship\":\"\",\"other_child_3_birthplace\":\"\",\"concerns_street_child\":\"\",\"wishes_address_3\":\"\",\"telephone\":\"\",\"other_child_2_birthplace\":\"\",\"other_child_1_birthplace\":\"\",\"current_photo_key\":null,\"protection_status\":\"\",\"care_arrangements_knowsfamily\":\"\",\"care_arrangements_other\":\"\",\"histories\":[],\"interviewers_org\":\"\",\"created_by\":\"fworker\",\"other_child_3_relationship\":\"\",\"concerns_abuse_situation\":\"\",\"address\":\"\",\"wishes_name_2\":\"\",\"other_child_1_dob\":\"\",\"other_org_interview_status\":\"\",\"gender\":\"\",\"posted_from\":\"Browser\",\"nationality\":\"\",\"separation_date\":\"\",\"other_child_2_dob\":\"\",\"evacuation_agent\":\"\",\"wishes_contacted_details\":\"\",\"other_family\":\"\",\"created_at\":\"2012-10-26 09:28:39UTC\",\"languages\":\"\",\"other_child_3_address\":\"\",\"is_mother_alive\":\"\",\"other_org_country\":\"\",\"dob_or_age\":\"\",\"concerns_disabled\":\"\",\"other_org_date\":\"\",\"concerns_vulnerable_person\":\"\",\"care_arrangements_familyinfo\":\"\",\"disclosure_other_orgs\":\"\",\"interviewer\":\"\",\"orther_org_reference_no\":\"\",\"other_child_2\":\"\",\"wishes_telephone_1\":\"\",\"other_child_2_address\":\"\",\"posted_at\":\"2012-10-26 09:28:39UTC\"}"; - getFakeHttpLayer().setDefaultHttpResponse(201, "[" + response + "]"); + getFakeHttpLayer().setDefaultHttpResponse(201, "[" + RESPONSE + "]"); List children = new ChildService(mockContext(), repository, fluentRequest).getAllChildren(); assertThat(children.size(), is(1)); - assertThat(children.get(0), equalTo(new Child(response))); + assertThat(children.get(0), equalTo(new Child(RESPONSE))); } @Test @@ -95,18 +98,22 @@ public void shouldCreateNewChildIfThereIsNoID() throws Exception { verify(repository).update(child); } - @Test(expected = SyncFailedException.class) - public void shouldAddPhotoParamIfPhotoIsCapturedAsPartOfChildAndThePhotoNameIsNotPresentInPhotoKeys() throws JSONException, IOException, GeneralSecurityException { + @Test + public void shouldAddPhotoKeysToParam() throws JSONException, IOException, GeneralSecurityException { + getFakeHttpLayer().setDefaultHttpResponse(201, RESPONSE ); + RapidFtrApplication context = mockContext(); FluentRequest mockFluentRequest = spy(new FluentRequest()); + ChildService childService = spy(new ChildService(context, repository, mockFluentRequest)); - String photoKeys = new JSONArray(Arrays.asList("photo-998877", "photo-998547")).toString(); + + String photoKeys = new JSONArray(Arrays.asList("photo-998877", "photo-998547", "abcd123", "1234ABC")).toString(); String childDetails = String.format("{ '_id' : 'abcdef', 'name' : 'child1', 'test2' : 0, 'current_photo_key' : '1234ABC', 'photo_keys' : %s}", photoKeys); Child child = new Child("id1", "user1", childDetails); - RapidFtrApplication context = mockContext(); - doReturn(null).when(mockFluentRequest).put(); - new ChildService(context, repository, mockFluentRequest).sync(child, currentUser); - verify(mockFluentRequest).param("current_photo_key", "1234ABC"); + doNothing().when(mockFluentRequest).addPhotoToMultipart(Matchers.any(MultipartEntity.class), Matchers.any(String.class)); + doNothing().when(childService).savePhoto(Matchers.any(Bitmap.class), Matchers.any(PhotoCaptureHelper.class), Matchers.anyString()); + childService.sync(child, currentUser); + verify(mockFluentRequest).param("photo_keys", new JSONArray(Arrays.asList("abcd123", "1234ABC")).toString()); } @Test(expected = SyncFailedException.class) @@ -179,19 +186,25 @@ public void shouldUpdateChildAttributesAfterSync() throws IOException, JSONExcep assertThat(syncedChild.getString("_attachments"), is(nullValue())); } - @Test(expected = RuntimeException.class) + @Test public void shouldSetMediaIfNotAlreadyExistingOnTheMobile() throws JSONException, IOException { FluentRequest mockFluentRequest = spy(new FluentRequest()); RapidFtrApplication context = mockContext(); - String response = "{\"recorded_audio\":\"audio-12321\",\"photo_keys\": \"[photo-998,photo-888]\",\"_id\":\"abcd\",\"current_photo_key\": \"photo-998877\",\"separation_place\":\"\",\"wishes_address_3\":\"\",\"care_arrangments_name\":\"\",\"other_family\":\"\",\"care_arrangements_knowsfamily\":\"\",\"created_at\":\"2012-12-14 10:57:39UTC\",\"wishes_contacted_details\":\"\",\"posted_from\":\"Browser\"}"; + String response = "{\"recorded_audio\":\"audio-12321\",\"photo_keys\": \"[photo-998,photo-888, photo-777]\",\"_id\":\"abcd\",\"current_photo_key\": \"photo-888\",\"separation_place\":\"\",\"wishes_address_3\":\"\",\"care_arrangments_name\":\"\",\"other_family\":\"\",\"care_arrangements_knowsfamily\":\"\",\"created_at\":\"2012-12-14 10:57:39UTC\",\"wishes_contacted_details\":\"\",\"posted_from\":\"Browser\"}"; + ChildService childService = spy(new ChildService(context, repository, mockFluentRequest)); getFakeHttpLayer().setDefaultHttpResponse(200, response); - Child child = new Child("id","user","{ 'name' : 'child1'}"); - new ChildService(context, repository, mockFluentRequest).sync(child, currentUser); - verify(mockFluentRequest).path("/children/abcd/photo/photo-998877"); - verify(mockFluentRequest).path("/children/abcd/audio"); + doNothing().when(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-998")); + doNothing().when(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-888")); + doNothing().when(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-777")); + + childService.sync(child, currentUser); + verify(mockFluentRequest).path("/children/abcd/audio"); + verify(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-888")); + verify(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-998")); + verify(childService).getPhotoFromServer(Matchers.any(Child.class), Matchers.any(PhotoCaptureHelper.class),eq("photo-777")); } @Test @@ -200,7 +213,7 @@ public void shouldFetchPrimaryPhotoFromServer() throws JSONException, IOExceptio Child child = new Child("id1", "user1", "{ '_id' : '1234abcd' ,'current_photo_key' : 'image_file_name'}"); getFakeHttpLayer().setDefaultHttpResponse(200, "image stream"); - new ChildService(mockContext(), repository, mockFluentRequest).getPhoto(child); + new ChildService(mockContext(), repository, mockFluentRequest).getPhoto(child, "image_file_name"); verify(mockFluentRequest).path("/children/1234abcd/photo/image_file_name"); } diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java index c751e06b..9df2fa7f 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/utils/PhotoCaptureHelperTest.java @@ -113,6 +113,7 @@ public void testReturnDefaultThumbnail() throws Exception { public void testReturnOriginalThumbnail() throws Exception { Bitmap expected = mock(Bitmap.class); doReturn(expected).when(photoCaptureHelper).loadThumbnail("random_file"); + doReturn(new File("random_file.jpg")).when(photoCaptureHelper).getFile("random_file", ".jpg"); Bitmap actual = photoCaptureHelper.getThumbnailOrDefault("random_file"); assertThat(actual, equalTo(expected)); diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/utils/http/FluentRequestTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/utils/http/FluentRequestTest.java index d0deaab0..86d20333 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/utils/http/FluentRequestTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/utils/http/FluentRequestTest.java @@ -7,13 +7,19 @@ import com.xtremelabs.robolectric.tester.org.apache.http.RequestMatcher; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.mime.MultipartEntity; +import org.apache.http.entity.mime.content.ByteArrayBody; +import org.apache.http.entity.mime.content.ContentBody; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.json.JSONException; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Matchers; import java.io.IOException; +import java.security.GeneralSecurityException; import java.security.Security; import static com.rapidftr.utils.http.FluentRequest.http; @@ -149,6 +155,18 @@ public void testExecuteShouldCallReset() throws IOException { verify(http).reset(); } + @Test + public void shouldAddImageMultiPartsFromPhotoKeys() throws IOException, GeneralSecurityException, JSONException { + FluentRequest fluentRequest = spy(new FluentRequest()); + String photoKeys = "[\"abcd\", \"1234\"]"; + MultipartEntity multipartEntity = spy(new MultipartEntity()); + doReturn(new ByteArrayBody("content body".getBytes(), "abcd")).when(fluentRequest).attachPhoto("abcd"); + doReturn(new ByteArrayBody("content body".getBytes(), "1234")).when(fluentRequest).attachPhoto("1234"); + fluentRequest.addPhotoToMultipart(multipartEntity, photoKeys); + verify(multipartEntity).addPart(eq("child[photo][0]"), Matchers.any(ContentBody.class)); + verify(multipartEntity).addPart(eq("child[photo][1]"), Matchers.any(ContentBody.class)); + } + @Test @Ignore // This test alone does a *real* connection to test SSL public void testSSL() throws IOException { Robolectric.getFakeHttpLayer().interceptHttpRequests(false); diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/view/fields/PhotoUploadBoxTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/view/fields/PhotoUploadBoxTest.java index 4b6b62b3..9c258593 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/view/fields/PhotoUploadBoxTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/view/fields/PhotoUploadBoxTest.java @@ -1,8 +1,10 @@ package com.rapidftr.view.fields; import android.app.Activity; +import android.content.Intent; import android.graphics.Bitmap; import android.view.LayoutInflater; +import android.widget.GridView; import android.widget.ImageView; import com.rapidftr.CustomTestRunner; import com.rapidftr.R; @@ -10,18 +12,16 @@ import com.rapidftr.activity.RapidFtrActivity; import com.rapidftr.activity.RegisterChildActivity; import com.rapidftr.utils.PhotoCaptureHelper; -import com.xtremelabs.robolectric.shadows.ShadowToast; import org.json.JSONArray; import org.json.JSONException; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Matchers; import java.io.IOException; import java.security.GeneralSecurityException; -import static com.xtremelabs.robolectric.Robolectric.shadowOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -57,36 +57,6 @@ public void shouldStartCameraActivityWhenImageClickedAndViewIsEnabled() { verify(view).startCapture(); } - @Test - public void shouldShowFullPhotoWhenImageClickedAndViewIsDisabled(){ - view.initialize(field, child); - doNothing().when(view).startCapture(); - - view.setEnabled(false); - view.getImageContainer().performClick(); - verify(view).showFullPhoto(null); - - } - @Test - public void shouldShowPhotoWhenImageClicked() throws Exception { - view.initialize(field, child); - doNothing().when(view).showFullPhoto(null); - - child.put(field.getId(), "random_file_name"); - view.getImageContainer().performClick(); - - verify(view).onImageClick(); - verify(view).showFullPhoto(null); - } - - @Test - public void shouldShowImageNotAvailableToastIfViewIsDisabledAndTheImageIsNotAvailable(){ - view.initialize(field, child); - view.setEnabled(false); - view.getImageContainer().performClick(); - Assert.assertThat(ShadowToast.getTextOfLatestToast(), equalTo(view.getContext().getString(R.string.photo_not_captured))); - } - @Test public void shouldSaveCaptureWhenCapturingSuccess() throws Exception { view.initialize(field, child); @@ -162,23 +132,8 @@ public void testSaveCaptureShouldSaveFileNameInChild() throws JSONException, IOE doReturn(fileName).when(view).createCaptureFileName(); view.saveCapture(); - assertThat(child.getString(field.getId()), equalTo("random_file_name")); - } - -// @Test -// public void shouldPaintAllThumbnailsUnderPhotoKeysForViewAndEditChild() throws JSONException, IOException { -// ShadowView shadowLinearLayout = shadowOf(view.findViewById(R.id.linear)); -// ShadowImageView shadowImageView = new ShadowImageView(); -// child.put("photo_keys", new JSONArray("[some_file_name, random_file_name]")); -// view.initialize(field, child); -//// doReturn(new ShadowImageView()).when(view).getImageView(); -//// doReturn(shadowLinearLayout).when(view).getGalleryView(); -// when(photoCaptureHelper.getThumbnailOrDefault("some_file_name")).thenReturn(bitmap); -// when(photoCaptureHelper.getThumbnailOrDefault("random_file_name")).thenReturn(bitmap); -//// doNothing().when(view).addImageToView(Matchers.any(), Matchers.any()); -// view.repaint(); -// verify(imageView,times(1)).setImageBitmap(bitmap); -// } + assertThat(child.getString("current_photo_key"), equalTo("random_file_name")); + } @Test public void shouldSaveNewlyCapturedFileNameInPhotoKeys() throws JSONException { @@ -194,9 +149,10 @@ public void shouldSaveNewlyCapturedFileNameInPhotoKeys() throws JSONException { @Test public void shouldAddCapturedFileNamesToExistingPhotoKeys() throws JSONException { child.put("photo_keys", new JSONArray("[some_file_name]")); - view.initialize(field, child); String fileName = "random_file_name"; doReturn(fileName).when(view).createCaptureFileName(); + doNothing().when(view).setGridAttributes(Matchers.any(GridView.class), Matchers.any(JSONArray.class)); + view.initialize(field, child); view.saveCapture(); assertThat(child.optJSONArray("photo_keys").length(), is(2)); @@ -204,4 +160,29 @@ public void shouldAddCapturedFileNamesToExistingPhotoKeys() throws JSONException assertThat(child.optJSONArray("photo_keys").get(1).toString(), is("random_file_name")); } + @Test + public void shouldSetCurrentPhotoKeyIfItIsNotSetEarlier(){ + view.initialize(field, child); + String fileName = "some_file_name"; + doReturn(fileName).when(view).createCaptureFileName(); + view.saveCapture(); + assertThat(child.optString("current_photo_key"), is("some_file_name")); + } + + @Test + public void shouldSetCurrentPhotoKey(){ + view.initialize(field, child); + Intent intent = new Intent(); + intent.putExtra("file_name","some_file"); + view.onActivityResult(PhotoUploadBox.SHOW_FULL_IMAGE_REQUEST,1, intent); + assertEquals(child.optString("current_photo_key"),"some_file"); + } + + @Test + public void shouldNotSetCurrentPhotoKey(){ + view.initialize(field, child); + Intent intent = new Intent(); + view.onActivityResult(PhotoUploadBox.SHOW_FULL_IMAGE_REQUEST,1, intent); + assertEquals(child.optString("current_photo_key"),""); + } }